modelcontextprotocol / modelcontextprotocol/python-sdk
[v2] Allow MCPServer to disable subscriptions/listen
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 24.3k
- Forks
- 4k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 31
Description
Initial Checks
- I confirm that I'm using the newest release of my line (the latest 2.x, or the latest 1.x if I'm still on v1)
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Release line
2.x (current stable)
Description
What happened?
MCPServer always installs a subscriptions/listen handler:
on_subscriptions_listen=ListenHandler(self._subscriptions)
The constructor exposes subscriptions: SubscriptionBus | None = None, but None creates an InMemorySubscriptionBus; it does not disable subscriptions.
This causes server/discover to advertise:
{
"tools": {"listChanged": true},
"prompts": {"listChanged": true},
"resources": {"listChanged": true, "subscribe": true}
}
Our MCP server has a static catalog and never publishes change notifications. It runs as a stateless Streamable HTTP server on AWS Lambda.
Claude Code 2.1.235 automatically opened four subscriptions/listen streams during discovery. Each request followed the long-lived SSE path and held a Lambda invocation until timeout.
We currently reject these requests in ASGI middleware. This prevents the timeout, but the server still advertises subscription support, so clients continue attempting the requests.
The low-level Server supports disabling this correctly through:
Server(..., on_subscriptions_listen=None)
The high-level MCPServer has no equivalent public option. Removing the handler through _lowlevel_server._request_handlers works, but relies on private internals.
What did you expect?
MCPServer should provide a supported opt-out, for example:
MCPServer(..., subscriptions=False)
or:
MCPServer(..., enable_subscriptions=False)
When disabled:
subscriptions/listenshould not be registered.- server/discover should advertise the relevant change and subscription capabilities as false.
- An unsolicited subscriptions/listen call should return Method not found.
- Existing behavior should remain the default for compatibility.
This matches SEP-2575’s stateless-first, “pay as you go” design. Long-lived streams should only be enabled when the server uses them.
Area
Server
References
AI assistance disclosure: I used an AI coding assistant to inspect the SDK source and help draft this report. I reviewed and verified the contents.
Example Code
from mcp.server import MCPServer
server = MCPServer("static-server")
capabilities = server._lowlevel_server.get_capabilities(
protocol_version="2026-07-28"
)
print(capabilities.model_dump(by_alias=True, exclude_none=True))
Python & MCP Python SDK
Python 3.11
mcp 2.0.0
AWS Lambda
Streamable HTTP
json_response=True
stateless_http=True
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the MCPServer constructor and its on_subscriptions_listen=ListenHandler(self._subscriptions) registration, then inspect _lowlevel_server.get_capabilities and the subscriptions/listen request path. Define the public opt-out while preserving the current default behavior. Done means disabled servers omit the handler, advertise the relevant capabilities as false, and return Method not found for unsolicited subscriptions/listen calls.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend-api-design
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100