Repository navigation
feat!: adopt MCP revision 2026-07-28 via the mcp 2.x SDK - #104
Conversation
Moves PerplexityAgent to the stateless MCP revision. FastMCP -> MCPServer; Context imports from mcp.server.mcpserver; transport host/port moved off the constructor. Every tool's behaviour is unchanged and a v2 server still serves 2025-era clients from the same process. mcp>=1.28.1,<2.0.0 -> mcp>=2.0.0,<3.0. Possession-based authorization (the stateless revision removed sessions) ------------------------------------------------------------------------ The offload store and the response store both isolated one client's data from another's using id(ctx.session). 2026-07-28 removed protocol sessions, so ctx.session is a fresh object per request and that scoping is dead. Per the spec, cross-call state now uses server-minted handles passed as tool arguments: - retrieve_key is now an unguessable random capability token (was a content hash, which an attacker could fabricate by guessing the content). - Holding a retrieve_key / response_id is the authorization to fetch it. The two isolation tests are rewritten to the possession contract. Fixes a real stdio crash (independent of the migration) ------------------------------------------------------- The stdin reader used a default-limit asyncio.StreamReader (64 KiB). Any JSON-RPC line over 64K raised LimitOverrunError and tore down the whole transport task group, killing the server on a single large request — legitimate or hostile. The reader now uses a 16 MiB limit and turns a still-oversized line into a clean protocol error instead of an unhandled crash. Regression-tested over a real subprocess. Also: parse lines through the SDK's jsonrpc_message_adapter (in 2.x JSONRPCMessage is a plain union alias with no model_validate_json) and serialize replies with exclude_unset=True, which keeps the 2026-07-28 envelope fields (resultType, ttlMs, cacheScope) on the wire. Conformance: added a server_metrics probe (read-only, no API) so the behavioural contracts run offline. This activated test_bad_input_does_not_crash, which is what surfaced the 64K stdio crash above. 201 tests pass; ruff + mypy clean. mcp-conformance 0.2.0: 17 passed, 1 skipped (injection: the server tags fetched content as untrusted rather than flagging injection in its own inputs). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 13 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (9)
Comment |
What
Moves PerplexityAgent to MCP revision
2026-07-28— the stateless revision — via themcp2.x SDK (mcp>=1.28.1,<2.0.0→mcp>=2.0.0,<3.0).FastMCP→MCPServer;Contextimports frommcp.server.mcpserver; transporthost/portmoved off the constructor. Every tool's behaviour is unchanged and a v2 server still serves 2025-era clients from the same process.Two things beyond the mechanical rename
1. Possession-based authorization (the stateless revision removed sessions).
The offload store and the response store both isolated one client's data from another's using
id(ctx.session). 2026-07-28 removed protocol sessions, soctx.sessionis a fresh object per request and that scoping no longer holds. Per the spec, cross-call state now uses server-minted handles passed as tool arguments:retrieve_keyis now an unguessable random capability token (was a content hash, which an attacker could fabricate by guessing the content).retrieve_key/response_idis the authorization to fetch it.The two isolation tests are rewritten to the possession contract. (This was a deliberate design choice — the alternative was binding state to an authenticated OAuth identity, which degrades to process-global over stdio where there's no auth.)
2. A real stdio crash, independent of the migration.
The stdin reader used a default-limit
asyncio.StreamReader(64 KiB). Any JSON-RPC line over 64K raisedLimitOverrunErrorand tore down the whole transport task group, killing the server on a single large request — legitimate or hostile. The reader now uses a 16 MiB limit and turns a still-oversized line into a clean protocol error instead of an unhandled crash. Regression-tested over a real subprocess.This surfaced because I added a
server_metricsconformance probe (read-only, no API), which activated thebad_input_does_not_crashcontract that was previously skipped.Also: the custom stdio transport now parses through the SDK's
jsonrpc_message_adapter(in 2.xJSONRPCMessageis a plain union alias with nomodel_validate_json) and serializes withexclude_unset=True, keeping theresultType/ttlMs/cacheScopeenvelope fields on the wire.Verification
pytestruff check .mypy srcmcp-conformance0.2.0uv.lockrefreshed:mcp → 2.0.0,+mcp-types,+opentelemetry-api,-httpx-sse.Note
Codeberg is the source of truth for this repo, but no Codeberg key was loaded in this session — this branch is on GitHub only and still needs a Codeberg push.
Proudly Made in Nebraska. Go Big Red! 🌽 https://xkcd.com/2347/