Skip to content

MCP tool hooks_route_enhanced returns 'spawnSync /bin/sh ETIMEDOUT' while CLI 'ruvector hooks route-enhanced' runs in <200ms #422

@ronmikailov

Description

@ronmikailov

Summary

The mcp__ruvector__hooks_route_enhanced MCP tool always returns {"success": false, "error": "spawnSync /bin/sh ETIMEDOUT"} for any input. The equivalent CLI subcommand ruvector hooks route-enhanced "<task>" succeeds in ~182ms, so the regression is inside the MCP server's shell-out path, not the underlying routing code.

Environment

  • ruvector version: 0.2.25 (latest on npm at time of report)
  • Node: v20.19.6
  • OS: Linux 6.6.87.2-microsoft-standard-WSL2 (Ubuntu, WSL2)
  • MCP client: Claude Code (claude-flow integration)
  • Server config: .mcp.jsonruvector mcp start (default, no env overrides)

Reproduction

  1. Start the ruvector MCP server (ruvector mcp start) and connect from any MCP client.
  2. Call the hooks_route_enhanced tool with any task:
    { "task": "test routing" }
  3. Observe response.

Actual

{
  "success": false,
  "error": "spawnSync /bin/sh ETIMEDOUT"
}

The error is reproducible on every call, including immediately after server start (so it is not a warm-up / first-call issue).

Expected

A routing decision similar to what the CLI returns:

$ time ruvector hooks route-enhanced "test routing"
{"success":true,"agent":"coder","confidence":0.5,"reason":"default mapping","signals":[],"coverageWeight":null,"complexity":null}

real    0m0.182s

Comparison: same input through CLI vs MCP

Path Result Time
ruvector hooks route-enhanced "test" (CLI) success, returns routing JSON ~180ms
mcp__ruvector__hooks_route_enhanced { "task": "test" } (MCP) spawnSync /bin/sh ETIMEDOUT ~immediate fail

mcp__ruvector__hooks_diff_analyze, mcp__ruvector__hooks_trajectory_step and other ruvector MCP tools all work in the same MCP server session, so the MCP transport itself is fine — the issue is specific to hooks_route_enhanced.

Likely cause

Looks like the MCP handler for hooks_route_enhanced is shelling out via child_process.spawnSync('/bin/sh', ...) with a timeout that is set too low (or set to 0 and rounded), so the child process is killed before it can boot. The other ruvector MCP hooks that work (diff_analyze, etc.) appear to call the underlying logic in-process, which would explain why only this one fails.

If the in-process path exists, switching hooks_route_enhanced to use it (the same code path the CLI command exercises) should fix it. If a shell-out is genuinely required, raising/removing the spawnSync timeout would unblock it.

Impact

In Claude Code, this hook is wired into the PreToolUse: Task hook chain (see .claude/settings.json from claude-flow's defaults) for enhanced agent routing. Because the MCP call always errors, this routing tier is silently disabled. The fallback mcp__claude-flow__hooks_route still works, so Task spawns are still routed — just without ruvector's AST/coverage/diff signals.

Workaround

Replace the MCP-tool hook with a command hook that calls the CLI directly:

{
  "type": "command",
  "command": "ruvector hooks route-enhanced \"\${tool_input.description}\" 2>/dev/null || true",
  "timeout": 2000
}

This bypasses the broken MCP handler and uses the working CLI path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions