Skip to content

feat(mcp-binding): one composable route per allowlisted MCP tool, on the official MCP SDK - #51

Merged
acn-ericlaw merged 2 commits into
mainfrom
feat/mcp-binding
Nov 14, 2026
Merged

acn-ericlaw merged 2 commits into
mainfrom
feat/mcp-binding

Conversation

@acn-ericlaw

Copy link
Copy Markdown
Collaborator

What

extensions/mcp-binding/, step 4 of RFC-0011 / ADR-0033 in the Python pack: a polyglot function host that serves the
tools of MCP servers as composable routes, one per allowlisted remote tool, on the official MCP SDK 2.x. Servers are named
in resources/mcp-servers.yml with their transport (stdio or http), their credential references (${VAR}, resolved at
boot, never logged) and their allowlist, each tool mapped to a route and the SHA-256 digest of its input schema. Boot
connects each server inside the serving loop, lists its tools and refuses to start by name when a tool is missing or its
schema changed. A route's reply is the structured content, else the blocks' text; isError is a 400 with the server's text,
a timeout 408, a protocol failure 502, a lost session 503. describe prints the digests and catalog rows; mcp.health
reports the servers. Platform gains on_startup, on_cleanup and create_app; the mcp extra is added. The shared
vector file tests/vectors/mcp-binding-vectors.json pins the pure half for both packs; a fixture MCP server drives both
transports in the tests (46 cases; the suite 397 passed). The HTTP transport was also driven against a public MCP server.

Why

The agent loop's design (ADR-0033, accepted 2026-11-14) puts the MCP client in the language packs, never in an engine
process: a stdio server is a subprocess of the pack, its credentials stay in the pack's environment, and the graph's
catalog names routes, so the model reads the graph's descriptions and a server cannot change a tool under a certified
graph. This is the Python half; the Node.js twin runs the same vector bytes next.

🤖 Generated with Claude Code
Co-Authored-By: Claude Fable 5.1 [email protected]

acn-ericlaw and others added 2 commits November 14, 2026 15:35
…the official MCP SDK

The MCP binding (extensions/mcp-binding) is step 4 of RFC-0011 / ADR-0033: a polyglot function host that serves
the tools of MCP servers as composable routes. Servers are named in resources/mcp-servers.yml, each with its
transport (stdio, a subprocess of this process with the SDK's minimal environment plus the listed variables, or
http, a streamable HTTP URL with headers), its credential references (${VAR}, resolved at boot and never logged)
and its allowlist mapping each remote tool to a route and the SHA-256 digest of its input schema. Boot connects
each server inside the serving loop, lists its tools and refuses to start by name when a tool is missing or its
schema changed; a route's reply is the structured content, else the blocks' text; isError is a 400 carrying the
server's text, a timeout 408, a protocol failure 502, a lost session 503. `describe` prints each tool's digest and
a catalog row for the graph. mcp.health reports the servers and their connections.

Platform gains on_startup, on_cleanup and create_app, so an extension can do asynchronous boot work before the
first request. The mcp extra pins mcp>=2,<3. The shared vector file tests/vectors/mcp-binding-vectors.json pins
the digest, the verification and the result mapping for both packs; the fixture server of tests/fixtures drives
both transports; 46 tests, the full suite 397 passed. The HTTP transport was also driven against a public MCP
server (the Mermaid Chart endpoint).

Memory: session 2026-11-14 [Claude Code] - the fact mcp-binding-route-per-tool and the thread mcp-binding.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
…s not part of its typed surface

basedpyright on CI (Python 3.10) reported create_mcp_http_client as not exported from
mcp.client.streamable_http: it lives in a private module and the re-export is untyped. The binding
now builds the httpx2.AsyncClient itself, with the server's headers, the call timeout as the deadline
and redirects followed, and hands it to streamable_http_client as before. Tests and the type check are
green locally with the venv's interpreter.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
@acn-ericlaw
acn-ericlaw merged commit ea3783d into main Nov 14, 2026
5 checks passed
@acn-ericlaw
acn-ericlaw deleted the feat/mcp-binding branch November 14, 2026 07:48
acn-ericlaw added a commit that referenced this pull request Nov 14, 2026
acn-ericlaw added a commit that referenced this pull request Nov 14, 2026
…he pack's convention

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant