Summary
npx ruvector mcp start fails the MCP handshake in Claude Code (claude mcp list → ✘ Failed to connect) because a console.log writes to stdout, which is the JSON-RPC channel for the MCP stdio transport. One stray line corrupts the initialize handshake.
Version
ruvector 0.2.35 (server reports "2.0")
Root cause
dist/core/onnx/loader.js:199 (source likely src/core/onnx/loader.ts) logs on a disk-cache hit:
console.log(` Disk cache hit: ${modelName}`);
console.log → stdout. Under the MCP stdio transport, stdout must contain only JSON-RPC frames, so this line makes the client's first read non-JSON and the handshake fails.
Evidence
Driving a real MCP initialize over stdin with the streams separated:
- stdout (must be pure JSON-RPC):
Disk cache hit: all-MiniLM-L6-v2 ← the pollution
- stderr (correct):
ParallelIntelligence: N workers ready, Loading ONNX model: all-MiniLM-L6-v2..., ONNX embedder ready: 384d, SIMD: true
So the embedder's other logs are already on stderr — only this cache-hit line leaks to stdout. It appears only once the model is disk-cached (steady state), which makes the failure look intermittent.
ruvector mcp test passes (97 tools registered) and the server is otherwise healthy — the problem is purely stdout hygiene on the stdio transport.
Fix
Send it to stderr, consistent with the rest of the embedder logs (and with ruv-swarm's stdio server — "logs to stderr, not stdout … Critical" — and RuView's "Logs go to stderr ONLY — stdout is the JSON-RPC channel and must stay clean"):
console.error(` Disk cache hit: ${modelName}`);
Or gate loader logging behind a debug flag when running under mcp start.
Impact
ruvector mcp start cannot connect to any stdio MCP host (Claude Code, Inspector) whenever the ONNX model is disk-cached — which is the normal steady state.
Summary
npx ruvector mcp startfails the MCP handshake in Claude Code (claude mcp list→✘ Failed to connect) because aconsole.logwrites to stdout, which is the JSON-RPC channel for the MCP stdio transport. One stray line corrupts theinitializehandshake.Version
ruvector 0.2.35 (server reports "2.0")
Root cause
dist/core/onnx/loader.js:199(source likelysrc/core/onnx/loader.ts) logs on a disk-cache hit:console.log→ stdout. Under the MCP stdio transport, stdout must contain only JSON-RPC frames, so this line makes the client's first read non-JSON and the handshake fails.Evidence
Driving a real MCP
initializeover stdin with the streams separated:Disk cache hit: all-MiniLM-L6-v2← the pollutionParallelIntelligence: N workers ready,Loading ONNX model: all-MiniLM-L6-v2...,ONNX embedder ready: 384d, SIMD: trueSo the embedder's other logs are already on stderr — only this cache-hit line leaks to stdout. It appears only once the model is disk-cached (steady state), which makes the failure look intermittent.
ruvector mcp testpasses (97 tools registered) and the server is otherwise healthy — the problem is purely stdout hygiene on the stdio transport.Fix
Send it to stderr, consistent with the rest of the embedder logs (and with ruv-swarm's stdio server — "logs to stderr, not stdout … Critical" — and RuView's "Logs go to stderr ONLY — stdout is the JSON-RPC channel and must stay clean"):
Or gate loader logging behind a debug flag when running under
mcp start.Impact
ruvector mcp startcannot connect to any stdio MCP host (Claude Code, Inspector) whenever the ONNX model is disk-cached — which is the normal steady state.