You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Stateless streamable HTTP: tools/call with progress returns notification as response body #980
On the 2026-07-28 suite (0.2.0-alpha.9), tools-call-with-progress fails against the stateless conformance server:
Failed: HTTP 200: expected a JSON-RPC result for 'tools/call', got unexpected body
{"jsonrpc":"2.0","method":"notifications/progress","params":{"message":"Starting","progress":0,"progressToken":"progress-test-1","total":100}}
In stateless mode the progress notification is emitted as the POST response body instead of (or before) the final tools/call result. The scenario passes against the stateful server on the 2025-11-25 suite, so this is specific to the stateless lifecycle.
tools-call-with-progress (2026-07-28 suite, 0.2.0-alpha.9) passes at 839922d (pre-#973) and fails at current main (2e2c791):
Failed: HTTP 200: expected a JSON-RPC result for 'tools/call', got unexpected body
{"jsonrpc":"2.0","method":"notifications/progress","params":{...,"progressToken":"progress-test-1"}}
Root cause: #990 added the SSE fallback for non-terminal first messages to the legacy stateless path in StreamableHttpService (tower.rs, the if self.config.json_response branch that checks matches!(message, Response | Error)). #973 introduced a separate modern per-request path, serve_negotiated_request_directly, which the 2026-07-28 conformance scenario now hits (per-request _meta negotiation), and that path returns the first outbound message as the JSON body unconditionally when json_response is enabled:
For a progress-emitting tool the first message is notifications/progress, so the client gets the notification as the response body and never receives the terminal result — the same failure mode #990 fixed for the legacy path. The modern path needs the same "JSON only when the first message is terminal, otherwise fall back to SSE" logic.
Activity
DaleSeo commentedon Jul 17, 2026
Reopening: this regressed with #973.
tools-call-with-progress(2026-07-28 suite,0.2.0-alpha.9) passes at 839922d (pre-#973) and fails at current main (2e2c791):Root cause: #990 added the SSE fallback for non-terminal first messages to the legacy stateless path in
StreamableHttpService(tower.rs, theif self.config.json_responsebranch that checksmatches!(message, Response | Error)). #973 introduced a separate modern per-request path,serve_negotiated_request_directly, which the 2026-07-28 conformance scenario now hits (per-request_metanegotiation), and that path returns the first outbound message as the JSON body unconditionally whenjson_responseis enabled:For a progress-emitting tool the first message is
notifications/progress, so the client gets the notification as the response body and never receives the terminal result — the same failure mode #990 fixed for the legacy path. The modern path needs the same "JSON only when the first message is terminal, otherwise fall back to SSE" logic.Repro:
cargo build -p mcp-conformance STATELESS=1 PORT=8002 ./target/debug/conformance-server & npx -y @modelcontextprotocol/conformance@0.2.0-alpha.9 server \ --url http://127.0.0.1:8002/mcp --scenario tools-call-with-progress --spec-version 2026-07-28