Repository navigation
Description
Summary
In Code Mode, an MCP server that is connected and reporting its tools (mcp connected server=utilities tools=5) is intermittently absent from the per-turn Code Mode catalog, so its tools resolve as Unknown tool. Within a single live session the namespace alternates: present on one turn, missing on the next, present again on the one after, with the MCP connection never dropping in between. search({ namespace: "utilities" }) returns items: [] on exactly the turns where the catalog is missing the namespace.
Because the catalog is what the model reads to learn the tool exists, a gateway-style server that is required on every turn becomes invisible roughly half the time. The model is told to use it and then cannot call it.
Environment
- opencode version: 1.18.30 (
/opt/homebrew/bin/opencode) - OS: Darwin 27.0.0 (macOS, arm64)
- Terminal: not a terminal session (driven by a desktop app over the local server API)
- Shell: /bin/zsh
- Install/channel: Homebrew install, latest
- Active plugins: none configured.
~/.config/opencode/opencode.jsonhas nopluginkey, and neither~/.config/opencode/plugin/nor~/.config/opencode/plugins/exists.~/.config/opencode/package.jsoncontains only@opencode-ai/plugin: 1.4.3.
Reproduction
-
Configure a stdio MCP server, in this case an app-owned utility gateway exposing 5 tools (
cio_util_find,cio_util_init,cio_util_use,cio_util_docs_lookup, plus one more), passed to the harness throughOPENCODE_CONFIG_CONTENT. -
Start a session in that directory. The log records the connection:
timestamp=2026-10-01T13:11:18.878Z level=INFO run=ac49a1dd message="mcp connected" server=utilities tools=5 ... connectionID=d54329c0-9457-40e8-a6d4-abc59428d546
-
Turn N: the Code Mode catalog includes
utilities (5 tools, 4 shown)and the call succeeds:tools.utilities.cio_util_find({ query: "worktree" }) -> { "utilities": [ { "id": "cio:scope", ... } ], "notFound": false } -
Turn N+1, same session, no reconnect, no compaction, no config change: the catalog contains only
browserandopencode, and the identical call fails:Error: Unknown tool 'utilities.cio_util_find'. Did you mean tools.browser.find?
-
Inside
execute,search({ namespace: "utilities", limit: 20 })returns{ items: [], remaining: 0, next: null }on the failing turn and 5 items on the succeeding turn. -
Turn N+2:
utilitiesis back in the catalog and calls work again.
Observed over four consecutive turns in one session: absent, present, absent, present. No mcp disconnected, no tools=0, and no gateway call failure appears in the log for this session in that window.
Expected Behavior
Once an MCP server is connected, its namespace and tools should be present in the Code Mode catalog for every subsequent turn of that session. The catalog is rebuilt per turn, so a rebuild should be additive with respect to already-connected servers rather than able to drop them. The error message is also misleading: it suggests a same-prefix tool (tools.browser.find) rather than saying the namespace is not registered.
Actual Behavior
The Code Mode catalog alternates between including and omitting an MCP namespace across consecutive turns of a live session while the underlying connection stays healthy. On the omitting turns:
tools.<server>.<tool>(...)throwsUnknown tool '<server>.<tool>'search({ namespace: "<server>" })returns zero items
Additional Context
Log evidence: every server process had the connection, the catalog still flipped
The caller is an app that configures the gateway MCP through OPENCODE_CONFIG_CONTENT and launches one opencode serve process per turn, so the config is fixed for the lifetime of a process and cannot be rewritten between turns. From the opencode log for the failing window (2026-10-01, project directory /Users/osaitech/Development/in-house/codeinoven):
13:20:18 run=60f36df3 message="mcp connected" server=utilities tools=5
13:21:59 run=b2dc73d6 message="mcp connected" server=utilities tools=5
13:25:01 run=bcd164d4 message="mcp connected" server=utilities tools=5
13:26:27 run=aa9ebdb2 message="mcp connected" server=utilities tools=5Every process that served this directory during the window reported tools=5 for utilities. run=bcd164d4 is the process that served the failing turn: its shell tool calls at 13:26:19 and 13:26:40 carry that run id, and it had connected utilities with all 5 tools at 13:25:01, roughly 80 seconds earlier. Across the same window there is no mcp disconnected, no tools=0, and no gateway call failure for the session:
13:11:15 run=8aaa372a level=ERROR message="Failed to drain Session" cause="Session.StepFailedError: Nothing to compact yet"That is the only error in the window, and it is an unrelated no-op compaction path. There is no compaction of the conversation, no reconnect, and no config change between the turn where the namespace was missing and the turn where it came back. Both turns sit inside the window above, so the flip happened while the connection was healthy and complete.
Limitation: successful MCP tool calls are not written to the log, so the exact process serving the succeeding execute call cannot be pinned from the log alone. What the log does establish is that no process in that window lacked the utilities connection, and none lost it.
- This looks related to the tool-registry staleness family, but the trigger differs from the ones already reported:
- MCP tools disappear after context compaction in long sessions (tool manifest drops to 0, server stays connected) #46190 covers tools vanishing after context compaction. There is no compaction here, and the tools come back on their own.
- mcp: Code Mode tool calls fail with Unknown tool for connected servers (codemode:false works) #51849 covers connected MCP tools failing in every fresh session (
codemode:falseworks). Here the same session succeeds on alternating turns, so the registry is not permanently empty. - The distinguishing signature is the alternation: one session, namespace present and absent turn to turn, with the connection healthy throughout.
- Environment is macOS with no terminal and Code Mode driving a local opencode server. The failing turns come through the harness as plain assistant turns with no user-visible config change, so the trigger is internal to the per-turn catalog rebuild rather than anything the user does.
- Workaround: retry on the next turn, or set
codemode: falsefor the server to expose tools natively.
Activity
github-actions commentedon Oct 1, 2026
This issue doesn’t fully meet our contributing guidelines.
What needs to be fixed:
Please edit this issue to address the above within 72 hours, or it will be automatically closed.
This issue might be a duplicate of existing issues. Please check:
Unknown toolerrors and disappear from search results.If you believe this was flagged incorrectly, please let a maintainer know.
github-actions commentedon Oct 4, 2026
This issue has been automatically closed because it was not updated to meet our contributing guidelines within the 72-hour window.
Feel free to open a new issue that follows our issue templates.