Repository navigation
Description
Feature hasn't been suggested before.
- I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
OpenCode MCP Tool Resolution Causes Large First-Turn and Per-Turn Overhead
Summary
We are embedding OpenCode as a long-lived local runtime inside another desktop app.
We found that session.create is not the main source of latency.
The main overhead comes from MCP tool resolution during session.prompt.
In current upstream behavior:
- On the first prompt for a workspace, MCP initialization connects every enabled MCP server.
- During MCP client creation, OpenCode immediately calls
listTools(). - On later prompts, OpenCode still calls
listTools()again for every connected MCP client insideMCP.tools().
This creates noticeable first-turn latency and also adds repeated per-turn latency when many MCP servers are enabled or when some remote MCP servers are slow.
Code Paths
session.create is not the MCP loading point
session.create only creates the session record:
packages/opencode/src/server/routes/session.ts:193packages/opencode/src/server/routes/session.ts:209packages/opencode/src/session/index.ts:219
MCP tool resolution happens during prompt
Prompt handling enters SessionPrompt.prompt(...) and resolves tools:
packages/opencode/src/server/routes/session.ts:786packages/opencode/src/server/routes/session.ts:817packages/opencode/src/session/prompt.ts:746packages/opencode/src/session/prompt.ts:840
At packages/opencode/src/session/prompt.ts:840, resolveTools() calls:
await MCP.tools()
First-use MCP initialization
MCP state is created through Instance.state(...):
packages/opencode/src/mcp/index.ts:182packages/opencode/src/mcp/index.ts:189
During first initialization, enabled MCP servers are created through:
packages/opencode/src/mcp/index.ts:325
For each server, OpenCode connects the client:
- remote connect:
packages/opencode/src/mcp/index.ts:387 - local connect:
packages/opencode/src/mcp/index.ts:472
After connection, OpenCode immediately calls:
packages/opencode/src/mcp/index.ts:506
This is:
await withTimeout(mcpClient.listTools(), ...)
So the first prompt pays:
- connect cost
- initial
listTools()cost
Per-prompt repeated listTools()
Even after clients are already connected, MCP.tools() still does:
packages/opencode/src/mcp/index.ts:606packages/opencode/src/mcp/index.ts:618packages/opencode/src/mcp/index.ts:620
This means every prompt can re-run client.listTools() for every connected MCP client.
Why This Is Expensive
For applications that:
- keep OpenCode as a long-lived runtime,
- enable multiple MCP servers,
- or use slow remote MCP servers,
the current model has two costs:
- First prompt latency:
- connect all enabled MCP servers
- list tools for all enabled MCP servers
- Ongoing prompt latency:
- re-list tools on every prompt
In our case, the user-visible symptom is:
- session creation appears fast enough
- the first real prompt is slow
- later prompts may still pay avoidable MCP enumeration overhead
Important Context
This is especially noticeable for desktop integrations where:
- the OpenCode sidecar is started once and kept alive,
- workspace/runtime state is expected to stay warm,
- session lifecycle should not imply MCP re-enumeration work.
Suggested Improvements
Option 1: Cache MCP tool lists inside OpenCode
Cache tool definitions per MCP client after the initial successful listTools(), and reuse them in MCP.tools() until invalidated.
Possible invalidation triggers:
- explicit reconnect
- explicit add/remove/disconnect
ToolListChangedNotificationSchema
This would preserve correctness while avoiding repeated listTools() calls on every prompt.
Option 2: Separate "connected client cache" from "tool schema refresh"
Allow MCP.tools() to use a cached schema by default, and refresh only:
- when explicitly requested,
- when the MCP server notifies tool list changes,
- or when a TTL expires.
Option 3: Expose prompt-time control
Expose a config flag to choose between:
- always refresh tools on prompt
- use cached tools with invalidation
This would help embedded desktop products that optimize for stable long-lived runtimes.
Expected Benefit
If MCP.tools() stops calling listTools() for every prompt, OpenCode should:
- reduce first-turn latency after initial warmup,
- reduce repeated per-turn latency,
- work better as an embedded long-lived desktop runtime.
Activity
github-actions commentedon Mar 26, 2026
This issue doesn't fully meet our contributing guidelines.
What needs to be fixed:
Please edit this issue to address the above within 2 hours, or it will be automatically closed.
This issue might be a duplicate of existing issues. Please check:
listTools()being called on every prompt with no caching, and proposes similar solutions (cached tool listings, lazy loading).If you believe this was flagged incorrectly, please let a maintainer know.
github-actions commentedon Mar 26, 2026
This issue has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window.
Feel free to open a new issue that follows our issue templates.