[BUG] Claude Code MCP Parameter Serialization Bug

Status Fixed / completed
Maintainer reply ✓ Yes — ollie-anthropic
Activity 9 comments · opened Jul 19, 2025 · closed Nov 18, 2025
💡 Likely answer: A maintainer (ollie-anthropic, collaborator) responded on this thread — see the highlighted reply below.

Claude Code MCP Parameter Serialization Bug

Summary

Claude Code is sending empty parameter dictionaries {} to MCP servers, breaking all tools that require parameters.

Environment

  • Claude Code version: Latest (July 2025) - check with claude --version
  • OS: macOS Darwin 24.3.0
  • Node.js: v23.11.0
  • MCP SDK: @modelcontextprotocol/sdk (latest)
  • Server type: Both stdio and HTTP MCP servers affected

Expected Behavior

When calling MCP tools with parameters like:
mcp__server-name__tool_name
Parameters: {"param1": "value1", "param2": "value2"}
The MCP server should receive the parameters correctly in request.params.

Actual Behavior

MCP servers receive empty parameter dictionaries {} regardless of what parameters are specified in Claude Code.

Evidence

Production Server Logs

Server logs consistently show:
"Raw params_dict: {}"
"Type of params_dict: <class 'dict'>"

Comprehensive Testing Results

  • ✅ Direct MCP Protocol: Works perfectly - parameters properly received
  • ✅ Claude Desktop: Works perfectly with identical servers
  • ❌ Claude Code: Sends empty objects instead of parameters
  • ✅ 48-tool production system: Works flawlessly in Claude Desktop, fails in Claude Code

Reproduction Steps

Quick Reproduction

  1. Set up any MCP server with tools requiring parameters
  2. Configure Claude Code to use the server: claude mcp add server-name "node" "/path/to/server.js"
  3. Call any tool with parameters
  4. Check server logs - parameters are empty {}

Detailed Reproduction (Attached Files)

The attached claude-code-mcp-bug-repro folder contains a complete reproduction case:

  1. Install: npm install
  2. Verify server works: ./test-mcp-direct.sh (shows parameters received correctly)
  3. Configure Claude Code: claude mcp add test-server "node" "/path/to/test-server.js"
  4. Test in Claude Code: Call mcp__test-server__test_tool with test_param: "hello"
  5. Observe bug: Server logs show empty parameters despite tool call

Root Cause

Parameter serialization bug in Claude Code's MCP implementation. The issue is NOT in:

  • ❌ MCP server implementations (work perfectly with direct protocol)
  • ❌ Parameter schemas (correctly defined)
  • ❌ MCP SDK (works with Claude Desktop)

The bug IS in:

  • ✅ Claude Code's parameter passing to MCP servers

Impact

  • All parameterized MCP tools are broken in Claude Code
  • Same tools work perfectly in Claude Desktop
  • Affects entire MCP ecosystem compatibility
  • Forces users to switch to Claude Desktop for MCP workflows
  • Breaks production systems (our 48-tool email management platform)

Comparison: Working vs Broken

| Environment | Parameter Reception | Status |
|---------------------|---------------------------------------------------|----------|
| Direct MCP Protocol | {"name": "tool", "arguments": {"param": "value"}} | ✅ Works |
| Claude Desktop | Parameters received correctly | ✅ Works |
| Claude Code | {} (empty object) | ❌ Broken |

Workaround

Use Claude Desktop instead of Claude Code for MCP tools requiring parameters.

Additional Context

  • Simple tools with no parameters work correctly in Claude Code
  • Issue affects both custom and official MCP servers
  • Parameter schemas are correctly defined per MCP specification
  • Direct API calls to servers work with proper parameters
  • Multiple server architectures tested (stdio, HTTP, different languages)

Attached Files

Complete reproduction package in claude-code-mcp-bug-repro/:

  • test-server.js - Minimal MCP server with detailed parameter logging
  • test-mcp-direct.sh - Proof that direct MCP protocol works
  • REPRODUCTION_STEPS.md - Step-by-step reproduction guide
  • BUG_EVIDENCE.md - Comprehensive evidence documentation
  • package.json - Required dependencies

---
Priority: High - This breaks fundamental MCP compatibility for Claude Code users and significantly impacts the MCP ecosystem
adoption.

BUG_EVIDENCE.md
REPRODUCTION_STEPS.md
package-lock.json
package.json

View original on GitHub ↗

9 Comments

ollie-anthropic collaborator · 1 year ago

Hi @ivan-rivera-projects - thanks for reporting this

Would you also be able to provide the test-server.js? I can't seem to reproduce this myself

richmarshall · 1 year ago

Hi, I installed Claude for Windows (Claude 0.12.28 (5f9bc7)) a few days back and built an MCP server using stdio. When logging out the tool call context, we can see the params are never set.

This should be pretty easy to recreate?

perrinmorrow · 1 year ago

I've also hit this with 0.12.28 (5f9bc7), starting today. It even happens with the filesystem MCP client. From the logs:

2025-07-23T03:45:55.174Z [filesystem] [info] Message from client: {"method":"tools/call","params":{"name":"read_file"},"jsonrpc":"2.0","id":8} { metadata: undefined }

The first call after restarting the app works, subsequent ones have no arguments field in the params.

tennox · 1 year ago

✅ Root Cause Identified + Minimal Reproduction Case

Through systematic testing, claude has identified the exact schema pattern that triggers this MCP parameter bug:

🎯 Specific Bug Trigger:

Schema pattern: {"type": ["string", "null"], "default": null} combined with required fields

Working schemas:

  • ✅ All required: {"type": "string"} + "required": ["field"]
  • ✅ All optional: {"type": "string", "default": "value"} + "required": []

Failing schema:

  • ❌ Mixed with union type: {"type": ["string", "null"], "default": null} + required fields

🧪 Minimal Reproduction Case:

I've created a complete reproduction script: Claude Code MCP Parameter Bug Reproduction

The gist includes:

  • ✅ Ready-to-run MCP server script
  • ✅ Step-by-step setup instructions
  • ✅ Three test cases showing working vs broken patterns
  • ✅ Technical analysis of the exact trigger condition

🔍 Evidence:

MCP Protocol Logs show Claude Code sending:

// Broken case (union type + null default)
"arguments": Some({})  // Empty despite user providing parameters!

// Working case (all required)  
"arguments": Some({"field1": "value1", "field2": "value2"})

📋 Quick Reproduction:

  1. Download the gist script
  2. Add to .mcp.json
  3. Try calling test_mixed_params(content: "hello", parent: "test")
  4. Bug occurs: Gets "missing field 'content'" despite providing it

This union type + null default pattern is commonly used by MCP servers for optional parameters, making this bug affect many real-world tools.

Tested on Claude Code 1.0.69
by: Claude Code 1.0.69

tennox · 1 year ago

@ollie-anthropic It's quite unfortunate I have to add separate MCP tool for every parameter variation currently. (can't use optional parameters)
I also can't use other MCP tools that have this kind of optional parameters.

Please investigate this 🙏

domdomegg · 11 months ago

I attempted to reproduce this bug locally and it appears to be fixed in recent versions.

Reproduction Setup

With the debug MCP server from the gist, and Claude Code version 2.0.37, I tested by having Claude call the test_mixed_params tool through the MCP server. The server logs to a file showing exactly what arguments it receives.

Test 1: With both required and optional parameters

Request: Call test_mixed_params with content='test log' and parent='parent123'

Server logs:

[13:48:35] Received: tools/call
[13:48:35] Tool: test_mixed_params
[13:48:35] Arguments received: {"content": "test log", "parent": "parent123"}
[13:48:35] Arguments empty: False

Result: ✅ Success - Both parameters received correctly

Test 2: With only the required parameter

Request: Call test_mixed_params with only content='only required test'

Server logs:

[13:49:14] Received: tools/call
[13:49:14] Tool: test_mixed_params
[13:49:14] Arguments received: {"content": "only required test"}
[13:49:14] Arguments empty: False

Result: ✅ Success - Required parameter received correctly

Conclusion

The bug reported in version 1.0.69 where parameters weren't passed when using the {"type": ["string", "null"], "default": null} pattern appears to be fixed in version 2.0.37.

@tennox Can you update to the latest version and confirm if this is still an issue for you?

tennox · 11 months ago

Confirmed! Just tested on my end with v2.0.37 and can verify the fix is working.

Caveat

this issue is marked as macos-specific - I'm on linux.

Details of my test

I created a dedicated test MCP server with the exact problematic schema pattern and tested all edge cases:

Test tool schema (the pattern that was broken):

{
  "type": ["string", "null"],
  "default": null,
  "required": ["message"]
}

Test results:

  • ✅ String value: {"message":"hello world"} - received correctly
  • ✅ Null value: {"message":null} - received correctly
  • ✅ Default (no param): {"message":null} - received correctly

All tested via:

claude --permission-mode bypassPermissions -p 'Call mcp__test-repro__test_tool_union_type with message="hello world"'

Server logs confirmed parameters are being passed properly - no empty {} objects. The union type + null default + required field combination now works as expected.

Thanks for fixing this! 🎉

domdomegg · 11 months ago

Great! I'm going to close this issue, but do please open a new issue if you do notice any bad MCP behavior in future. Thanks again for reporting this and glad it's fixed.

github-actions[bot] · 10 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.