Skip to content

fix(openapi): preserve anyOf/oneOf/allOf in projected MCP input schema#308

Open
AlexisMarasigan wants to merge 1 commit into
tadata-org:mainfrom
AlexisMarasigan:fix/preserve-anyof-in-input-schema
Open

fix(openapi): preserve anyOf/oneOf/allOf in projected MCP input schema#308
AlexisMarasigan wants to merge 1 commit into
tadata-org:mainfrom
AlexisMarasigan:fix/preserve-anyof-in-input-schema

Conversation

@AlexisMarasigan

@AlexisMarasigan AlexisMarasigan commented May 26, 2026

Copy link
Copy Markdown

Summary

convert_openapi_to_mcp_tools was injecting a top-level "type" field on every property without one — including properties whose schema used a JSON Schema composition keyword (anyOf, oneOf, allOf). The downstream jsonschema validator then AND'd the injected type with the existing composition, silently rejecting valid inputs at the MCP layer with Input validation error: <payload> is not of type '<picked>'.

For T | None, the bug surfaced as the nullable-rejection in #246. For T | U with both real types (e.g. dict[str, list[str]] | list[str]), the bug rejects whichever side lost the non-deterministic next(iter(set)) pick in get_single_param_type_from_schema#307.

Fix

Skip the "type" injection when any composition keyword is already present:

_COMPOSITION_KEYWORDS = ("anyOf", "oneOf", "allOf")

def _has_composition_keyword(schema):
    return any(k in schema for k in _COMPOSITION_KEYWORDS)

# in convert_openapi_to_mcp_tools, for path/query/body params:
if not _has_composition_keyword(properties[param_name]) and "type" not in properties[param_name]:
    properties[param_name]["type"] = ...

Tests

pytest tests/  →  71 passed

(The 14 errors in test_http_real_transport.py are pre-existing on mainRuntimeError: Event loop is closed on Python 3.13. Unrelated to this fix.)

Closes / refs

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.

`convert_openapi_to_mcp_tools` was injecting a single `"type"` field on
every property without one — including properties whose schema used a
JSON Schema composition keyword (`anyOf`, `oneOf`, `allOf`). The
downstream jsonschema validator then AND'd the injected `type` with the
existing composition, silently rejecting valid inputs at the MCP layer
with `Input validation error: <payload> is not of type '<picked>'`.

For `T | None` the bug surfaced as rejected null values (issue tadata-org#246).
For `T | U` with both real types (e.g. `dict[str, list[str]] | list[str]`)
the bug rejects whichever side lost the non-deterministic
`next(iter(set))` pick in `get_single_param_type_from_schema` (issue tadata-org#307).

Skip the "type" injection when any of the composition keywords is
already present. Updates two existing tests that asserted the buggy
behavior on `Optional[ProductCategory]` / `Optional[float]` /
`Optional[List[str]]` / `Optional[str]` params, and adds two regression
tests covering `T | U` and `oneOf`/`allOf`.

Closes tadata-org#307. Likely also closes tadata-org#246. May help tadata-org#165.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant