[v1.x] Route Context.report_progress() to the originating request stream

Merged
MA
4mo ago
+10-3

Context.report_progress() was calling send_progress_notification() without related_request_id, so on Streamable HTTP the progress notification was routed to the standalone GET stream instead of the originating POST's SSE response stream. If the client hadn't yet opened the GET stream (or never opens one), the notification was silently dropped.

Motivation and Context

The spec says messages sent on a POST's SSE stream before the response "SHOULD relate to the originating client request", and messages on the standalone GET stream "SHOULD be unrelated to any concurrently-running JSON-RPC request from the client". Progress notifications carry the request's progressToken and so should go on the POST stream.

Context.log(), elicit(), and elicit_url() already pass related_request_id=self.request_id; this brings report_progress() in line.

This surfaced as a flake in the tools-call-with-progress server-conformance scenario, where the client (the TypeScript SDK transport, which opens the GET stream concurrently with the first request rather than awaiting it) sometimes hadn't registered the GET stream before the first report_progress() fired.

How Has This Been Tested?

  • Updated tests/issues/test_176_progress_token.py to assert related_request_id is forwarded.
  • Verified the test fails on v1.x without the fix and passes with it.
  • Ran the server-conformance suite locally against the everything-server.

Breaking Changes

None for the default SSE response mode (strict improvement: progress is now delivered on the POST stream regardless of GET timing).

Intentional behavior change: with json_response=True, progress notifications are now routed to the request stream and discarded along with other request-related notifications, rather than being sent on the standalone GET stream. This matches the existing behavior of Context.log() in that mode and is what the spec recommends for request-related messages.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

The standalone GET stream is optional per spec, and the TypeScript SDK client opens it fire-and-forget after notifications/initialized. Relying on it for request-related progress was always racy.

AI Disclaimer