Skip to content

Commit 153661c

Browse files
committed
Keep unknown keys on client and server capabilities
1 parent d7845c0 commit 153661c

5 files changed

Lines changed: 51 additions & 9 deletions

File tree

‎scripts/gen_surface_types.py‎

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,24 @@
106106
}
107107

108108
# Classes the spec defines as open key-value bags: `_meta` content, the
109-
# JSON-Schema-document fields on `Tool`, and the schemas with explicit
110-
# `additionalProperties: {}`. These keep `extra="allow"` so the sieve preserves
111-
# arbitrary keys; every other class ignores extras. Per-version because codegen
112-
# reuses class names across versions for unrelated schemas (e.g. `Data`).
109+
# JSON-Schema-document fields on `Tool`, the capability objects (documented as
110+
# "not a closed set"), and the schemas with explicit `additionalProperties: {}`.
111+
# These keep `extra="allow"` so the sieve preserves arbitrary keys; every other
112+
# class ignores extras. Per-version because codegen reuses class names across
113+
# versions for unrelated schemas (e.g. `Data`).
113114
OPEN_CLASSES: dict[str, frozenset[str]] = {
114-
"2025-11-25": frozenset({"Meta", "InputSchema", "OutputSchema", "Result", "GetTaskPayloadResult", "Data"}),
115+
"2025-11-25": frozenset(
116+
{
117+
"Meta",
118+
"InputSchema",
119+
"OutputSchema",
120+
"Result",
121+
"GetTaskPayloadResult",
122+
"Data",
123+
"ClientCapabilities",
124+
"ServerCapabilities",
125+
}
126+
),
115127
"2026-07-28": frozenset(
116128
{
117129
"MetaObject",
@@ -122,6 +134,8 @@
122134
"InputSchema",
123135
"OutputSchema",
124136
"Result",
137+
"ClientCapabilities",
138+
"ServerCapabilities",
125139
}
126140
),
127141
}

‎src/mcp-types/mcp_types/_types.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,8 @@ class ClientCapabilities(MCPModel):
393393
`initialize` through 2025-11-25; per-request in `_meta` on 2026-07-28.
394394
"""
395395

396+
model_config = ConfigDict(extra="allow")
397+
396398
experimental: dict[str, dict[str, Any]] | None = None
397399
"""Experimental, non-standard capabilities that the client supports."""
398400
sampling: SamplingCapability | None = None
@@ -485,6 +487,8 @@ class ServerTasksCapability(MCPModel):
485487
class ServerCapabilities(MCPModel):
486488
"""Capabilities that a server may support. Not a closed set."""
487489

490+
model_config = ConfigDict(extra="allow")
491+
488492
experimental: dict[str, dict[str, Any]] | None = None
489493
"""Experimental, non-standard capabilities that the server supports."""
490494

‎src/mcp-types/mcp_types/_v2025_11_25/__init__.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ class ClientCapabilities(WireModel):
196196
"""
197197

198198
model_config = ConfigDict(
199-
extra="ignore",
199+
extra="allow",
200200
)
201201
elicitation: Elicitation | None = None
202202
"""
@@ -1106,7 +1106,7 @@ class ServerCapabilities(WireModel):
11061106
"""
11071107

11081108
model_config = ConfigDict(
1109-
extra="ignore",
1109+
extra="allow",
11101110
)
11111111
completions: dict[str, Any] | None = None
11121112
"""

‎src/mcp-types/mcp_types/_v2026_07_28/__init__.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,7 +2041,7 @@ class ServerCapabilities(WireModel):
20412041
"""
20422042

20432043
model_config = ConfigDict(
2044-
extra="ignore",
2044+
extra="allow",
20452045
)
20462046
completions: JSONObject | None = None
20472047
"""
@@ -2287,7 +2287,7 @@ class ClientCapabilities(WireModel):
22872287
"""
22882288

22892289
model_config = ConfigDict(
2290-
extra="ignore",
2290+
extra="allow",
22912291
)
22922292
elicitation: Elicitation | None = None
22932293
"""

‎tests/types/test_methods.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,30 @@ def test_serialize_server_result_drops_top_level_server_info_on_discover_but_kee
10081008
assert sieved["_meta"] == {types.SERVER_INFO_META_KEY: stamp}
10091009

10101010

1011+
def test_discover_round_trips_unknown_server_capabilities():
1012+
capabilities = types.ServerCapabilities.model_validate({"tools": {}, "events": {"listChanged": False}})
1013+
result = types.DiscoverResult(supported_versions=["2026-07-28"], capabilities=capabilities)
1014+
dumped = result.model_dump(by_alias=True, mode="json", exclude_none=True)
1015+
sieved = methods.serialize_server_result("server/discover", "2026-07-28", dumped)
1016+
assert sieved["capabilities"] == {"tools": {}, "events": {"listChanged": False}}
1017+
parsed = methods.parse_server_result("server/discover", "2026-07-28", sieved)
1018+
assert isinstance(parsed, types.DiscoverResult)
1019+
assert parsed.capabilities.model_dump(by_alias=True, exclude_none=True) == sieved["capabilities"]
1020+
1021+
1022+
@pytest.mark.parametrize("version", PRE_2026)
1023+
def test_initialize_round_trips_unknown_capabilities_at_pre_2026_versions(version: str):
1024+
capabilities: dict[str, Any] = {"tools": {}, "events": {}}
1025+
result = {"protocolVersion": version, "capabilities": capabilities, "serverInfo": {"name": "S", "version": "1"}}
1026+
sieved = methods.serialize_server_result("initialize", version, result)
1027+
assert sieved["capabilities"] == capabilities
1028+
client_info = {"name": "C", "version": "1"}
1029+
params = {"protocolVersion": version, "capabilities": {"events": {"enabled": True}}, "clientInfo": client_info}
1030+
request = methods.parse_client_request("initialize", version, params)
1031+
assert isinstance(request, types.InitializeRequest)
1032+
assert request.params.capabilities.model_dump(exclude_none=True) == {"events": {"enabled": True}}
1033+
1034+
10111035
def test_serialize_server_result_drops_an_unknown_nested_tool_field():
10121036
tool = {"name": "echo", "inputSchema": {"type": "object"}, "unknownField": 1}
10131037
sieved = methods.serialize_server_result("tools/list", "2025-11-25", {"tools": [tool], "resultType": "complete"})

0 commit comments

Comments
 (0)