[BUG] MCP tool results silently replaced with full file content when input parameter is named `file_path`
Summary
Claude Code silently discards MCP tool results and replaces them with the raw file content when the MCP tool's input schema contains a parameter named file_path. This makes it impossible for MCP servers to return transformed/compressed file representations when using that parameter name.
Environment
- Claude Code version: 2.1.92
- OS: Windows 11 (10.0.22631)
- MCP SDK:
@modelcontextprotocol/sdk1.x (stdio transport)
Reproduction
MCP server setup
A custom MCP tool that reads a file via an external CLI (rtk) and returns a structurally compressed version (function signatures only, bodies omitted):
server.registerTool("rtk_read", {
title: "RTK Read",
description: "Structural file overview with 56-80% token reduction",
inputSchema: {
file_path: z.string().describe("Absolute path to the file"), // ← THIS NAME TRIGGERS THE BUG
},
annotations: {
readOnlyHint: true,
openWorldHint: false,
},
}, async ({ file_path }) => {
const output = await runRtk(["read", "--level", "aggressive", file_path]);
return { content: [{ type: "text", text: output }] };
});
Steps to reproduce
- Register the MCP tool above in
.mcp.json - Ask Claude to call
rtk_readon a 340-line JavaScript file - Observe that Claude receives 340 lines (full file) instead of the MCP server's 54-line compressed output
Verification at each layer
The MCP server's output was verified at every layer to confirm the server is NOT the source of the problem:
| Layer | Output (src/game/dice.js, 340 lines) |
|-------|------|
| RTK CLI direct (rtk read --level aggressive) | 55 lines / 3,263 chars ✅ |
| Node.js execFile calling RTK | 56 lines / 3,121 chars ✅ |
| MCP JSON-RPC direct test (stdin/stdout) | 56 lines / 3,121 chars ✅ |
| Claude Code → MCP tool call | 340 lines / full file ❌ |
Root cause isolation
Three variables were tested independently:
| Parameter name | readOnlyHint | Result |
|---|---|---|
| file_path | true | ❌ 340 lines (full file — overridden) |
| target | absent | ✅ 54 lines (compressed — correct) |
| target | true | ✅ 54 lines (compressed — correct) |
Conclusion: The file_path parameter name is the sole trigger. readOnlyHint has no effect.
Fix / Workaround
Renaming the input parameter from file_path to any other name (e.g. target, source, filepath) prevents the override. This is a viable workaround but is surprising and undocumented behavior.
Expected behavior
Claude Code should pass MCP tool results through to the model unmodified, regardless of parameter naming. If Claude Code needs to augment MCP results (e.g., for caching or context), it should do so additively (appending metadata) rather than replacing the tool's output.
Actual behavior
When an MCP tool has an input parameter named file_path, Claude Code:
- Calls the MCP tool (server receives the call and returns compressed output)
- Silently discards the MCP server's response
- Reads the file at the
file_pathvalue using its own built-in file reader - Returns the full file content to the model as if it were the MCP tool's output
This happens transparently — there is no error, warning, or log indicating the replacement.
Impact
- Token waste: MCP tools designed for token compression (structural overviews, summarization) are rendered useless. In our case, 84% compression savings are completely lost.
- Silent failure: Tool authors have no indication their output is being replaced. Debugging requires testing at every layer to isolate where the substitution occurs.
- Fragile contract: MCP tool behavior depends on parameter naming conventions that are undocumented. Renaming
file_pathtotargetchanges behavior with no schema or spec basis. - Broader risk: Other parameter names matching built-in tools (e.g.,
command,pattern,query) may trigger similar undocumented overrides.
Questions for the team
- Is this intentional behavior (e.g., for file content caching/deduplication)?
- If intentional, can it be made opt-out via an annotation or tool configuration?
- Are there other parameter names that trigger similar overrides?
- Related: #32105 (
updatedToolOutputfor PostToolUse hooks) — could this mechanism serve as a workaround for MCP tools?
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗