[MODEL] Model ignores MCP tool schema default values, prefers JSON over custom formats (TOON)
Preflight Checklist
- [x] I have searched existing issues for similar behavior reports
- [x] This report does NOT contain sensitive information (API keys, passwords, etc.)
Type of Behavior Issue
Ignoring instructions or constraints
What You Asked Claude to Do
I built a custom MCP server with ~78 tools using @modelcontextprotocol/sdk. Many tools define a format parameter with default: "toon":
{
"format": {
"default": "toon",
"description": "Output format",
"enum": ["toon", "json"],
"type": "string"
}
}
TOON is a tab-delimited format I built for token efficiency. It cuts output size by about 50% compared to JSON for list/table data. The whole point of setting default: "toon" is so the server uses TOON when the model doesn't explicitly specify a format.
I asked Claude to search and list items. Simple listing operations where TOON is the right fit.
What Claude Actually Did
On every single tool call, the model explicitly passed format: "json", even for basic list/search operations where JSON adds no value.
Example tool calls observed:
my_search(query: "monthly reports", maxResults: 5, format: "json")
my_search(query: "project updates Q1", maxResults: 10, format: "json")
my_list(category: "active", format: "json")
These are all list operations returning tabular data (titles, dates, categories). TOON handles this perfectly. But the model never once omitted the format parameter to let my default kick in.
I've been using this MCP server daily for weeks. This isn't a one-off. Across multiple sessions and different types of queries, the model always explicitly passes format: "json". It never respects the schema default.
Expected Behavior
- For list/search operations, respect the schema default. Either omit
formator pass"toon" - Only override to
"json"when there's an actual need (like parsing deeply nested structures) - The
defaultfield in tool schemas should influence parameter selection, not get ignored
What the Docs Say (and Don't Say)
I went through the relevant documentation to understand if this is expected or a gap:
1. Claude 4.6 "What's New" (docs)
The release notes document a breaking change under "Tool parameter quoting":
"Opus 4.6 may produce slightly different JSON string escaping in tool call arguments."
This confirms tool call argument handling has changed in Opus 4.6. But there is no mention of how default values in tool schemas should be handled.
2. Tool Use Overview (docs)
The official tool use docs actually show this same pattern in their own examples. In the get_weather example, the unit parameter is optional (not in required array), yet Claude explicitly passes "unit": "celsius" anyway. The docs even acknowledge this:
"as well as a guessed unit parameter, as unit is not a required parameter"
So the model already has a documented tendency to fill in optional parameters with its own guesses. My issue extends this: when an optional parameter has an explicit default value in the schema, the model should use that default rather than guessing its own preferred value.
The tool use docs also mention that the model may "do its best to infer a reasonable value" for parameters. But "reasonable" should mean respecting the developer-specified default, not overriding it with the model's own bias toward JSON.
3. MCP Specification (spec)
The MCP spec defines inputSchema as standard JSON Schema. JSON Schema supports the default keyword. But neither the MCP spec nor Anthropic's tool use docs define how the model should handle default values. This is the gap.
The actual problem
None of these docs specify that the model should respect default values in tool parameter schemas. The behavior is undefined, and the model falls back to its training prior (JSON > everything else). This means MCP server developers can set default values in their schemas, but the model will ignore them.
Files Affected
None. This is about how the model selects parameter values when calling MCP tools.
Permission Mode
Default (auto-approve MCP tools)
Can You Reproduce This?
Yes, every time.
Steps to Reproduce
- Define an MCP tool with a parameter that has a non-JSON default:
server.tool(
'my_search',
'Search items',
{
query: z.string(),
format: z.enum(['toon', 'json']).default('toon').describe('Output format'),
},
async ({ query, format }) => {
// format will always be "json" when called by the model,
// even though default is "toon"
}
);
- Connect the MCP server to Claude Code
- Ask Claude to use that tool for any task
- Check the tool call. The model will explicitly pass
format: "json" - Repeat in new sessions. Same result every time.
Claude Model
Claude Opus 4.6 (claude-opus-4-6)
Impact
- Token cost adds up. TOON saves ~50% tokens on list output. With 78 tools used daily, the model picking JSON every time wastes context window over time.
- Schema defaults don't work. If the model ignores
defaultvalues, there's no point setting them. MCP developers lose control over their own tool's output behavior. - Not just my format. Any MCP server with a custom output format will hit this. The model gravitates to JSON regardless of what the developer configured as default.
- Documented pattern. The tool use docs already show the model filling in optional parameters with guessed values (
unit: "celsius"). Withdefaultvalues, there's an explicit developer preference that should take priority over the model's guess.
Claude Code Version
2.1.45 (Claude Code)
Platform
Claude Code CLI (Windows 11), Claude Max subscription
Suggested Fixes
- Model-level: Tune the model to factor in
defaultvalues when selecting tool parameters. If a default exists and the user didn't request a specific format, use the default instead of guessing. - Claude Code level: When forwarding tool schemas to the model, add guidance to respect
defaultvalues unless there's a reason to override. - Documentation level: The tool use docs and MCP integration docs should specify how
defaultvalues in tool schemas are expected to be handled by the model. Right now this behavior is undefined.
Environment
- OS: Windows 11 Pro 10.0.26200
- Node.js MCP server using
@modelcontextprotocol/sdk - 10 MCP servers connected, ~78 tools on the affected server
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗