Files
2026-04-14 19:33:48 +02:00

121 lines
3.5 KiB
Markdown

# metin-release-mcp
Thin [Model Context Protocol](https://modelcontextprotocol.io/) 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:
```json
{
"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 tools
- `metin-release-mcp --list-tools` — dump the full tool JSON schemas
- `metin-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
```json
{
"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:
```json
{
"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:
1. `METIN_RELEASE_BINARY` environment variable, if set and non-empty
2. `shutil.which("metin-release")` against `PATH`
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.