Skip to content

Commit 013ce5a

Browse files
committed
Remove redundant extra-field annotations from generated models
1 parent 6968429 commit 013ce5a

4 files changed

Lines changed: 16 additions & 28 deletions

File tree

‎scripts/gen_surface_types.py‎

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ def build(entry: dict[str, str]) -> str:
253253
source = raw.read_text(encoding="utf-8")
254254

255255
source = re.sub(r"\A# generated by datamodel-codegen:\n#[^\n]*\n", "", source)
256+
# Explicit __annotations__ hides declared fields under Python 3.14's deferred annotations.
257+
source = source.replace(' __annotations__ = {\n "__pydantic_extra__": Dict[str, Any],\n }\n', "")
258+
source = source.replace(", Dict,", ",")
256259
# Keep named aliases only for recursive types; other aliases remain ordinary Python types and unions.
257260
for node in reversed(ast.parse(source).body):
258261
if not (
@@ -292,13 +295,6 @@ def build(entry: dict[str, str]) -> str:
292295
staging = TYPES_DIR / f"_staging_{version}.py"
293296
try:
294297
staging.write_text(source, encoding="utf-8")
295-
subprocess.run(
296-
[
297-
"uv", "run", "--frozen", "ruff", "check", "--no-cache",
298-
"--select", "F401,UP006,UP035", "--fix", "--unsafe-fixes", str(staging),
299-
],
300-
cwd=REPO_ROOT, capture_output=True, check=True,
301-
) # fmt: skip
302298
subprocess.run(
303299
["uv", "run", "--frozen", "ruff", "format", "--no-cache", str(staging)],
304300
cwd=REPO_ROOT, capture_output=True, check=True,

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

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -394,9 +394,6 @@ class GetTaskPayloadResult(WireModel):
394394
model_config = ConfigDict(
395395
extra="allow",
396396
)
397-
__annotations__ = {
398-
"__pydantic_extra__": dict[str, Any],
399-
}
400397
meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None
401398
"""
402399
See [General fields: `_meta`](https://modelcontextprotocol.io/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.
@@ -793,9 +790,6 @@ class Meta(WireModel):
793790
model_config = ConfigDict(
794791
extra="allow",
795792
)
796-
__annotations__ = {
797-
"__pydantic_extra__": dict[str, Any],
798-
}
799793
progress_token: Annotated[ProgressToken | None, Field(alias="progressToken")] = None
800794
"""
801795
If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications.
@@ -953,9 +947,6 @@ class Result(WireModel):
953947
model_config = ConfigDict(
954948
extra="allow",
955949
)
956-
__annotations__ = {
957-
"__pydantic_extra__": dict[str, Any],
958-
}
959950
meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None
960951
"""
961952
See [General fields: `_meta`](https://modelcontextprotocol.io/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.
@@ -2656,9 +2647,6 @@ class Data(WireModel):
26562647
model_config = ConfigDict(
26572648
extra="allow",
26582649
)
2659-
__annotations__ = {
2660-
"__pydantic_extra__": dict[str, Any],
2661-
}
26622650
elicitations: list[ElicitRequestURLParams]
26632651

26642652

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,9 +1055,6 @@ class InputSchema(WireModel):
10551055
model_config = ConfigDict(
10561056
extra="allow",
10571057
)
1058-
__annotations__ = {
1059-
"__pydantic_extra__": dict[str, Any],
1060-
}
10611058
schema_: Annotated[str | None, Field(alias="$schema")] = None
10621059
type: Literal["object"]
10631060

@@ -1073,9 +1070,6 @@ class OutputSchema(WireModel):
10731070
model_config = ConfigDict(
10741071
extra="allow",
10751072
)
1076-
__annotations__ = {
1077-
"__pydantic_extra__": dict[str, Any],
1078-
}
10791073
schema_: Annotated[str | None, Field(alias="$schema")] = None
10801074

10811075

@@ -2028,9 +2022,6 @@ class Result(WireModel):
20282022
model_config = ConfigDict(
20292023
extra="allow",
20302024
)
2031-
__annotations__ = {
2032-
"__pydantic_extra__": dict[str, Any],
2033-
}
20342025
meta: Annotated[ResultMetaObject | None, Field(alias="_meta")] = None
20352026
result_type: Annotated[str, Field(alias="resultType")]
20362027
"""

‎tests/types/test_methods.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,19 @@ def test_serialize_server_result_preserves_open_type_extras():
960960
assert sieved["tools"][0]["_meta"] == nested_meta
961961

962962

963+
@pytest.mark.parametrize("input_schema", [{}, {"type": "array"}])
964+
def test_serialize_server_result_rejects_invalid_tool_input_schema(input_schema: dict[str, Any]) -> None:
965+
"""The 2026 spec requires a tool's input schema to declare `type="object"`, even though it allows extra keys."""
966+
result = {
967+
"tools": [{"name": "echo", "inputSchema": input_schema}],
968+
"resultType": "complete",
969+
"ttlMs": 0,
970+
"cacheScope": "private",
971+
}
972+
with pytest.raises(pydantic.ValidationError):
973+
methods.serialize_server_result("tools/list", "2026-07-28", result)
974+
975+
963976
def test_serialize_server_result_drops_top_level_server_info_on_discover_but_keeps_the_meta_stamp():
964977
"""Server identity moved from the discover body to result `_meta` (spec PR #3002):
965978
the sieve drops the removed body key and preserves the `_meta` stamp."""

0 commit comments

Comments
 (0)