Files
pyMCPBroker/docs/SPEC.md
2026-04-14 00:16:59 +02:00

236 lines
4.7 KiB
Markdown

# pyMCPBroker Specification
## Purpose
pyMCPBroker exposes a very small stable API to a language model while wrapping one or more MCP servers running over `stdio`.
The model never sees raw MCP tools directly. It only sees three stable meta-tools:
- `meta_tree`
- `meta_desc`
- `meta_call`
Normal workflow:
1. call `meta_tree` to navigate
2. call `meta_desc` on a leaf path
3. call `meta_call` with arguments matching the schema returned by `meta_desc`
## Terminology
- **entry**: logical element exposed to the model
- `type=node`: navigation node
- `type=tool`: callable leaf
- **path**: stable absolute URL-like identifier
- **source**: real MCP backend mounted on a node
- `backend=stdio`: MCP process launched locally over stdin/stdout
## Public API
### `POST /meta_tree`
Input:
```json
{
"path": "/"
}
```
Returns the direct children of a node path.
Errors if the path does not exist or if it points to a tool leaf.
### `POST /meta_desc`
Input:
```json
{
"path": "/repo/read/get_file"
}
```
For a node path, returns node metadata and optionally summarized children.
For a tool path, returns:
- stable path
- summary
- description
- exact `args_schema`
- optional `example_args`
### `POST /meta_call`
Input:
```json
{
"path": "/repo/read/get_file",
"args": {
"owner": "myorg",
"repo": "demo-repo",
"ref": "main",
"filePath": "README.md"
}
}
```
The broker validates `args` against the dynamic schema previously returned by `meta_desc`, then calls the real MCP tool.
## Config format
The config is static JSON loaded at startup.
Top-level shape:
```json
{
"tree": [ ... ]
}
```
or:
```json
{
"tree": {
"path": "/",
"type": "node",
"children": [ ... ]
}
}
```
The explicit root node is optional. If omitted, `/` is created implicitly.
### Node fields
- `path`
- `type="node"`
- `summary` optional
- `description` optional
- `children` optional
- `source` optional
### Source fields
- `backend`: currently only `"stdio"`
- `command`: shell command to launch the MCP server
- `tool_filter`: optional unordered list of allow/deny glob patterns
- `tool_overrides`: optional per-tool overrides
- `path_aliases`: optional mapping from real MCP tool name to exposed leaf name
### Environment variables
`${ENV_VAR}` substitution is supported in strings, especially in `command`.
Missing variables fail at startup.
## Source mounting model
A `source` mounted on a node causes the broker to:
1. start the MCP process
2. initialize the MCP session
3. fetch `tools/list`
4. apply `tool_filter`
5. apply `tool_overrides`
6. expose the remaining tools as child leaves under the node path
The exposed leaf path is:
- `parent_path + / + alias`, if `path_aliases` defines one
- otherwise `parent_path + / + tool_name`
Example:
- node path: `/repo/read`
- real tool: `get_file_contents`
- alias: `get_file`
- exposed path: `/repo/read/get_file`
## Filter semantics
`tool_filter` is optional.
Positive patterns allow tools. Patterns prefixed with `!` deny tools.
Rules:
- if there is no positive pattern, all tools are allowed first, then deny rules are applied
- if at least one positive pattern exists, only tools matching a positive pattern are allowed, then deny rules are applied
- pattern order does not matter
Examples:
- `[]` → expose all tools
- `["!delete_*"]` → expose everything except delete tools
- `["get_*", "list_*"]` → expose only get/list tools
- `["get_*", "!get_secret_*"]` → expose get tools except secret ones
## Overrides
`tool_overrides` is optional.
Supported fields:
- `summary`
- `description`
- `max_output_chars`
- `timeout`
- `example_args`
- `render_mode`
They only affect the broker-facing presentation and execution limits. They do not rename the real MCP tool.
## Output normalization
The broker can truncate large outputs using `max_output_chars`.
Current behavior:
- preserve JSON structure when possible
- truncate long strings first
- compact long lists if needed
- return an explicit wrapper when truncation happened
## Internal MCP support
Current transport support:
- MCP `stdio` only
Required MCP methods:
- `initialize`
- `tools/list`
- `tools/call`
The broker also sends `notifications/initialized` after initialization.
## CLI
```bash
python -m pyMCPBroker 0.0.0.0:8100 /config.json
```
Optional shared secret:
```bash
python -m pyMCPBroker 0.0.0.0:8100 /config.json mysecret
```
Accepted options:
- `--reload`
- `--ignore-broken-tool`
- `--log-level`
- `--dump-tree`
## Repository editor config
The repository may include a `.vscode/` directory with recommended Python extensions plus launch/task settings for pytest and for starting the broker against `smoke_config.json`. This editor config is optional and does not affect runtime behavior.