Repository navigation
fix: preserve explicit nulls in MCP tool arguments - #303
liangzhechen655 wants to merge 3 commits into
Conversation
Eigenwise
left a comment
There was a problem hiding this comment.
Source review of eabd141ae4fec8598f0aff96f83fc9ee0dbc7016: preserving explicit nulls for nullable arguments is useful, but mcp_factory.py:182 also forwards null for nonnullable optional fields. For an optional property advertised as type: string without a default, the existing generated model accepts an explicitly supplied value=None. The new dump sends {"value": null}; the old dump omitted it. A server validating that advertised schema rejects the new request.
Preserve the distinction between genuinely nullable arguments and locally accepted None for a nonnullable field. Add that nonnullable regression while retaining the required-null, explicit optional-null, omission, default, zero and false cases. Check both fresh and persistent session forwarding.
This finding is source-derived. I haven't run this head's tests or measured its per-function coverage.
Eigenwise
left a comment
There was a problem hiding this comment.
Rechecked 301f1eb7c947c24678c4ccacf2d6b60cfaf10b43. Plain nonnullable None is now omitted, nullable null and supplied values are retained, and the per-tool referenced-type case passes. Normal CI passed all 35 new cases, 435 tests total with 3 MiniMax skips; formatting and lint passed.
One advertised-nullability gap remains at mcp_factory.py:67-69: an optional value referencing $defs.Value = {"enum": ["brief"]} is converted to Any, so the TypeAdapter check accepts None and forwards {"value": null}. The advertised enum rejects that request; the base omitted the value. Referenced nonnull const and enum inside anyOf have the same gap. An outer type: string with a nullable anyOf also must not forward null.
Preserve null restrictions through references and applicable schema combinations when deciding whether to forward None. Add focused generated-tool argument assertions for these cases in both session paths, keeping the current passing presence cases. These counterexamples are source-derived, not locally executed.
A generated MCP tool serializes inputs with
exclude_none=True, losing an explicitly supplied null even when the server declares that parameter nullable. A required nullable input can become an empty request, and an optional null cannot distinguish clearing a value from omission.Preserve supplied field presence with
exclude_unset=True. Determine nullability from the declared parameter type before the converter widens optional fields to acceptNone. Only genuinely nullable parameters forward null; locally acceptedNoneon a nonnullable optional parameter stays omitted. Each generated tool stores its own nullability information, including referenced types, and both fresh and persistent sessions use the same serialization.Validation on Windows / Python 3.13: