Initial Checks
Release line
2.x (current stable)
Description
What happens. ServerCapabilities is documented as "Not a closed set", but unknown keys are silently dropped (see the example below). Spec results are also sieved against the schema in ServerRunner._serialize, so even a custom server/discover handler that returns a dict with capabilities.events loses it before it reaches the wire.
What I expected. Extra capability keys to be kept, as the docstring suggests.
Why it matters. ChatGPT's MCP Events (launched 29 September 2026, docs at https://developers.openai.com/plugins/build/mcp-events) only subscribes to servers whose server/discover result contains top-level capabilities.events. With the SDK as it is, a Python server can't advertise it without working around the SDK.
Workaround. The events/* methods themselves register fine with add_request_handler. The capability can be added by a ServerMiddleware that edits the serialised result after call_next. That works, and I've tested it end to end with ChatGPT, but it relies on internals.
Possible fixes, in rough order of effort:
- Let ServerCapabilities keep extra keys (extra="allow"), so the "not a closed set" docstring holds and the sieve passes them through.
- A supported way to add capability keys, like extensions already has.
- First class Events support, following the draft in modelcontextprotocol/experimental-ext-triggers-events.
For anyone who needs it before then, I've published the workaround plus the full Events implementation (verification, signing, retries, persistence) as mcp-webhook-events on PyPI, MIT licensed: https://github.com/s1980amber-commits/mcp-webhook-events
Example Code
import mcp_types as t
caps = t.ServerCapabilities(tools={}, events={})
print(caps.model_dump(by_alias=True, exclude_none=True))
# prints {'tools': {}} (the 'events' key is dropped)
Python & MCP Python SDK
Python 3.12.3 (Linux) and 3.14.4 (Windows)
mcp 2.2.0, mcp-types 2.2.0
Protocol 2026-07-28, Streamable HTTP, stateless
Initial Checks
Release line
2.x (current stable)
Description
What happens. ServerCapabilities is documented as "Not a closed set", but unknown keys are silently dropped (see the example below). Spec results are also sieved against the schema in ServerRunner._serialize, so even a custom server/discover handler that returns a dict with capabilities.events loses it before it reaches the wire.
What I expected. Extra capability keys to be kept, as the docstring suggests.
Why it matters. ChatGPT's MCP Events (launched 29 September 2026, docs at https://developers.openai.com/plugins/build/mcp-events) only subscribes to servers whose server/discover result contains top-level capabilities.events. With the SDK as it is, a Python server can't advertise it without working around the SDK.
Workaround. The events/* methods themselves register fine with add_request_handler. The capability can be added by a ServerMiddleware that edits the serialised result after call_next. That works, and I've tested it end to end with ChatGPT, but it relies on internals.
Possible fixes, in rough order of effort:
For anyone who needs it before then, I've published the workaround plus the full Events implementation (verification, signing, retries, persistence) as mcp-webhook-events on PyPI, MIT licensed: https://github.com/s1980amber-commits/mcp-webhook-events
Example Code
Python & MCP Python SDK