chore: import upstream snapshot with attribution
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) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:10:27 +08:00
commit 49b9bb6724
992 changed files with 161690 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
# serve-one
The kernel layer beneath `MCPServer.run()` / `run_server_from_args`. Every
transport entry composes the same three pieces: a `lowlevel.Server` (the
handler registry), a `Connection` (per-peer state), and a driver — `serve_one`
for one request → result dict, or `serve_connection` for a dispatcher loop.
This is what you write to bring up MCP over a custom transport. Uniquely, the
server file here builds the stdio entry by hand instead of importing
`stories._hosting`.
## Run it
```bash
# stdio (default — the client spawns server.py as a subprocess; its __main__
# is the hand-built serve_connection loop)
uv run python -m stories.serve_one.client
```
## What to look at
- `server.py::handle_one``Connection.from_envelope(...)` + `serve_one(...)`
returns the raw result dict for one request. No handshake, no streams; the
entry owns wire encoding and exception→error mapping.
- `server.py::main``JSONRPCDispatcher` + `Connection.for_loop(...)` +
`serve_connection(...)`: exactly what `Server.run()` does internally for
stdio.
- `server.py::SingleExchangeContext` — the per-request `DispatchContext` a
custom entry must supply. The SDK ships no public concrete class for this
yet.
- `client.py` — drives `handle_one` directly and asserts the raw result-dict
shape (`structuredContent` / `content`), then proves the loop-mode driver
works over the wire.
## Caveats
- **Deep imports** — `serve_one`, `serve_connection`, and `Connection` are only
reachable at `mcp.server.runner` / `mcp.server.connection` today; a shorter
`mcp.server.*` re-export is tracked for beta.
- **Lowlevel-only.** The drivers take a `lowlevel.Server` and `MCPServer` has
no public accessor for its underlying one (`_lowlevel_server` is private), so
there is no `MCPServer`-tier variant of this story. Build the lowlevel
`Server` directly until that accessor lands.
- **No public `DispatchContext`** — `SingleExchangeContext` is hand-rolled
boilerplate; a public helper (or a `serve_one` overload that builds one) is
tracked for beta.
- **Lifespan** — the transport entry enters `server.lifespan(server)` **once**
and threads `lifespan_state` to every `handle_one()` call; never enter it
per-request.
- `ServerRunner` is kernel-internal; never construct it directly. The
free-function drivers are the supported surface.
## Spec
[Architecture — lifecycle](https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle)
· [2026 versioning — discover](https://modelcontextprotocol.io/specification/draft/server/discover)
## See also
`legacy_routing/` (composing `serve_one` behind `classify_inbound_request`),
`dual_era/` (`Connection.protocol_version` in handlers).
+39
View File
@@ -0,0 +1,39 @@
"""Drive `handle_one` directly to assert the raw result-dict shape, then over the wire."""
import mcp_types as types
from mcp_types.version import LATEST_MODERN_VERSION
from mcp.client import Client
from stories._harness import Target, run_client
from stories.serve_one.server import build_server, handle_one
async def main(target: Target, *, mode: str = "auto") -> None:
# ── direct: the namesake recipe — Connection.from_envelope + serve_one → raw result dict.
# The entry enters lifespan once and threads it to every per-request handle_one().
server = build_server()
params = {
"name": "add",
"arguments": {"a": 2, "b": 3},
"_meta": {
types.PROTOCOL_VERSION_META_KEY: LATEST_MODERN_VERSION,
types.CLIENT_INFO_META_KEY: {"name": "serve-one-probe", "version": "0.0.0"},
types.CLIENT_CAPABILITIES_META_KEY: {},
},
}
async with server.lifespan(server) as lifespan_state:
raw = await handle_one(server, "tools/call", params, lifespan_state=lifespan_state)
assert raw["structuredContent"] == {"result": 5}, raw
assert raw["content"][0] == {"type": "text", "text": "5"}, raw
# ── over the wire: the loop-mode driver behind the connected client.
async with Client(target, mode=mode) as client:
listed = await client.list_tools()
assert [t.name for t in listed.tools] == ["add"]
result = await client.call_tool("add", {"a": 2, "b": 3})
assert result.structured_content == {"result": 5}, result
if __name__ == "__main__":
run_client(main)
+110
View File
@@ -0,0 +1,110 @@
"""serve_one / serve_connection mechanics: the kernel drivers a transport entry composes.
`handle_one()` is the modern single-exchange recipe (`Connection.from_envelope`
+ `serve_one` → raw result dict). `main()` is the loop recipe
(`JSONRPCDispatcher` + `Connection.for_loop` + `serve_connection`) — what
`Server.run()` does for stdio. Both drivers take a `lowlevel.Server`, so this is
a lowlevel-only story: `MCPServer` has no public accessor for its underlying
`Server` yet.
"""
from collections.abc import Mapping
from dataclasses import dataclass, field
from typing import Any
import anyio
import mcp_types as types
from mcp_types.version import LATEST_MODERN_VERSION
from mcp.server.connection import Connection # deep-path import; shorter re-export planned
from mcp.server.context import ServerRequestContext
from mcp.server.lowlevel import Server
from mcp.server.runner import serve_connection, serve_one # deep-path import; shorter re-export planned
from mcp.server.stdio import stdio_server
from mcp.shared.exceptions import NoBackChannelError
from mcp.shared.jsonrpc_dispatcher import JSONRPCDispatcher
from mcp.shared.transport_context import TransportContext
__all__ = ["SingleExchangeContext", "build_server", "handle_one"]
def build_server() -> Server[Any]:
async def list_tools(
ctx: ServerRequestContext[Any], params: types.PaginatedRequestParams | None
) -> types.ListToolsResult:
return types.ListToolsResult(
tools=[types.Tool(name="add", description="Add two integers.", input_schema={"type": "object"})]
)
async def call_tool(ctx: ServerRequestContext[Any], params: types.CallToolRequestParams) -> types.CallToolResult:
assert params.name == "add" and params.arguments is not None
total = params.arguments["a"] + params.arguments["b"]
return types.CallToolResult(content=[types.TextContent(text=str(total))], structured_content={"result": total})
return Server("serve-one-example", on_list_tools=list_tools, on_call_tool=call_tool)
@dataclass
class SingleExchangeContext:
"""Minimal `DispatchContext` for one inbound request with no back-channel.
A custom transport entry hand-builds one of these per request. The SDK
ships no public concrete class for this yet; this is the structural minimum.
"""
request_id: int | str | None
transport: TransportContext = field(default_factory=lambda: TransportContext(kind="custom", can_send_request=False))
message_metadata: None = None
can_send_request: bool = False
cancel_requested: anyio.Event = field(default_factory=anyio.Event)
async def send_raw_request(self, method: str, params: Mapping[str, Any] | None, opts: Any = None) -> dict[str, Any]:
raise NoBackChannelError(method)
async def notify(self, method: str, params: Mapping[str, Any] | None, opts: Any = None) -> None:
return None
async def progress(self, progress: float, total: float | None = None, message: str | None = None) -> None:
return None
async def handle_one(
server: Server[Any], method: str, params: Mapping[str, Any], *, lifespan_state: Any
) -> dict[str, Any]:
"""Serve exactly one modern-era request and return its raw result dict.
Reads the envelope from `params._meta` (the 2026 wire shape), builds a
born-ready `Connection.from_envelope`, and drives `serve_one`. The transport
entry enters `server.lifespan(server)` once and threads `lifespan_state` to
every call — never enter the lifespan per-request.
"""
meta = params.get("_meta", {})
connection = Connection.from_envelope(
meta.get(types.PROTOCOL_VERSION_META_KEY, LATEST_MODERN_VERSION),
meta.get(types.CLIENT_INFO_META_KEY),
meta.get(types.CLIENT_CAPABILITIES_META_KEY),
)
return await serve_one(
server,
SingleExchangeContext(request_id=1),
method,
params,
connection=connection,
lifespan_state=lifespan_state,
)
async def main() -> None:
"""Serve over stdio by building the dispatcher + Connection by hand (loop mode)."""
server = build_server()
async with server.lifespan(server) as lifespan_state:
async with stdio_server() as (read_stream, write_stream):
dispatcher: JSONRPCDispatcher[TransportContext] = JSONRPCDispatcher(
read_stream, write_stream, inline_methods=frozenset({"initialize"})
)
connection = Connection.for_loop(dispatcher)
await serve_connection(server, dispatcher, connection=connection, lifespan_state=lifespan_state)
if __name__ == "__main__":
anyio.run(main)