[BUG] Cowork MCP client strips tool inputSchema properties typed as nullable unions (["string","null"]) — enums and nested schemas never reach the model
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
In Cowork mode (Claude Desktop for Windows), for any MCP tool inputSchema property whose type is a union array containing null (the standard output of .NET/C#/Kotlin nullable types), the schema surfaced to the model is reduced to an empty object — type, enum, and nested items/properties are all dropped. Only a stand-alone description survives.
What the MCP server sends (verbatim from a raw tools/list stdio capture — Sparx Systems Enterprise Architect MCP add-in MCP3.exe v2.8.4, tool create_or_update_connectors):
"direction": {
"type": ["string","null"],
"enum": ["Unspecified","FromSourceToTarget","FromTargetToSource","BothDirection", null]
}
What the model receives:
"direction": {}
More examples from the same tool, same pattern:
| Server sends | Model receives |
|---|---|
| "scope": {"type":["string","null"],"enum":["Public","Protected","Private","Package",null]} | "scope": {} |
| "routingStyle": {"description":"routing style in diagrams","type":["string","null"],"enum":["Default","OrthogonalSquare","OrthogonalRounded",null]} | "routingStyle": {"description":"routing style in diagrams"} |
| "taggedValues": {"description":"…","type":["array","null"],"items":{ …full nested object schema with its own enum… }} | "taggedValues": {"description":"…"} |
Simple-typed properties in the same tool are preserved correctly (e.g. "relatedElementID": {"type":"integer"} arrives typed; integer is normalized to number, which is harmless). The dropped properties are exactly those with union types.
Impact: the model cannot see the allowed enum values or nested structures, so it guesses — and every guess outside the invisible enum fails the tool call with the server's generic error. In our case this caused a three-email support exchange with the MCP server vendor (Sparx Systems Japan), where both sides were provably looking at different schemas: the vendor correctly claimed the enum is provided; our model never received it. Any MCP server whose schemas are generated from a language with nullable types is affected.
Related, but not duplicates: #5844 (display-level: anyOf-nullable params shown as unknown in /mcp), #31302 (large-schema truncation, closed as duplicate). This report is specifically about union-type properties arriving as {} in the model-facing schema, with a wire-level capture attached.
What Should Happen?
Nullable union types ("type": ["string","null"]) are valid JSON Schema (draft-07) and common in generated schemas. The client should preserve them as-is — or, if it must normalize for the API, keep the non-null member type together with enum and nested items/properties (e.g. {"type":"string","enum":[…]}), rather than dropping the property definition entirely. The model must see the same contract the server published.
Error Messages/Logs
No client-side error. Server-side consequence of the invisible enum: any guessed value fails with the server's generic error, e.g.:
request: {"connectorInfo":[{"connectorID":0,"type":"Dependency","direction":"Source -> Destination","sourceEnd":{"relatedElementID":1671},"targetEnd":{"relatedElementID":1672}}]}
response: "An error occurred invoking 'create_or_update_connectors'."
With the enum value from the raw schema (never shown to the model), the same call succeeds:
request: {"connectorInfo":[{"connectorID":0,"type":"Dependency","direction":"FromSourceToTarget",…}]}
response: {"Connectors":[{"connectorID":1177,"direction":"from source to target",…}]}
Steps to Reproduce
The MCP server used is the free official Sparx Systems EA MCP add-in (https://www.sparxsystems.jp/en/MCP), but any server declaring nullable union types reproduces it — a minimal FastMCP/TS server with one property "direction": {"type":["string","null"],"enum":["A","B",null]} is enough.
- Capture the server's raw
tools/list: run the server binary manually and paste{"jsonrpc":"2.0","method":"tools/list","id":1}on stdin. Confirm the property carriestype+enum(raw capture from our environment attached as file). - Connect the same server in Claude Desktop → Cowork mode (STDIO,
mcp.json). - In a Cowork session, ask Claude to quote the tool definition of the affected property exactly as it appears in its tool list (or let it attempt a call — it cannot know the enum values).
- Compare: the property arrives as
{}— notype, noenum; sibling properties with simple types ("type":"integer") arrive intact. - Optional control proving it is client-side: send the call by hand with a value from the raw enum — the server accepts it (see Error Messages/Logs section).
Claude Model
Not sure / Multiple models
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
Claude Desktop for Windows 1.20186.0 (Cowork mode; no CLI — bundled Claude Code runtime version not user-visible)
Platform
Other
Operating System
Windows
Terminal/Shell
Other
Additional Information
Environment detail: Claude Desktop for Windows 1.20186.0, Cowork mode (no terminal involved - the 'Terminal' field does not apply). MCP server connected via STDIO from mcp.json. Reproduced identically with Claude Fable 5 and Claude Opus 4.8, and against MCP server versions 2.8.2 and 2.8.4 - the behavior is model- and server-version-independent, pointing at the client-side schema pipeline.
I will attach the full raw tools/list capture (tools-list-raw-2.8.4.json) to this issue - it contains the complete create_or_update_connectors inputSchema as sent by the server, for direct comparison with what the model receives.