Align with spec #3002: optional clientInfo, serverInfo in result _meta (#3143)

This commit is contained in:
Max 2026-07-23 12:00:36 +01:00 • committed by GitHub
commit 837ef904f8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 1757 additions and 567 deletions

View file

@ -302,12 +302,14 @@ PACKAGE_BY_VERSION = {
"2026-07-28": "mcp_types.v2026_07_28",
}
# The three reserved `params._meta` entries the 2026 surface requires on every request.
# The reserved `params._meta` entries the 2026 surface accepts on every request.
# `clientInfo` is optional (SHOULD-include, spec PR #3002); the other two are required.
META_TRIPLE: dict[str, Any] = {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {"name": "client", "version": "1.0"},
"io.modelcontextprotocol/clientCapabilities": {},
}
META_REQUIRED_KEYS = ("io.modelcontextprotocol/protocolVersion", "io.modelcontextprotocol/clientCapabilities")
# One minimal valid params mapping per surface request class.
REQUEST_PARAMS_FIXTURES: dict[type[BaseModel], dict[str, Any] | None] = {
@ -397,7 +399,6 @@ RESULT_BODY_FIXTURES: dict[type[BaseModel] | UnionType, dict[str, Any]] = {
v2026.DiscoverResult: {
"supportedVersions": ["2026-07-28"],
"capabilities": {},
"serverInfo": {"name": "server", "version": "1.0"},
"resultType": "complete",
"ttlMs": 0,
"cacheScope": "private",
@ -651,8 +652,8 @@ def test_unknown_version_strings_raise_value_error_on_every_parse_function():
assert "2099-01-01" in str(excinfo.value)
def test_2026_07_28_requests_missing_a_reserved_meta_entry_reject_as_missing():
for absent_key in META_TRIPLE:
def test_2026_07_28_requests_missing_a_required_meta_entry_reject_as_missing():
for absent_key in META_REQUIRED_KEYS:
partial_meta = {key: value for key, value in META_TRIPLE.items() if key != absent_key}
with pytest.raises(pydantic.ValidationError) as excinfo:
methods.parse_client_request("tools/list", "2026-07-28", {"_meta": partial_meta})
@ -661,6 +662,14 @@ def test_2026_07_28_requests_missing_a_reserved_meta_entry_reject_as_missing():
]
def test_2026_07_28_requests_accept_meta_without_the_optional_client_info():
"""spec PR #3002: `clientInfo` is optional on the 2026 surface - the required
pair alone validates."""
pair_meta = {key: value for key, value in META_TRIPLE.items() if key != "io.modelcontextprotocol/clientInfo"}
parsed = methods.parse_client_request("tools/list", "2026-07-28", {"_meta": pair_meta})
assert isinstance(parsed, types.ListToolsRequest)
def test_2026_07_28_results_require_result_type():
with pytest.raises(pydantic.ValidationError):
methods.parse_server_result("tools/call", "2026-07-28", {"content": []})
@ -861,7 +870,6 @@ MONOLITH_RESULT_FIXTURES: dict[str, types.Result] = {
"server/discover": types.DiscoverResult(
supported_versions=["2026-07-28"],
capabilities=types.ServerCapabilities(),
server_info=types.Implementation(name="server", version="1.0"),
ttl_ms=0,
cache_scope="private",
),
@ -927,6 +935,24 @@ def test_serialize_server_result_preserves_open_type_extras():
assert sieved["tools"][0]["_meta"] == nested_meta
def test_serialize_server_result_drops_top_level_server_info_on_discover_but_keeps_the_meta_stamp():
"""Server identity moved from the discover body to result `_meta` (spec PR #3002):
the sieve drops the removed body key and preserves the `_meta` stamp."""
stamp = {"name": "server", "version": "1.0"}
dumped: dict[str, Any] = {
"supportedVersions": ["2026-07-28"],
"capabilities": {},
"serverInfo": stamp,
"_meta": {types.SERVER_INFO_META_KEY: stamp},
"resultType": "complete",
"ttlMs": 0,
"cacheScope": "private",
}
sieved = methods.serialize_server_result("server/discover", "2026-07-28", dumped)
assert "serverInfo" not in sieved
assert sieved["_meta"] == {types.SERVER_INFO_META_KEY: stamp}
def test_serialize_server_result_drops_an_unknown_nested_tool_field():
tool = {"name": "echo", "inputSchema": {"type": "object"}, "unknownField": 1}
sieved = methods.serialize_server_result("tools/list", "2025-11-25", {"tools": [tool], "resultType": "complete"})

View file

@ -121,6 +121,7 @@ SKIP: frozenset[str] = frozenset(
"v2026_07_28.RequestMetaObject",
"v2026_07_28.RequestedSchema",
"v2026_07_28.ResourceRequestParams",
"v2026_07_28.ResultMetaObject",
"v2026_07_28.StringSchema",
"v2026_07_28.SubscriptionsListenResultMeta",
"v2026_07_28.TitledMultiSelectEnumSchema",