3.5 KiB
metin-release-mcp
Thin Model Context Protocol server that
wraps the Phase 1 metin-release CLI. Each release … subcommand is exposed
as an MCP tool. The server contains no release business logic: it shells out
to the real CLI with --json and returns the parsed envelope verbatim.
Install
The server ships as an optional extra alongside the main CLI:
pip install -e '.[mcp]'
This installs the mcp Python SDK and adds a metin-release-mcp console
script plus a python -m metin_release_mcp module entry.
Running
The server speaks MCP over stdio, so you wire it into an MCP-capable client (Claude Desktop, Claude Code, etc.) as a stdio command. Example client entry:
{
"mcpServers": {
"metin-release": {
"command": "metin-release-mcp",
"env": {
"METIN_RELEASE_BINARY": "/usr/local/bin/metin-release"
}
}
}
}
You can also poke at it directly:
metin-release-mcp --help— list registered toolsmetin-release-mcp --list-tools— dump the full tool JSON schemasmetin-release-mcp --version
Tools
| Tool | CLI subcommand |
|---|---|
release_inspect |
metin-release release inspect |
release_build_manifest |
metin-release release build-manifest |
release_sign |
metin-release release sign |
release_diff_remote |
metin-release release diff-remote |
release_upload_blobs |
metin-release release upload-blobs |
release_promote |
metin-release release promote |
release_verify_public |
metin-release release verify-public |
release_publish |
metin-release release publish |
Tool input keys match CLI flag names with _ instead of -
(--base-url → base_url, --dry-run → dry_run). Boolean fields
correspond to argparse store_true flags: pass true to set the flag,
omit or pass false to leave it off.
Example invocation
{
"name": "release_inspect",
"arguments": {
"source": "/srv/metin/client"
}
}
The server runs metin-release release inspect --json --source /srv/metin/client
and returns the full JSON envelope:
{
"ok": true,
"command": "release inspect",
"status": "inspected",
"stats": {
"source_path": "/srv/metin/client",
"file_count": 9166,
"total_bytes": 3523473920,
"launcher_present": true,
"main_exe_present": true
}
}
CLI resolution
On every tool call the server resolves the metin-release binary in this order:
METIN_RELEASE_BINARYenvironment variable, if set and non-emptyshutil.which("metin-release")againstPATH
If neither resolves, the tool call returns a wrapper-level error envelope
(error.code = "cli_not_found").
Error handling
The server never invents its own release-level errors. There are three paths:
- Success — CLI exits 0 with a valid JSON envelope → envelope returned as-is
- CLI-level failure — CLI exits non-zero with an
{"ok": false, "error": …}envelope → that envelope is returned as-is, plus the CLI's stderr is attached as a diagnostic text block - Wrapper failure — binary missing, unparseable stdout, unknown tool,
invalid input → synthetic envelope with one of
cli_not_found,cli_unparseable_output,unknown_tool,invalid_tool_input
Environment variables
| Variable | Purpose |
|---|---|
METIN_RELEASE_BINARY |
Override the metin-release binary path. |
Any env vars the wrapped CLI honours (METIN_RELEASE_MAKE_MANIFEST,
METIN_RELEASE_SIGN_MANIFEST) are inherited by the subprocess unchanged.