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
52 lines
2.1 KiB
Markdown
52 lines
2.1 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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.py` `main` — the body opens with `Client(target, mode=mode)`. The
|
|
vendor request rides whichever protocol era `mode` selects; nothing else in
|
|
the story changes between eras.
|
|
- `server.py` `SearchParams` — subclasses `types.RequestParams` so `_meta`
|
|
(and on a 2026-07-28 connection, the reserved `io.modelcontextprotocol/*`
|
|
envelope keys) parse uniformly without extra code.
|
|
- `server.py` `add_request_handler("acme/search", SearchParams, search)` — the
|
|
method string is the wire `method`; use a vendor prefix so it can never
|
|
collide with a future spec method.
|
|
- `client.py` `client.session.send_request(...)` — `Client` only exposes spec
|
|
verbs, so vendor methods go through the underlying `ClientSession`.
|
|
`send_request` accepts any `types.Request` subclass.
|
|
|
|
## Caveats
|
|
|
|
- The TypeScript SDK's equivalent example also shows a custom server→client
|
|
**notification** (`acme/searchProgress`). The Python client can observe
|
|
vendor notifications via `NotificationBinding` (see
|
|
`docs/advanced/extensions.md`). That half is omitted here because the
|
|
lowlevel server has no surface for emitting vendor notifications yet.
|
|
|
|
## Spec
|
|
|
|
[Requests — basic protocol](https://modelcontextprotocol.io/specification/2025-11-25/basic#requests)
|
|
(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).
|