Description
XcodeBuildMCP v2.0.7 tools are completely invisible in Claude Code 2.1.39 despite the server showing as "Connected" in claude mcp list. Zero tools appear — no error, no warning.
This is caused by fields added by @modelcontextprotocol/sdk v1.26.0 that Claude Code's MCP client doesn't handle gracefully.
Affected Fields
In initialize response:
instructions — large documentation string (~1500 chars)
capabilities.tools.listChanged: true
capabilities.resources and capabilities.logging
In tools/list response (per-tool):
execution: { taskSupport: "forbidden" }
annotations: { title: "...", readOnlyHint: true/false }
inputSchema.$schema: "http://json-schema.org/draft-07/schema#"
How We Diagnosed
- Created a minimal canary MCP server with bare
{name, description, inputSchema} and capabilities: {tools: {}} — tools loaded ✅
- XcodeBuildMCP proxy stripping only tool-level fields — still dropped ❌
- Proxy also normalizing the
initialize response (removing instructions, simplifying capabilities) — tools loaded ✅
The instructions field and/or extra capabilities in the initialize response appear to be the primary trigger. Tool-level annotations and execution may also contribute.
Workaround
Node.js proxy that normalizes MCP responses:
#!/usr/bin/env node
const { spawn } = require('child_process');
const proc = spawn('xcodebuildmcp', ['mcp'], {
stdio: ['pipe', 'pipe', process.stderr],
cwd: process.env.XCODEBUILDMCP_CWD || process.cwd(),
});
let buffer = '';
proc.stdout.on('data', (data) => {
buffer += data.toString();
const lines = buffer.split('\n');
buffer = lines.pop();
for (const line of lines) {
if (!line.trim()) { process.stdout.write('\n'); continue; }
try {
const msg = JSON.parse(line);
// Clean initialize response
if (msg.result && msg.result.protocolVersion) {
delete msg.result.instructions;
if (msg.result.capabilities) {
msg.result.capabilities = { tools: {} };
}
}
// Clean tools/list response
if (msg.result && msg.result.tools && Array.isArray(msg.result.tools)) {
msg.result.tools = msg.result.tools.map(tool => {
const { execution, annotations, ...rest } = tool;
if (rest.inputSchema) delete rest.inputSchema['$schema'];
return rest;
});
}
process.stdout.write(JSON.stringify(msg) + '\n');
} catch (e) {
process.stdout.write(line + '\n');
}
}
});
process.stdin.pipe(proc.stdin);
proc.on('exit', (code) => process.exit(code || 0));
process.on('SIGTERM', () => proc.kill('SIGTERM'));
process.on('SIGINT', () => proc.kill('SIGINT'));
Save as a proxy script, then in .mcp.json:
{
"XcodeBuildMCP": {
"type": "stdio",
"command": "node",
"args": ["/path/to/xcodebuildmcp-proxy.js"],
"env": { "XCODEBUILDMCP_CWD": "/path/to/your/project" }
}
}
Suggested Fix
Consider one or more of:
- Make
instructions opt-in via config (e.g. enableInstructions: false in .xcodebuildmcp/config.yaml)
- Strip
instructions from initialize when the client doesn't advertise support
- Make
annotations and execution optional per MCP spec — only include them if the client negotiates support during initialize
Related
Environment
- XcodeBuildMCP: 2.0.7
- @modelcontextprotocol/sdk: 1.26.0
- Claude Code: 2.1.39
- macOS: Darwin 24.6.0 (Apple Silicon)
Description
XcodeBuildMCP v2.0.7 tools are completely invisible in Claude Code 2.1.39 despite the server showing as "Connected" in
claude mcp list. Zero tools appear — no error, no warning.This is caused by fields added by @modelcontextprotocol/sdk v1.26.0 that Claude Code's MCP client doesn't handle gracefully.
Affected Fields
In
initializeresponse:instructions— large documentation string (~1500 chars)capabilities.tools.listChanged: truecapabilities.resourcesandcapabilities.loggingIn
tools/listresponse (per-tool):execution: { taskSupport: "forbidden" }annotations: { title: "...", readOnlyHint: true/false }inputSchema.$schema: "http://json-schema.org/draft-07/schema#"How We Diagnosed
{name, description, inputSchema}andcapabilities: {tools: {}}— tools loaded ✅initializeresponse (removinginstructions, simplifying capabilities) — tools loaded ✅The
instructionsfield and/or extra capabilities in theinitializeresponse appear to be the primary trigger. Tool-levelannotationsandexecutionmay also contribute.Workaround
Node.js proxy that normalizes MCP responses:
Save as a proxy script, then in
.mcp.json:{ "XcodeBuildMCP": { "type": "stdio", "command": "node", "args": ["/path/to/xcodebuildmcp-proxy.js"], "env": { "XCODEBUILDMCP_CWD": "/path/to/your/project" } } }Suggested Fix
Consider one or more of:
instructionsopt-in via config (e.g.enableInstructions: falsein.xcodebuildmcp/config.yaml)instructionsfrom initialize when the client doesn't advertise supportannotationsandexecutionoptional per MCP spec — only include them if the client negotiates support duringinitializeRelated
Environment