Skip to content

Commit 5faa8fe

Browse files
committed
Accept boolean sub-schemas in 2025-11-25 tool schema properties
JSON Schema 2020-12 allows `true`/`false` anywhere a sub-schema is expected, but the generated 2025-11-25 `InputSchema`/`OutputSchema` typed `properties` values as `dict[str, Any]`, so a tool advertising `"properties": {"result": true}` failed `ListToolsResult` validation and the whole listing was lost on any pre-2026 session. The 2026-07-28 surface already leaves these schemas free-form. Widen the `additionalProperties` of both `properties` maps to `anyOf: [object, boolean]` via the generator's existing schema-patch list and regenerate; the 2026-07-28 module is unchanged. Fixes #3353
1 parent 57394b0 commit 5faa8fe

3 files changed

Lines changed: 30 additions & 2 deletions

File tree

scripts/gen_surface_types.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@
5555
{"$ref": "#/$defs/PrimitiveSchemaDefinition"},
5656
{},
5757
),
58+
# JSON Schema 2020-12 allows a boolean wherever a sub-schema is expected, and
59+
# 2026-07-28 already leaves these free-form; accept `true`/`false` property schemas.
60+
(
61+
"$defs/Tool/properties/inputSchema/properties/properties/additionalProperties",
62+
{"additionalProperties": True, "properties": {}, "type": "object"},
63+
{"anyOf": [{"additionalProperties": True, "properties": {}, "type": "object"}, {"type": "boolean"}]},
64+
),
65+
(
66+
"$defs/Tool/properties/outputSchema/properties/properties/additionalProperties",
67+
{"additionalProperties": True, "properties": {}, "type": "object"},
68+
{"anyOf": [{"additionalProperties": True, "properties": {}, "type": "object"}, {"type": "boolean"}]},
69+
),
5870
],
5971
"2026-07-28": [
6072
("$defs/NumberSchema/properties/default/type", "number", ["integer", "number"]),

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,7 +1358,7 @@ class InputSchema(WireModel):
13581358
extra="allow",
13591359
)
13601360
schema_: Annotated[str | None, Field(alias="$schema")] = None
1361-
properties: dict[str, dict[str, Any]] | None = None
1361+
properties: dict[str, dict[str, Any] | bool] | None = None
13621362
required: list[str] | None = None
13631363
type: Literal["object"]
13641364

@@ -1376,7 +1376,7 @@ class OutputSchema(WireModel):
13761376
extra="allow",
13771377
)
13781378
schema_: Annotated[str | None, Field(alias="$schema")] = None
1379-
properties: dict[str, dict[str, Any]] | None = None
1379+
properties: dict[str, dict[str, Any] | bool] | None = None
13801380
required: list[str] | None = None
13811381
type: Literal["object"]
13821382

tests/types/test_methods.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,22 @@ def test_elicit_request_surface_accepts_loose_property_schemas():
474474
assert isinstance(parsed, types.ElicitRequest)
475475

476476

477+
def test_2025_11_25_tool_schema_surfaces_accept_boolean_sub_schemas():
478+
"""JSON Schema 2020-12 allows `true`/`false` wherever a sub-schema is expected; real servers emit them."""
479+
tool = {
480+
"name": "echo",
481+
"inputSchema": {"type": "object", "properties": {"arg": True}},
482+
"outputSchema": {
483+
"type": "object",
484+
"properties": {"result": True, "hidden": False, "rows": {"type": "array", "items": True}},
485+
"required": ["result"],
486+
},
487+
}
488+
sieved = methods.serialize_server_result("tools/list", "2025-11-25", {"tools": [tool]})
489+
assert sieved["tools"][0]["inputSchema"] == tool["inputSchema"]
490+
assert sieved["tools"][0]["outputSchema"] == tool["outputSchema"]
491+
492+
477493
def test_response_map_keys_mirror_the_request_map_keys():
478494
assert set(methods.SERVER_RESULTS) == set(methods.CLIENT_REQUESTS)
479495
assert set(methods.CLIENT_RESULTS) == set(methods.SERVER_REQUESTS)

0 commit comments

Comments
 (0)