-
-
Notifications
You must be signed in to change notification settings - Fork 199
Open
Labels
Description
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: truecapabilities.resourcesandcapabilities.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}andcapabilities: {tools: {}}— tools loaded ✅ - XcodeBuildMCP proxy stripping only tool-level fields — still dropped ❌
- Proxy also normalizing the
initializeresponse (removinginstructions, 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
instructionsopt-in via config (e.g.enableInstructions: falsein.xcodebuildmcp/config.yaml) - Strip
instructionsfrom initialize when the client doesn't advertise support - Make
annotationsandexecutionoptional per MCP spec — only include them if the client negotiates support duringinitialize
Related
- Claude Code issue: [BUG] MCP client silently drops all tools when third-party server includes outputSchema in tools/list response anthropics/claude-code#25081
- Issue MCP server fails to connect in Claude Code despite working correctly from CLI #210 in this repo (connection failures — may be same root cause)
Environment
- XcodeBuildMCP: 2.0.7
- @modelcontextprotocol/sdk: 1.26.0
- Claude Code: 2.1.39
- macOS: Darwin 24.6.0 (Apple Silicon)
Reactions are currently unavailable