Commit Graph

340 Commits

Author SHA1 Message Date
Max Isbey c54fe3b36a feat(mrtr): linear continuation-based handler — Option H
The Option B footgun was: await elicit() looks like a suspension point but
is actually a re-entry point, so everything above it runs twice. Option H
fixes that by making it a REAL suspension point — the coroutine frame is
held in a ContinuationStore across MRTR rounds, keyed by request_state.

Handler code stays exactly as it was in the SSE era:

    async def my_tool(ctx: LinearCtx, location: str) -> str:
        audit_log(location)      # runs exactly once
        units = await ctx.elicit("Which units?", UnitsSchema)
        return f"{location}: 22°{units.u}"

The wrapper linear_mrtr(my_tool, store=...) translates this into a standard
MRTR on_call_tool handler. Round 1 starts the coroutine; elicit() sends
IncompleteResult back through the wrapper and parks on a stream. Round 2's
retry wakes it with the answer. The coroutine continues from where it
stopped — no re-entry, no double-execution.

Trade-off: server holds the frame in memory between rounds. Client sees
pure MRTR (no SSE, independent requests), but server is stateful within
a single tool call. Horizontally-scaled deployments need sticky routing on
the request_state token. Same operational shape as Option A's SSE hold,
without the long-lived connection.

SDK pieces (src/mcp/server/experimental/mrtr/linear.py):
- LinearCtx with async elicit(message, PydanticSchema) -> instance
- ContinuationStore — owns the task group, TTL-based frame expiry
- linear_mrtr(handler, store=...) — the wrapper
- ElicitDeclined raised when user declines/cancels

7 E2E tests including the key assertion: side-effects above await fire
exactly once (the test measures audit_log count).
2026-03-20 17:06:58 +00:00
Max Isbey 29cb1ba837 examples(mrtr): handler-shape comparison deck (SEP-2322)
Python-SDK counterpart to typescript-sdk#1701. Seven ways to write the
same weather-lookup tool so the diff between files is the argument.

SDK primitives (src/mcp/server/experimental/mrtr.py):
- MrtrCtx.once() — idempotency guard tracked in request_state (Option F)
- ToolBuilder — structural step decomposition; end_step runs exactly once
  regardless of round count (Option G)
- input_response() — sugar for the guard-first pattern
- sse_retry_shim() — Option A comparison artifact (pragma no-cover until
  LATEST_PROTOCOL_VERSION bumps past the MRTR gate)
- dispatch_by_version() — Option D comparison artifact

Option examples (examples/servers/mrtr-options/):
- E (degrade-only): the SDK default. MRTR-native; pre-MRTR gets a default
  or error. Both quadrant rows collapse here.
- A (SSE shim): SDK emulates retry over SSE. Safe re-entry, hidden loop.
- B (await shim): exception-based. UNSAFE — hidden double-execution above
  await. Not a ship target; for contrast.
- C (version branch): explicit if/else in handler body.
- D (dual handler): two functions, SDK picks by version.
- F (ctx.once): idempotency guard, opt-in per side-effect.
- G (ToolBuilder): no above-the-guard zone; end_step structurally
  unreachable until all elicitations complete.

The invariant test (tests/experimental/test_mrtr.py) parametrises E/F/G
against the same Client + callback to prove identical wire behaviour —
the server's internal choice doesn't leak. The footgun test measures
audit_log count to prove F and G actually hold the guard (naive handler
fires twice; F and G fire once).

Both F and G depend on request_state integrity. The demos use plain
base64-JSON; a production SDK MUST HMAC-sign the blob.
2026-03-20 16:09:46 +00:00
Max Isbey 25fb05f416 feat(mrtr): add IncompleteResult types and client retry loop (SEP-2322)
Lowlevel plumbing for Multi Round-Trip Requests:

Types:
- IncompleteResult with result_type discriminator, input_requests, request_state
- InputRequest/InputResponse unions (elicitation, sampling, roots)
- input_responses + request_state fields on RequestParams

Server (lowlevel):
- on_call_tool return widened to include IncompleteResult

Session:
- send_request accepts TypeAdapter (overload) for union result parsing
- call_tool_mrtr() returns CallToolResult | IncompleteResult
- call_tool() stays narrow, raises on IncompleteResult with migration hint

Client:
- call_tool() drives MRTR retry loop internally — dispatches embedded
  input requests to elicitation/sampling/list_roots callbacks, retries
  with collected responses + echoed request_state
- max_mrtr_rounds bound (default 8)

The client-side delta from today's code is zero: elicitation_callback is the
same function whether it fires from SSE push or MRTR retry.
2026-03-20 15:54:11 +00:00
Max Isbey 92c693bb73 fix: cancel in-flight handlers when transport closes in server.run() (#2306) 2026-03-20 13:37:32 +00:00
Max Isbey 883d893097 test: rewrite cli.claude config tests to assert JSON output directly (#2311)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Felix Weinberger <felixweinberger@users.noreply.github.com>
2026-03-19 15:16:34 +00:00
Max Isbey 20dd94632e feat(client): store InitializeResult as initialize_result (#2300) 2026-03-18 17:31:26 +00:00
Max Isbey 67201a9bbd test: fix WS test port race; narrow to single smoke test covering both transport ends (#2267) 2026-03-18 15:48:30 +00:00
Max Isbey 7826ade12b test: convert test_integration.py to in-memory transport (fix flaky) (#2277) 2026-03-18 15:25:11 +00:00
Max Isbey 1a2244f402 fix: handle non-UTF-8 bytes in stdio server stdin (#2302) 2026-03-17 18:40:39 +00:00
Max Isbey 75a80b6f07 refactor: connect-first stream lifecycle for sse and streamable_http (#2292)
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
2026-03-16 23:30:20 +00:00
Max Isbey e1fd62e0f3 fix: close all memory stream ends in client transport cleanup (#2266) 2026-03-13 14:43:54 +00:00
Max Isbey dd52713517 Rewrite TestChildProcessCleanup with socket-based deterministic liveness probe (#2265) 2026-03-12 12:52:32 +00:00
Max Isbey 62eb08e5b2 fix: don't send log notification on transport error (#2257) 2026-03-09 17:47:27 +00:00
Max Isbey 31a38b5078 fix: correct Context type parameters across examples and tests (#2256) 2026-03-09 16:52:56 +00:00
Shivam Aggarwal 51c53f2c18 fix: accept wildcard media types in Accept header per RFC 7231 (#2152)
Co-authored-by: Shivam <shivam@Shivams-MacBook-Air-2.local>
2026-03-09 16:30:02 +00:00
Max Isbey 7ba41dcfae fix: make local coverage runs reliable (#2236) 2026-03-06 17:24:18 +00:00
Ramesh Reddy Adutla eaf971cf25 Add warning log when rejecting request with unknown/expired session ID (#2212)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
2026-03-06 16:55:37 +00:00
Max Isbey 92f1b1500d fix: remove MIME type validation from MCPServer Resource (#2235) 2026-03-06 14:50:58 +00:00
Giulio Leone b33c811675 perf: use deque for InMemoryTaskMessageQueue FIFO operations (#2165) 2026-03-05 15:44:33 +00:00
Giulio Leone 7c0224828b fix(oauth): include client_id in token request body for client_secret_post (#2185)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-05 14:57:33 +00:00
Max Isbey 528abfab86 tests: remove lax-no-cover pragmas by moving assertions before cancellation (#2206) 2026-03-04 16:11:34 +00:00
Varun6578 b3149d2f33 fix: clean up SSE session on client disconnect (#2200)
Co-authored-by: Varun Sharma <sharmava@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
2026-03-04 14:45:11 +00:00
Max Isbey cc22bf5464 refactor: remove request_ctx ContextVar, thread Context explicitly (#2203)
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
2026-03-04 13:23:02 +00:00
Jonathan Hefner cb07adeca3 docs: add code fences to Example: docstring blocks (#2104) 2026-02-19 21:06:11 +01:00
Max Isbey 0e96aecd1d fix: use exact match for loopback hosts in issuer URL validation (#2089) 2026-02-18 19:40:52 +00:00
Max Isbey e82203bfc4 refactor: remove unused mcp.shared.progress module (#2080) 2026-02-18 13:10:02 +00:00
Akshan Krithick fc57c2c4c5 test: fix progress notification assertions for related_request_id (#2038)
Co-authored-by: Lee Hubbard <hubbard.zlee@unknowncyber.com>
Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
2026-02-18 11:53:03 +00:00
Felix Weinberger 92140e5086 Add idle session timeout to StreamableHTTPSessionManager (#2022) 2026-02-18 10:47:02 +00:00
Felix Weinberger be5bb7c4f2 fix: normalize trailing slashes before length check in check_resource_allowed (#2074) 2026-02-17 14:34:59 +00:00
Max Isbey 705497a593 fix: allow null id in JSONRPCError per JSON-RPC 2.0 spec (#2056) 2026-02-17 10:30:34 +00:00
BabyChrist666 3b53fb9a00 fix: add HTTP readiness check to wait_for_server and remove dead code in SSE tests (#2073) 2026-02-17 08:34:47 +01:00
Marcelo Trylesinski 2fe56e56de fix: handle HTTP error status codes in streamable HTTP client (#2047) 2026-02-14 09:49:42 +01:00
Max Isbey 0a22a9dc33 refactor: replace lowlevel Server decorators with on_* constructor kwargs (#1985) 2026-02-12 15:55:54 +00:00
Aaron Abbott f049c8e5c6 Fix leaked anyio streams in streamable_http (#1991)
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
2026-02-11 14:52:07 +00:00
Felix Weinberger 239d682b6f fix: pass conformance auth scenarios, add RFC 8707 resource validation (#2010) 2026-02-09 11:41:03 +00:00
Marcelo Trylesinski 7c7c13b648 fix: send JSONRPCError instead of bare exceptions in streamable HTTP client (#2005) 2026-02-09 10:38:46 +00:00
Marcelo Trylesinski 1a8c14a5b8 refactor: replace mcp.types as types to from mcp import types (#1986) 2026-02-03 16:42:29 +00:00
Marcelo Trylesinski 4fc49c62bd feat: add ClientRequestContext type alias for client-side handlers (#1989) 2026-02-03 17:37:38 +01:00
Marcelo Trylesinski b1f7eec3cd refactor: split RequestContext between server and client (#1987) 2026-02-03 14:35:07 +01:00
Marcelo Trylesinski 21822053df Support different transports in Client (#1972) 2026-01-30 12:11:27 +00:00
Max Isbey 2137c8fbdb fix: revert README to v1.x documentation on main (#1971)
Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
2026-01-29 20:03:01 +00:00
Marcelo Trylesinski 14744c66c5 Add tests for MCPServer.read_resource exception handling (#1957) 2026-01-27 13:49:06 +01:00
Marcelo Trylesinski acba5478a9 refactor: McpError renamed to MCPError and flatten parameters (#1956)
Co-authored-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
2026-01-26 14:37:44 +01:00
Marcelo Trylesinski 65c614e48e Rename FastMCP to MCPServer (#1951) 2026-01-25 14:45:52 +01:00
Max Isbey a7ddfdae07 ci: add strict-no-cover to detect unnecessary coverage pragmas (#1897) 2026-01-23 21:00:20 +01:00
Marcelo Trylesinski f0ab53e194 Add meta to Client methods (#1923) 2026-01-22 14:50:39 +01:00
Marcelo Trylesinski d77292fb06 refactor: drop test classes (#1924) 2026-01-22 12:37:52 +01:00
Marcelo Trylesinski 7b728a243e refactor: drop unused logger/logging (#1926) 2026-01-22 11:56:41 +01:00
Marcelo Trylesinski bcb07c2b25 refactor: flatten the methods in Client (#1914) 2026-01-20 13:12:07 +01:00
Marcelo Trylesinski 5fdd48a0d3 Completely drop RootModel from types module (#1910) 2026-01-19 14:29:15 +01:00