Files
vocero-client/debug-mcp-tool-not-called.md
T
2026-08-26 17:42:00 -04:00

6.0 KiB

Debug Session: mcp-tool-not-called

Status: [OPEN]

Symptom

  • The voice assistant says it will call an MCP tool, but no MCP tool call is observed.
  • No useful runtime log or call attempt is visible from the current instrumentation.

Expected

  • When the model decides to use an MCP tool, the client should emit a tool-call event, execute the MCP proxy request, and produce visible debug evidence for each stage.

Hypotheses

  1. The realtime model is not actually emitting response.function_call_arguments.done, so the spoken promise to use a tool is plain text, not a real function call.
  2. The MCP tools are not present in the effective session state at the moment of the request, so the model cannot legally call them.
  3. The session instructions are updated too late or with the wrong content, so the model receives guidance text but not usable tool declarations.
  4. The browser receives a tool-call event, but the handler path fails before logging or before execRemoteMcpTool() starts.
  5. The MCP proxy request starts, but the current logs do not surface pre-call or failure details, making the attempt invisible.

Evidence Plan

  • Instrument session bootstrap, tool declaration updates, transcript-based MCP ranking, tool-call event handling, and MCP proxy fetch lifecycle.
  • Reproduce with a prompt that should match one MCP tool by description.
  • Compare whether the model emits only assistant transcript text or a real tool-call event.

Notes

  • First code change in this session must remain instrumentation only.

Evidence Summary

  • api/config loads correctly with searchMcpEnabled=true, agentToolCount=16, and a non-empty primary prompt.
  • Transcript-time MCP ranking is active and produces ranked candidates such as get_api_info, get_report_detail, and get_public_day_report for relevant spoken requests.
  • No response.function_call_arguments.done event was recorded in the current reproduction.
  • No toolcall event, no runTool() start, and no MCP proxy fetch were recorded in the current reproduction.

Hypothesis Status

ID Hypothesis Status Evidence
A The model speaks about tool use but does not emit a real function call CONFIRMED The log file contains transcript/ranking events only; no function_call_arguments.done entry was produced in the reproduced turn.
B MCP tools are missing from runtime state PARTIAL api/config proves the remote profile exposes 16 tools, but the current run lacks direct evidence from live session.update.
C MCP guidance reaches the session too late for the same voice turn LIKELY Ranking is computed from the live user transcript; current code only pushes updated instructions on the final transcript, which can miss the active turn.
D The browser gets the toolcall event but fails before execution REJECTED (current run) There is no toolcall event at all in the current reproduction.
E The MCP proxy request starts but is invisible REJECTED (current run) No pre-fetch or post-fetch MCP proxy log was emitted.

Minimal Fix

  • Push the computed MCP-guidance instructions to the live session as soon as ranked tool suggestions appear on partial user transcripts, instead of waiting only for the final transcript.
  • Track the last live instruction snapshot to avoid redundant session.update spam.
  • Add client-construction instrumentation so the next run proves which tools/instructions are present at session start.

Post-Fix Evidence

  • The live session is created with 17 tools and non-empty instructions.
  • During matching turns, the client now narrows the tool set down to the strongest MCP candidates and sends tool_choice="required".
  • Example evidence from the latest run:
    • get_api_info is selected as the top candidate with strong score (29).
    • The client sends setTools(..., "required") with ["get_api_info", ...].
    • The client sends updated instructions immediately after.
  • Even with tool_choice="required" and a narrowed tool list, no response.function_call_arguments.done event is emitted.
  • Therefore no browser toolcall, no runTool(), and no MCP proxy request can happen.

Updated Hypothesis Status

ID Hypothesis Status Evidence
A The model speaks about tool use but does not emit a real function call CONFIRMED Even after forcing tool_choice="required" and narrowing the tool list, no function_call_arguments.done event appears.
B MCP tools are missing from runtime state REJECTED The client sends 17 initial tools and later sends narrowed MCP-only tool lists, including tool_choice="required".
C MCP guidance reaches the session too late for the same voice turn REJECTED The client now pushes guidance and tool policy during partial transcripts, before the turn finishes.
D The browser gets the toolcall event but fails before execution REJECTED No upstream function-call event is emitted at all.
E The MCP proxy request starts but is invisible REJECTED The MCP proxy is never reached because the model never initiates a tool call.

Current Root Cause

  • The speech-to-speech realtime model path in the current backend stack is not performing actual function calling for these MCP tools in this conversation flow, even when tools are declared and tool_choice="required" is sent.
  • The spoken assistant text is therefore behaving like a promise in natural language, not a real tool invocation.

Backend Branch B

  • Added relay-side instrumentation in demo/server.py to report:
  • Outbound client text events forwarded to upstream, including session.update summaries with toolCount, toolNames, toolChoice, and instruction length.
  • Inbound upstream text events forwarded back to the client, including session.updated, response.function_call_arguments.done, and error summaries when present.
  • Binary frame forwarding in both directions and client disconnects.
  • No new runtime evidence has been collected from this instrumentation yet; a fresh reproduction is required with the patched relay active.