[BUG] MCP Server Integration: protocolVersion validation error with stdio servers
Environment
- Platform (select one):
- [x] Anthropic API
- [ ] AWS Bedrock
- [ ] Google Vertex AI
- [ ] Other: <!-- specify -->
- Claude CLI version: 0.2.69 (Claude Code)
- Operating System: Linux
- Terminal: Bash
Bug Description
When connecting Claude CLI to our MCP server using the direct stdio approach, we consistently encounter a validation error for the protocolVersion field despite it being correctly specified in the .mcp.json configuration file. The error occurs before any communication is sent to our server, suggesting an internal validation issue within Claude CLI.
Error message:
[
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [ "protocolVersion" ],
"message": "Required"
}
]
Steps to Reproduce
- Create a .mcp.json file in your project with proper protocolVersion specified:
{
"mcpServers": {
"example-mcp-server": {
"type": "stdio",
"command": "node /path/to/mcp-server.js",
"protocolVersion": "2025-03-26"
}
}
}
- Create an MCP server using the vscode-jsonrpc library that listens for the initialize request
- Register the server with
claude mcp add example-mcp-server "node /path/to/mcp-server.js" - Run
claude --mcp-debug - Observe the validation error about protocolVersion being undefined
Expected Behavior
Claude CLI should read the protocolVersion field from .mcp.json and include it when preparing the initialize request to the MCP server.
Actual Behavior
Claude CLI appears to spawn the MCP server process correctly but fails during internal validation with the error message above. The server log shows no evidence of receiving any requests from Claude CLI, indicating the error occurs before any communication is attempted.
Additional Context
We've conducted extensive testing and confirmed:
- Our server starts correctly and works with test scripts that send properly formatted requests
- Claude CLI correctly loads our configuration (verified with
claude mcp list) - Multiple configuration approaches all result in the same error:
- Using relative paths in the command
- Using full absolute paths to both Node.js and the server script
- Adding environment variables in the configuration
The error persists regardless of configuration approach, suggesting an internal issue with how Claude CLI handles the protocolVersion field when preparing the initialize request.
A detailed technical report with server implementation, test scripts, and full investigation is attached below.
---
Technical Report: Claude CLI MCP Integration Issue
Issue Summary
When attempting to connect Claude CLI to our MCP server (built following the spec) using the direct stdio approach, we consistently encounter the following validation error:
[
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [ "protocolVersion" ],
"message": "Required"
}
]
The error occurs despite having properly configured the protocolVersion field in our project's .mcp.json file. Our investigation confirms this is an internal issue within Claude CLI's validation layer that occurs before any communication is attempted with our MCP server.
Environment Details
OS: Linux
Node.js: v22.12.0 (Path: /home/verlyn13/.nvm/versions/node/v22.12.0/bin/node)
Claude CLI: 0.2.69 (Claude Code)
Project Path: /home/verlyn13/Projects/ScopeTechGtHb/scopecam
MCP Server Script: /home/verlyn13/Projects/ScopeTechGtHb/scopecam/mcp-client/mcp-stdio-server.js
Configurations Tested
1. Standard Configuration
{
"mcpServers": {
"scopecam-mcp-server": {
"type": "stdio",
"command": "node /home/verlyn13/Projects/ScopeTechGtHb/scopecam/mcp-client/mcp-stdio-server.js",
"protocolVersion": "2025-03-26"
}
}
}
2. Full Path Configuration
{
"mcpServers": {
"scopecam-mcp-server": {
"type": "stdio",
"command": "/home/verlyn13/.nvm/versions/node/v22.12.0/bin/node /home/verlyn13/Projects/ScopeTechGtHb/scopecam/mcp-client/mcp-stdio-server.js",
"protocolVersion": "2025-03-26"
}
}
}
3. Environment Variable Configuration
{
"mcpServers": {
"scopecam-mcp-server": {
"type": "stdio",
"command": "node /home/verlyn13/Projects/ScopeTechGtHb/scopecam/mcp-client/mcp-stdio-server.js",
"protocolVersion": "2025-03-26",
"env": {
"MCP_PROTOCOL_VERSION": "2025-03-26"
}
}
}
}
All configurations result in the same validation error.
Detailed Investigation Steps
1. Configuration Verification
We confirmed that Claude CLI is loading our configuration correctly:
$ claude mcp list --verbose
scopecam-mcp-server: node /home/verlyn13/Projects/ScopeTechGtHb/scopecam/mcp-client/mcp-stdio-server.js
2. Server Operability Testing
We developed and ran a test script (test-stdio-server.js) that directly spawns and communicates with our MCP server:
const { spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
const logFilePath = '/tmp/test-stdio-server.log';
fs.writeFileSync(logFilePath, '');
function log(message) {
fs.appendFileSync(logFilePath, `[${new Date().toISOString()}] ${message}\n`);
console.log(message);
}
log('Starting MCP Stdio Server test...');
// The path to the stdio server script
const serverPath = path.join(__dirname, 'mcp-stdio-server.js');
log(`Server script path: ${serverPath}`);
// Spawn the server process
const serverProcess = spawn('node', [serverPath], {
stdio: ['pipe', 'pipe', 'pipe']
});
log(`Server process spawned with PID: ${serverProcess.pid}`);
// Handle server process events
serverProcess.on('error', (err) => {
log(`Failed to start server process: ${err.message}`);
});
serverProcess.stderr.on('data', (data) => {
log(`Server STDERR: ${data.toString()}`);
});
serverProcess.stdout.on('data', (data) => {
log(`Server STDOUT: ${data.toString()}`);
});
// Send an initialize request
const initializeRequest = {
jsonrpc: '2.0',
id: 1,
method: 'initialize',
params: {
processId: process.pid,
clientInfo: {
name: 'test-client',
version: '1.0.0'
},
capabilities: {},
protocolVersion: '2025-03-26'
}
};
log('Sending initialize request...');
serverProcess.stdin.write(JSON.stringify(initializeRequest) + '\r\n');
// Clean up after 5 seconds
setTimeout(() => {
log('Test complete. Checking server log...');
try {
const serverLog = fs.readFileSync('/tmp/mcp-stdio-server.log', 'utf8');
log('---- Server Log Begin ----');
log(serverLog);
log('---- Server Log End ----');
} catch (err) {
log(`Error reading server log: ${err.message}`);
}
log('Terminating server process...');
serverProcess.kill();
process.exit(0);
}, 5000);
Test results confirmed:
- Our server launches correctly
- The server process is accessible
- The server initializes properly
- However, the server log shows no evidence of receiving communication from Claude CLI
3. Server Implementation Review
Our server implements the expected MCP protocol with proper handling of the initialize request:
const rpc = require('vscode-jsonrpc/node');
const fs = require('fs');
const path = require('path');
const logFilePath = '/tmp/mcp-stdio-server.log';
// Clear log file on start for cleaner debugging during development
fs.writeFileSync(logFilePath, '');
function log(message) {
fs.appendFileSync(logFilePath, `[${new Date().toISOString()}] ${message}\n`);
}
log('MCP Stdio Server Process Started.');
log(`Node version: ${process.version}`);
log(`Arguments: ${process.argv.join(' ')}`);
log(`CWD: ${process.cwd()}`);
// REQUIRED_PROTOCOL_VERSION should match what the server implementation actually supports
const REQUIRED_PROTOCOL_VERSION = "2025-03-26";
// Create a JSON-RPC connection piping stdin/stdout of this process
const connection = rpc.createMessageConnection(
new rpc.StreamMessageReader(process.stdin),
new rpc.StreamMessageWriter(process.stdout)
);
// --- Initialization Handler ---
connection.onRequest('initialize', (params) => {
log(`Received initialize request. Client capabilities: ${JSON.stringify(params.capabilities)}`);
log(`Client requested protocolVersion: ${params.protocolVersion}`);
if (params.protocolVersion !== REQUIRED_PROTOCOL_VERSION) {
log(`ERROR: Client protocolVersion (${params.protocolVersion}) does not match required version (${REQUIRED_PROTOCOL_VERSION})`);
// Throwing an error here sends a proper JSON-RPC error response
throw new rpc.ResponseError(
rpc.ErrorCodes.InvalidParams, // Or a more specific code if available/custom
`Unsupported protocolVersion: Client sent ${params.protocolVersion}, server requires ${REQUIRED_PROTOCOL_VERSION}`,
{ requiredVersion: REQUIRED_PROTOCOL_VERSION }
);
}
log(`Protocol version matched (${REQUIRED_PROTOCOL_VERSION}). Sending capabilities.`);
// Respond with server capabilities
return {
capabilities: {
// List actual server capabilities here
},
serverInfo: {
name: 'ScopeCam MCP Server (Stdio)',
version: '1.0.0'
},
protocolVersion: REQUIRED_PROTOCOL_VERSION // Explicitly confirm the negotiated version
};
});
// --- Shutdown Handler ---
connection.onRequest('shutdown', () => {
log('Received shutdown request.');
// Perform any cleanup needed before exiting
return null; // Successful shutdown response
});
// --- Exit Handler ---
connection.onNotification('exit', () => {
log('Received exit notification. Exiting process.');
// Exit the process cleanly
process.exit(0);
});
// --- Example MCP method ---
connection.onRequest('mcp/getServerStatus', (params) => {
log(`Received mcp/getServerStatus request with params: ${JSON.stringify(params)}`);
// Implement the actual logic for this method
return { status: 'running', pid: process.pid, version: REQUIRED_PROTOCOL_VERSION };
});
// --- Error Handling ---
connection.onError((error) => {
log(`Connection Error: ${error.message}\n${error.stack}`);
});
connection.onClose(() => {
log('Connection closed.');
});
// --- Start Listening ---
connection.listen();
log(`MCP Stdio Server listening on stdin/stdout for protocol ${REQUIRED_PROTOCOL_VERSION}...`);
// Handle unexpected exit
process.on('exit', (code) => {
log(`Process exiting with code: ${code}`);
});
process.on('uncaughtException', (err) => {
log(`UNCAUGHT EXCEPTION: ${err.message}\n${err.stack}`);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
log(`UNHANDLED REJECTION: ${reason}`);
});
4. Minimal Test Case
We created a minimal test server outside our project to isolate the issue:
// /tmp/mcp-test/test-server.js
const fs = require('fs');
fs.writeFileSync('/tmp/mcp_test_server.log', `Started at ${new Date()}\nArgs: ${process.argv.join(' ')}\n`);
// Keep process running
process.stdin.on('data', (data) => {
fs.appendFileSync('/tmp/mcp_test_server.log', `Received data: ${data.toString()}\n`);
});
// Log process start
console.log('Server started');
// Handle process signals
process.on('exit', () => {
fs.appendFileSync('/tmp/mcp_test_server.log', `Process exited at ${new Date()}\n`);
});
With minimal configuration:
// /tmp/mcp-test/.mcp.json
{
"mcpServers": {
"test-mcp": {
"type": "stdio",
"command": "node /tmp/mcp-test/test-server.js",
"protocolVersion": "2025-03-26"
}
}
}
The minimal test case reproduced the same issue, confirming it's not specific to our project setup.
5. Error Analysis
The error message format strongly indicates it originates from a validation layer within Claude CLI:
[
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": [ "protocolVersion" ],
"message": "Required"
}
]
This suggests:
- The validation is performed by a schema validation library (likely Zod or similar)
- The validation occurs on a request object that should contain
protocolVersion - Claude CLI is not correctly including the
protocolVersionfrom the.mcp.jsonconfiguration
6. Server Logs
After attempting to run claude --mcp-debug, the MCP server log shows:
[2025-04-11T23:23:43.696Z] MCP Stdio Server Process Started.
[2025-04-11T23:23:43.696Z] Node version: v22.12.0
[2025-04-11T23:23:43.697Z] Arguments: /home/verlyn13/.nvm/versions/node/v22.12.0/bin/node /home/verlyn13/Projects/ScopeTechGtHb/scopecam/mcp-client/mcp-stdio-server.js
[2025-04-11T23:23:43.697Z] CWD: /home/verlyn13/Projects/ScopeTechGtHb/scopecam/mcp-client
[2025-04-11T23:23:43.701Z] MCP Stdio Server listening on stdin/stdout for protocol 2025-03-26...
Critically, there are no log entries showing reception of any requests from Claude CLI, confirming the failure occurs before any communication is attempted.
Previous Working Solution
We previously had a working solution using a wrapper script approach that bypassed this issue:
# claude-protocol-fixed.sh
#!/bin/bash
export MCP_PROTOCOL_VERSION=2025-03-26
export DEBUG=true
# Log start
echo "[$(date -Iseconds)] Starting MCP wrapper script" > /tmp/claude-protocol-wrapper.log
echo "[$(date -Iseconds)] Environment: MCP_PROTOCOL_VERSION=$MCP_PROTOCOL_VERSION" >> /tmp/claude-protocol-wrapper.log
# Execute the MCP server script
exec node /home/verlyn13/Projects/ScopeTechGtHb/scopecam/mcp-client/mcp-stdio-server.js
Registered with:
claude mcp add scopecam-mcp-server "/home/verlyn13/Projects/ScopeTechGtHb/scopecam/mcp-client/claude-protocol-fixed.sh"
This approach worked but doesn't leverage the intended direct stdio integration method.
Detailed Error Timeline
- Initial Test: Standard
.mcp.jsonwith relativenodepath
- Error:
protocolVersionvalidation failure
- Full Path Test:
.mcp.jsonwith absolute paths to bothnodeand the server script
- Error: Same
protocolVersionvalidation failure
- Temporary ENOENT Error: During configuration changes, we briefly saw:
````
MCP server "scopecam-mcp-server" Connection failed: spawn systemctl --user restart scopecam-mcp.service ENOENT
- This was likely due to a temporary path configuration issue that was resolved
- Latest Tests: All configuration variants result in the same
protocolVersionvalidation error
Technical Analysis
The evidence points to a specific issue in Claude CLI's internal processing:
- Configuration Loading: Claude CLI correctly loads our
.mcp.jsonconfiguration, as verified byclaude mcp list
- Process Spawning: Claude CLI successfully spawns our server process (verified by server startup logs)
- Initialization Request Preparation: When Claude CLI internally constructs the
initializerequest, it fails to include theprotocolVersionfrom the configuration as a parameter, resulting in a validation error
- Validation Failure: The internal validation layer checks the request before sending it and finds
protocolVersionisundefinedwhen it should be a string
- Connection Termination: Due to this validation failure, no request is ever sent to our server
Root Cause Hypothesis
Claude CLI appears to be:
- Loading our configuration correctly
- Spawning our process correctly
- But failing to include the
protocolVersionfield from the configuration when preparing theinitializerequest parameters - This triggers internal validation failure before any communication is attempted
This is consistent with the error message format and the lack of any communication in our server logs.
Comparison with Other Tools
It's worth noting that other tools using the same MCP protocol don't experience this issue:
- Our test script successfully communicates with the server using the same protocol
- The wrapper script approach works despite using the same server implementation
- This suggests the issue is specific to Claude CLI's handling of the
stdioserver configuration
Additional Testing Options
We've attempted various additional tests:
- Different Protocol Versions: We tried variations like
2025-03,2025-03-26, and2025-03-26-0with the same result
- Environment Variables: We added
envsection to the configuration with explicitprotocolVersionvariables
- Alternative Configuration Formats: We tested different ways of specifying the command (with and without full paths)
All tests resulted in the same validation error.
Impact and Workarounds
The issue prevents us from using the direct stdio integration method with Claude CLI, forcing us to use less ideal workarounds:
- Wrapper Script: Continue using our wrapper script approach (working but not ideal)
- Alternative MCP Types: Potentially explore different server types (WebSocket, etc.)
Neither solution leverages the intended direct stdio integration.
Recommendations for Anthropic
- Investigate Internal Validation: Review how Claude CLI prepares the
initializerequest parameters, especially how it incorporates theprotocolVersionfrom.mcp.json
- Add Debugging Option: Consider adding an option to Claude CLI that outputs the actual request it's trying to send, which would help diagnose issues like this
- Review Error Handling: The current error message is not very user-friendly; consider providing more context about where the validation is failing
- Documentation Update: Provide more explicit documentation about the expected structure of
.mcp.jsonand how fields are used in the protocol
Questions for Anthropic Support
- Am I missing something obvious here? Is this a known issue with Claude CLI's handling of the
protocolVersionfield forstdioservers?
- Are there any specific configuration requirements or formats for the
protocolVersionfield that aren't documented on the main documentation site?
- Can you provide any additional debugging options or logs that would help diagnose this issue?
- Is there a newer version of Claude CLI that might address this issue? (I've kept the client updated each time an update is available.)
- Are there any environment variables or global configuration options that might affect how Claude CLI handles the
protocolVersionfield?
Conclusion
The issue appears to be a bug in Claude CLI's internal handling of the protocolVersion field when preparing the initialize request for stdio type MCP servers. Despite correct configuration in .mcp.json, the field is not properly included in the request parameters, causing internal validation to fail.
I've tried multiple configuration approaches and workarounds, without success with an initial connection upon launch of claude-code. I have been able to get it to work with workarounds. I believe this requires investigation and resolution by Anthropic's development team.
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗