Repository navigation
Description
The OpenCode 2 adapter adds the thread's MCP server (t3-code-<id>) once, on the first turn after it loads the thread, and remembers that in state.mcp (prepareTurn in OpenCode2AdapterV2.ts). It only forgets it when the OpenCode server reconnects.
OpenCode 2 keeps MCP servers added at runtime (PUT /api/experimental/mcp/:server) in the project Location's in-memory state, and evicts a Location after 60 minutes without activity (packages/core/src/location-activity.ts). The eviction drops the server. T3's next turn on that thread, whether a user message, a scheduled task or a PR-watch wake, only sends POST /session/:id/prompt, so the thread runs without T3's tools and nothing tells the model or the user.
Repro (nightly 20261007.2761, OpenCode 2.0.24):
- Start an OpenCode thread in a project and let it finish a turn that uses a T3 tool.
- Leave that project idle for over an hour, or evict it right away on T3's OpenCode server:
DELETE /api/debug/location?location[directory]=<project>(same teardown as the idle eviction). - Send the thread a message asking it to call a T3 tool, e.g.
list_scheduled_tasks.
Result: OpenCode's GET /api/mcp?location[directory]=<project> listed linear and t3-code-<id> before the eviction and only linear after it and a full turn, and the model had no T3 tools in any later turn. T3's trace shows the PUT only before the first turn; the turns after an eviction send just the prompt:
07:45:39 PUT /api/experimental/mcp/t3-code-ccb57895e89db907?location[directory]=… 204
07:45:39 POST /api/session/ses_…/prompt 200
(Location evicted)
07:46:00 POST /api/session/ses_…/prompt 200
07:46:13 POST /api/session/ses_…/prompt 200
Expected: a thread keeps its T3 tools on every turn. Re-adding the server in prepareTurn when it is missing from the Location (or adding it on every turn; OpenCode leaves an unchanged config connected) would cover eviction, and any other way OpenCode can lose runtime servers.
Threads that wake on schedules or PR watches are idle for hours between runs, so they hit this regularly. We work around it with an OpenCode plugin that remembers T3's server configs per directory and adds them back when the Location boots again.
Related on the OpenCode side: anomalyco/opencode#51343 (idle eviction).
Found and written with Claude Opus 5.5 in T3 Code (OpenCode 2 + cursor-opencode-provider).
Activity
juliusmarminge commentedon Oct 7, 2026
Note
Grok responding on behalf of Julius.
Triage: confirmed bug in the OpenCode 2 adapter (the trigger is upstream).
Root cause (
apps/server/src/orchestration-v2/Adapters/OpenCode2AdapterV2.ts):ThreadState.mcp(L399-402) caches "T3's MCP server as registered for this thread."prepareTurn(L3241) callsclient.mcp.add(PUT /api/experimental/mcp/:server) only whenstate.mcp === undefined(L3264-3285). Once that succeeds,state.mcp = wanted.t3-code-<id>, but the server process keeps running, so no reconnect fires andstate.mcpstays stale. The thread then runs without T3 tools, and nothing warns about it.t3OrchestrationSystemPrompt(state.mcp !== undefined)also keeps telling the model the tools are there.Proposed fix: in
prepareTurn, stop treatingstate.mcpas proof the server is registered. Either:client.mcp.addon every turn. It's idempotent: OpenCode leaves an unchanged config connected. This costs one PUT per turn and also covers any other way OpenCode can lose runtime servers. Or:GET /api/mcp?location[directory]=…and re-add the server whent3-code-<id>is missing.Option 1 is the simplest and most robust. Add a test that removes or evicts the server between turns and checks the PUT is sent again.
Related:
Workaround: