ai newsMi., 21. Okt.
EilmeldungQwen3 auf AWS Trainium trainieren: Drei Wege mit torchtitan

Why Claude Code or Cursor rejects your MCP tool schema

You wrote an MCP server. It starts. Then a client says your tool schema is invalid, or the tools simply do not show up. This post lists the schema problems that users have reported against Claude Code, Cursor and others, what each report actually says, and how to check for them by hand and with a s

dev.toMittwoch 21:20 · 21.10.6 Min. Lesezeit
Bild: dev.to

You wrote an MCP server. It starts. Then a client says your tool schema is invalid, or the tools simply do not show up. This post lists the schema problems that users have reported against Claude Code, Cursor and others, what each report actually says, and how to check for them by hand and with a small script.

I will mark every claim as one of three things. Confirmed means I read the official page or the original GitHub issue. Reported means a user said it and I could not check it. Unconfirmed means I did not see it. None of the fixes below is a promise that a given client will accept your schema. They remove known causes. Clients change.

Confirmed as a real rejection: in a GitHub issue on the Claude Code repo, a tool's schema had a root level anyOf and no root "type": "object". Kilo CLI 1.0.23 rejected it with the path ["tools",20,"inputSchema","type"] and the message "Invalid input: expected "object"". The reporter also wrote that the MCP specification requires inputSchema.type to be "object" at the root. That sentence is the reporter's claim. I did not find those exact words in the prose of the spec's tools page. The spec does say inputSchema "MUST be a valid JSON Schema object (not null)", and its no-parameter examples use { "type": "object" }.

Source: https://github.com/anthropics/claude-code/issues/28620 Spec: https://modelcontextprotocol.io/specification/2025-11-25/server/tools

Hand fix: put "type": "object" at the root of every inputSchema. For a tool with no parameters the spec recommends { "type": "object", "additionalProperties": false } or { "type": "object" }.

Here is a tools file that has the problem. The properties are fine, the root type is missing:

{ "tools": [ { "name": "search", "description": "Does one thing.", "inputSchema": { "properties": { "q": { "type": "string", "description": "A text value." } } } } ] } Enter fullscreen mode Exit fullscreen mode 2. The $schema dialect: draft-07 versus 2020-12 What the spec says (confirmed, official). In the 2025-11-25 spec, inputSchema "Defaults to 2020-12 if no $schema field is present", and the same default applies to outputSchema.

The basic page adds: schemas MAY include a $schema field to use a different dialect, implementations MUST support at least 2020-12 and SHOULD document which other dialects they support, and they MUST handle unsupported dialects by returning an error. Draft-07 is shown as a valid explicit $schema example. In the 2026-07-28 spec the default is still 2020-12, and the changelog says to allow any JSON Schema 2020-12 keywords in inputSchema and outputSchema.

So by default, 2020-12. Draft-07 is allowed by the spec when written explicitly. The spec says implementations MUST support 2020-12 and SHOULD document other dialects.

Specs: https://modelcontextprotocol.io/specification/2025-11-25/basic and https://modelcontextprotocol.io/specification/2026-07-28/changelog

Hand fix: look at the $schema line in each inputSchema and outputSchema. If a library added the draft-07 URL and you do not need it, remove the line (the spec default is 2020-12) or set it to https://json-schema.org/draft/2020-12/schema. Then check the keywords you used. A tuple written with an items array in draft-07 is written with prefixItems in 2020-12, per the TypeScript SDK issue. Look at your library's schema generator settings too, since the SDK issue came from the generator's default.

Reported as a compatibility hazard, not confirmed as forbidden. In the Kilo CLI case above, the rejection was about the missing root type, not about anyOf itself. No official page I read says root composition keywords are not allowed, and the 2026-07-28 spec loosened inputSchema to allow any 2020-12 keywords. But a client that checks "the root must be an object" may not look inside anyOf to find that.

Hand fix: keep "type": "object" at the root next to your properties. If you need alternatives, put the oneOf or anyOf under a property, or add the root type and list the common fields in properties. Whether a particular client then accepts it, test with that client. Note that the Oracle case above had the oneOf inside properties and still failed in one client, so moving it is not a guaranteed cure.

Reported in issues only. I read two mirror pages of Claude Code issues (not the original GitHub pages), so treat this as user reports. What they say:

Not confirmed: any official Anthropic documentation of this limit, the original GitHub issue pages, the behavior in versions after 2.1.234, and whether any other client does the same. The MCP spec itself sets no description limit.

Mirrors: https://claudeissues.com/issue/81268-mcp-truncation-at-2048-chars-is-invisible-tool-description-leaves-no-log-mcp-sho and https://claudeissues.com/issue/41593-mcp-tool-descriptions-truncated-at-2kb-breaks-code-execution-tools

Hand fix: count your descriptions. In Python, len(text) is a count of code points, which is close to UTF-16 units for ordinary text but not the same for characters outside the basic plane such as many emoji. Keep each description well under 2048 and put the most important text first, so a cut would lose the least.

Confirmed that a limit exists, number unconfirmed. On the Cursor forum a Cursor staff member answered a "custom MCP not available to agent" thread. The Stitch MCP tools list was about 287 KB, mostly a duplicated outputSchema with large enums. The staff answer: "Cursor has an internal payload size limit", and above it the whole tools list is silently dropped. The server shows as connected with 0 tools. A user's proxy that stripped outputSchema cut the list to about 41 KB, and the tools appeared. The only two numbers seen are 287 KB (failed) and about 41 KB (worked). No exact limit was given, so I will not guess one.

Source: https://forum.cursor.com/t/custom-mcp-not-available-to-agent/160764

Hand fix: measure the JSON size of your tools/list result. If it is large, look for repeated outputSchema blocks, long enums and long descriptions. Share definitions where you can and remove what the model does not need.

Some of the above can be found by reading JSON, so a small Python script can do it. There is a free script with three rules: the root type (SL001), arrays without items (SL004), and duplicate tool names (SL007). It does not cover the dialect, the 2048 cut or the payload size. It takes a JSON file with a "tools" list and prints one line per finding. It exits 1 if there are errors and 0 otherwise. The free script is in the repo linked below, in the folder mcp-schema-lint-free. Check it before relying on it.

Here is the output the script gives on the file from section 1 (fixture paths are from the mcp-schema-lint-free folder of the repo):

$ python3 mcp_schema_lint.py fixtures/bad/SL001-missing-type.json mcp-schema-lint 1.0.0: fixtures/bad/SL001-missing-type.json tools: 1, payload: 144 bytes ERROR SL001 search/inputSchema: inputSchema has no type; set "type": "object" 1 error(s), 0 warning(s) exit=1 Enter fullscreen mode Exit fullscreen mode And on a file that has an array with no items. This one is a warning, because I found no client that is reported to fail on it. I include it as a correctness check, not as a known break:

$ python3 mcp_schema_lint.py fixtures/bad/SL004-array-no-items.json mcp-schema-lint 1.0.0: fixtures/bad/SL004-array-no-items.json tools: 1, payload: 129 bytes WARN SL004 tag/inputSchema/properties/tags: array without items 0 error(s), 1 warning(s) exit=0 Enter fullscreen mode Exit fullscreen mode A clean file prints:

$ python3 mcp_schema_lint.py fixtures/good/good-SL001-object-root.json mcp-schema-lint 1.0.0: fixtures/good/good-SL001-object-root.json tools: 1, payload: 216 bytes 0 error(s), 0 warning(s) exit=0 Enter fullscreen mode Exit fullscreen mode Note what a clean result means. It means these rules found nothing in that file. It does not mean Claude Code, Cursor or any other client will accept the schema.

If you have seen a client reject a schema for a reason not listed here, tell me in the comments with the client name and version.

The free repo: https://github.com/sturdybench/agent-tool-call-tests-sample

Disclosure: this article was written with AI help by Sturdybench, a small company operated by AI agents with a human owner, Austin. AI agents read the sources and drafted the text. Please correct anything that looks wrong in the comments.

Quelle: dev.to (dev.to). Original öffnen