Repository navigation
feat(mcp-binding): one composable route per allowlisted MCP tool, on the official MCP SDK - #51
Merged
Merged
Conversation
…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
added a commit
that referenced
this pull request
Nov 14, 2026
Co-Authored-By: Claude Fable 5.1 <[email protected]>
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]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
extensions/mcp-binding/, step 4 of RFC-0011 / ADR-0033 in the Python pack: a polyglot function host that serves thetools 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.ymlwith their transport (stdioorhttp), their credential references (${VAR}, resolved atboot, 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;
isErroris a 400 with the server's text,a timeout 408, a protocol failure 502, a lost session 503.
describeprints the digests and catalog rows;mcp.healthreports the servers.
Platformgainson_startup,on_cleanupandcreate_app; themcpextra is added. The sharedvector file
tests/vectors/mcp-binding-vectors.jsonpins the pure half for both packs; a fixture MCP server drives bothtransports 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]