-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Open
Labels
P3Nice to haves, rare edge casesNice to haves, rare edge casesfeature requestRequest for a new feature that's not currently supportedRequest for a new feature that's not currently supportedimproves spec complianceWhen a change improves ability of SDK users to comply with spec definitionWhen a change improves ability of SDK users to comply with spec definitionready for workEnough information for someone to start working onEnough information for someone to start working on
Description
Initial Checks
- I confirm that I'm using the latest version of MCP Python SDK
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Description
MCP Python SDK Protocol Compliance Gap: Response Sent After Receiving Cancellation Notifications
- Assessment: This is a protocol “SHOULD not” compliance gap. When acting as the receiver of a cancellation notification, the SDK still sends a JSON-RPC error response for the cancelled request, contrary to the spec’s guidance.
Description
The MCP specification states: “Receivers of cancellation notifications SHOULD not send a response for the cancelled request.”
In the current implementation, after processing a CancelledNotification
, the SDK sends an error response for the cancelled in-flight request.
Detailed Analysis
- Dedicated handling branch for cancellation notifications(https://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/shared/session.py#L382):
# Handle cancellation notifications
if isinstance(notification.root, CancelledNotification):
cancelled_id = notification.root.params.requestId
if cancelled_id in self._in_flight:
await self._in_flight[cancelled_id].cancel()
cancel()
sends an error response instead of silently terminating( (https://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/shared/session.py#L135)):
async def cancel(self) -> None:
"""Cancel this request and mark it as completed."""
...
self._cancel_scope.cancel()
self._completed = True # Mark as completed so it's removed from in_flight
# Send an error response to indicate cancellation
await self._session._send_response(
request_id=self.request_id,
response=ErrorData(code=0, message="Request cancelled", data=None),
)
- Result: Even when the cancellation is triggered by a
CancelledNotification
, the SDK responds with a JSON-RPC error for the cancelled request, diverging from the spec’s “SHOULD not” recommendation.
Potential Impact
- Protocol consistency: Behavior deviates from the spec’s guidance, potentially surprising peers that expect silent termination.
- Interoperability: Differences may surface when integrating with implementations that strictly follow the “SHOULD not” behavior.
Remediation
- Implement silent cancellation for notification-triggered cancellations:
- Add a non-responding cancellation path on
RequestResponder
(e.g.,mark_cancelled_without_response()
), which cancels and marks complete without calling_send_response
. - In the cancellation notification handling branch, call the silent path instead of
cancel()
.
- Add a non-responding cancellation path on
Suggested Implementation
- Location:
src/mcp/shared/session.py
inBaseSession._receive_loop()
cancellation branch and inRequestResponder
.
Change call site to silent cancellation:
- From:
await self._in_flight[cancelled_id].cancel()
- To:
await self._in_flight[cancelled_id].mark_cancelled_without_response()
Impact
- Aligns behavior with the MCP spec’s “SHOULD not” guidance.
- Reduces unnecessary response traffic and improves predictability and interoperability in cancellation flows.
Example Code
Python & MCP Python SDK
Latest
Metadata
Metadata
Assignees
Labels
P3Nice to haves, rare edge casesNice to haves, rare edge casesfeature requestRequest for a new feature that's not currently supportedRequest for a new feature that's not currently supportedimproves spec complianceWhen a change improves ability of SDK users to comply with spec definitionWhen a change improves ability of SDK users to comply with spec definitionready for workEnough information for someone to start working onEnough information for someone to start working on