Skip to content

[Bug]: OpenCode 2: a thread's first turn doesn't see T3 Code's MCP tools (prompt is sent before OpenCode registers them) #16141

Description

@nkoynov

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

Needs the long-name fix (#16142), because without it OpenCode 2 never registers T3's tools at all (#16140).

  1. OpenCode 2.0.22 provider instance (T3-spawned), no OpenCode plugins, model opencode/big-pickle.
  2. New thread, prompt: "Call the execute tool exactly once with this code and reply with its raw output: return { a: search({ query: "orchestrator_capabilities", limit: 5 }).items.map((i) => i.path) }".
  3. Send the same prompt again as the second turn.

Expected behavior

The first turn sees tools["t3-code-…"].orchestrator_capabilities, like every later turn.

Actual behavior

On the first turn the search comes back empty ({"a":[]}) in 5 of 5 new threads. The second turn on the same thread lists the T3 tools.

OpenCode2AdapterV2.ts prepareTurn calls client.mcp.add and then sends session.prompt right away. OpenCode resolves mcp.add before the session's tool registry has the new server's tools: it reloads the registry from a mcp.tools.changed event debounced by 100 ms (packages/core/src/tool/mcp.ts), and mcpTools.flush only waits for the initial registration. So the first step's catalog is taken without T3's tools.

  • Code Mode models: they recover only if they search again on a later step. A delegated big-pickle child's first search was empty at 15:42:20.268 and the second, 4.4 s later, found the tools.
  • cursor-opencode-provider: it fixes the tool list for the whole turn, so the turn never gets them. cursor/claude-opus-5-5-1m, turn 1: "NO_T3_TOOLS"; turn 2 called t3-code-6fb4b99c8f0e4cda_t3_thread_configuration and got its own thread id.

A delegated OpenCode child has only one turn, so it depends on that retry.

Impact

Major degradation or frequent failure

Version or commit

main @ e22c880 plus the MCP server-name fix (#16142)

Environment

Linux x64 (NixOS VM), Node 24.21, OpenCode 2.0.22 spawned by T3; opencode/big-pickle (no plugins) and cursor/claude-opus-5-5-1m via cursor-opencode-provider 0.8.0

Logs or stack traces

# 5 new threads, first turn, same probe
thread:project:529ff43e-…:fd4e134e-…  -> {"a":[],"b":[]}
thread:project:23d3e3e9-…:eeec7768-…  -> {"a":[],"b":[]}
thread:project:c2d091bb-…:e847473a-…  -> {"a":[],"b":[]}
thread:project:6105ed7b-…:a60e2d20-…  -> {"a":[],"b":[]}
thread:project:8d931078-…:3852ed03-…  -> {"a":[],"b":[]}
# thread:project:3ada6bbb-…:625a2118-…, turn 2
{"a":["tools[\"t3-code-5f396b4d3be75e9c\"].orchestrator_capabilities", …], "b":["tools[\"t3-code-5f396b4d3be75e9c\"].t3_thread_configuration", …]}

Workaround

Send a throwaway first turn. A local OpenCode plugin can also hold the first prompt (session.hook("prompt")) until the server's tools are registered. In our runs that took 103 ms on a new thread.

This is the OpenCode counterpart of #13437 (Codex, accepted), and the triage on #15736 tracks this per provider. The root cause is on the OpenCode side: anomalyco/opencode#51089 ("mcp.add resolves before the session tool registry has the new server's tools"), with fix PR anomalyco/opencode#52214, open and unreviewed. If that lands, T3 needs no change beyond requiring the fixed OpenCode version. Otherwise T3 would need a bounded wait after a fresh mcp.add, only on the turn that added the server, and it must stay interruptible by Stop. Stop during the wait is what sank the Codex attempts on #13437.

Model: Claude Opus 5.5 (1M). Harness: Claude Code in T3 Code.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions