MCP Tool Schema Checker
Paste an MCP tools/list response, a single MCP tool, or an OpenAI or Anthropic function definition. The checker applies rules from the MCP 2026-07-28 specification and the OpenAI and Claude tool-use docs: name rules per provider, required fields that do not exist, invented types, coded enums, dates with no format, x-mcp-header values that get a tool dropped, strict-mode incompatibilities, and annotation contradictions. It can also check a tools/call result against the tool's outputSchema. Everything runs in your browser.
Check tool definitions
MCP 2026-07-28 · OpenAI · Claude
Runs in your browser. The checker is deterministic rules, not an LLM. Your tool definitions are never uploaded or stored.
MCP tools/list JSON-RPC response · 3 tools
Error:
orders.searchrequired names "customer_id", which is not in propertiesresult.tools[0].inputSchema.required
The model is never told the key exists or what type it takes, so it rarely sends it, and validation fails the call. This is usually a renamed property whose required entry was left behind.
Fix: Add the property with a type and description, or remove it from required.
required-unknown · JSON Schema
Error:
get_orderx-mcp-header "Order Id" is not an HTTP tokenresult.tools[1].inputSchema.properties.orderId["x-mcp-header"]
The value must match RFC 9110 field-name syntax, so spaces, colons and control characters are not allowed. Streamable HTTP clients MUST reject a tool with an invalid x-mcp-header and leave it out of tools/list, so the model never sees this tool.
Fix: Use letters, digits and hyphens.
mcp-header-invalid · MCP 2026-07-28
Error:
cancel_order"float" is not a JSON Schema typeresult.tools[2].inputSchema.properties.refundAmount.type
Validators reject the schema, and models that do read it treat the type as unknown. Names like int, float, str and dict usually come from a Python or TypeScript type leaking into the schema.
Fix: Use "number".
type-invalid · JSON Schema
Warning:
orders.searchCoded enum has no descriptionresult.tools[0].inputSchema.properties.status.enum
The model sees "P", "S", "X" but not what each means, so it picks by position or by guess.
Fix: Add a description that maps each value to its meaning.
enum-undescribed · Tool design
Warning:
orders.search"createdAfter" looks like a date or time but its format is not statedresult.tools[0].inputSchema.properties.createdAfter
The model may send "2026-10-16", "16/10/2026" or "next Friday". The schema accepts them all, and the handler parses whichever arrived.
Fix: Add `"format": "date"` or `"date-time"`, and an example in the description.
date-format-unstated · Tool design
Warning:
cancel_orderDescription is 3 wordsresult.tools[2].description
A one-line description leaves the model to infer when to call the tool and what the arguments mean, so it calls it for near-miss requests or fills arguments with plausible guesses.
Fix: Add when to use it, when not to, what it returns, and one concrete example value.
description-thin · Tool design
Warning:
cancel_ordernullable is OpenAPI 3.0, not JSON Schemaresult.tools[2].inputSchema.properties.reason.nullable
JSON Schema validators ignore nullable, so a null from the model fails validation even though the schema looks like it allows one.
Fix: Use a type array such as `"type": ["string", "null"]`.
openapi-nullable · JSON Schema
Warning:
cancel_orderName suggests a destructive action, destructiveHint is falseresult.tools[2].annotations.destructiveHint
false tells an honest host the tool only adds things. It may drop the confirmation step for a delete or reset.
Fix: Remove destructiveHint (it defaults to true) or set it to true, and require confirmation outside the model.
annotations-destructive-false · MCP 2026-07-28
Info:
orders.searchUnknown arguments are acceptedresult.tools[0].inputSchema
Without `additionalProperties: false` a misspelt or invented argument (userID for userId) passes validation. Zod's default object then strips it, and the call succeeds without the value the model thought it sent.
Fix: Add `"additionalProperties": false` (z.strictObject in Zod) so the model gets a validation error it can correct.
extra-keys-accepted · JSON Schema
Info:
cancel_orderUnknown arguments are acceptedresult.tools[2].inputSchema
Without `additionalProperties: false` a misspelt or invented argument (userID for userId) passes validation. Zod's default object then strips it, and the call succeeds without the value the model thought it sent.
Fix: Add `"additionalProperties": false` (z.strictObject in Zod) so the model gets a validation error it can correct.
extra-keys-accepted · JSON Schema
Info:
cancel_order3 parameters have no description: orderId, refundAmount, reasonresult.tools[2].inputSchema.properties
The model fills parameters from their names alone. Names like id, query or type rarely say which id, what syntax, or which type.
Fix: Give each parameter a description with its meaning, format and an example value.
params-undescribed · Tool design
Check a tools/call result against outputSchema
Paste one result for a tool from the list above. The sample shows a result that drifted from get_order's schema.
Paste a result to check it.
What the checker can and cannot tell you(click to expand)
Why is a dotted name fine for MCP but an error for OpenAI?
MCP allows letters, digits, underscore, hyphen and dot, up to 128 characters. OpenAI function names allow letters, digits, underscore and dash up to 64; Claude allows the same set up to 128. A host that forwards MCP tools to a model API has to rename orders.search, so pick Check against for the models your agent uses.
What does strict mode change?
OpenAI strict mode and Claude strict tool use accept a subset of JSON Schema. OpenAI requires additionalProperties: false on every object and every property in required. Claude requires the same additionalProperties, rejects numeric and length constraints, and caps optional and union-typed parameters across the whole request. Tools that set strict: true are always checked this way.
What will it miss?
The rules read the schema, not the server. They cannot see whether the handler enforces what the schema promises, whether a model actually calls the tool correctly, or whether annotations tell the truth. Treat a clean report as a well-formed contract, and test the calls themselves. Heuristic rules such as thin descriptions and date-like names say so in their explanation.