docs: document mcp server usage

This commit is contained in:
Jan Nedbal
2026-04-14 19:33:48 +02:00
parent a8ae85c0a4
commit b2283b0c3f
3 changed files with 153 additions and 0 deletions

View File

@@ -7,6 +7,27 @@ follow semantic versioning: major for incompatible CLI or JSON contract changes,
minor for new subcommands or additive flags, patch for fixes that preserve the minor for new subcommands or additive flags, patch for fixes that preserve the
contract. contract.
## [Unreleased]
### Added
- `metin_release_mcp` package and `metin-release-mcp` console script — a
thin Model Context Protocol stdio server that wraps the Phase 1
`release …` subcommands as eight MCP tools (`release_inspect`,
`release_build_manifest`, `release_sign`, `release_diff_remote`,
`release_upload_blobs`, `release_promote`, `release_verify_public`,
`release_publish`). Each tool's input schema mirrors the CLI's
argparse signature 1:1; the wrapper shells out to
`metin-release <subcommand> --json …` and returns the parsed envelope
verbatim with zero duplicated business logic.
- `[mcp]` optional dependency group pulling in the official `mcp`
Python SDK.
- `docs/mcp.md` — MCP server usage guide.
- `tests/mcp/` — 45 new tests covering the CLI runner (success path,
error-envelope passthrough, unparseable output, missing binary),
tool schemas (mirror checks against each command's argparse), and
dispatch translation (booleans, optionals, paths with spaces).
## [0.1.0] - 2026-04-14 ## [0.1.0] - 2026-04-14
First Phase 1 drop. Implements the minimum asset release path the First Phase 1 drop. Implements the minimum asset release path the

View File

@@ -31,3 +31,15 @@ Add `--json` to get a machine-parseable envelope on stdout. Exit codes:
| 4 | reserved (ERP sync, Phase 2+) | | 4 | reserved (ERP sync, Phase 2+) |
See `docs/cli.md` for the full command reference. See `docs/cli.md` for the full command reference.
## MCP server
The `metin-release-mcp` console script (Phase 3) exposes each Phase 1
subcommand as an MCP tool over stdio. Install with the `mcp` extra:
```
pip install -e .[mcp]
metin-release-mcp --help
```
See `docs/mcp.md` for tool list, client wiring, and error handling.

120
docs/mcp.md Normal file
View File

@@ -0,0 +1,120 @@
# 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.