49b9bb6724
Deploy Docs / deploy-docs (push) Failing after 1s
Conformance Tests / client-conformance (push) Failing after 3s
Conformance Tests / server-conformance (push) Failing after 1s
GitHub Actions Security Analysis / zizmor (push) Failing after 1s
CI / checks (push) Failing after 59m20s
CI / all-green (push) Waiting to run
2.1 KiB
2.1 KiB
custom-methods
Register and call a vendor-prefixed JSON-RPC method that is not part of the
MCP spec. The server uses the low-level Server.add_request_handler (there is
no MCPServer surface for this, so server.py is lowlevel-native and there is
no server_lowlevel.py sibling); the client drops to client.session to send
it.
Run it
# stdio (default — the client spawns the server as a subprocess)
uv run python -m stories.custom_methods.client
# HTTP — the client self-hosts the server on a free port, runs, then tears it down
uv run python -m stories.custom_methods.client --http
What to look at
client.pymain— the body opens withClient(target, mode=mode). The vendor request rides whichever protocol eramodeselects; nothing else in the story changes between eras.server.pySearchParams— subclassestypes.RequestParamsso_meta(and on a 2026-07-28 connection, the reservedio.modelcontextprotocol/*envelope keys) parse uniformly without extra code.server.pyadd_request_handler("acme/search", SearchParams, search)— the method string is the wiremethod; use a vendor prefix so it can never collide with a future spec method.client.pyclient.session.send_request(...)—Clientonly exposes spec verbs, so vendor methods go through the underlyingClientSession.send_requestaccepts anytypes.Requestsubclass.
Caveats
- The TypeScript SDK's equivalent example also shows a custom server→client
notification (
acme/searchProgress). The Python client can observe vendor notifications viaNotificationBinding(seedocs/advanced/extensions.md). That half is omitted here because the lowlevel server has no surface for emitting vendor notifications yet.
Spec
Requests — basic protocol (JSON-RPC request shape; vendor method names live outside the spec's reserved set).
See also
serve_one/ (the per-exchange driver that runs registered handlers),
middleware/ (wrapping every registered handler, including vendor methods).