[FEATURE]:OpenCode MCP Tool Resolution Causes Large First-Turn and Per-Turn Overhead · Issue #19300 · anomalyco/opencode · GitHub
Skip to content

[FEATURE]:OpenCode MCP Tool Resolution Causes Large First-Turn and Per-Turn Overhead #19300

Closed as not planned

Description

@whuanle

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:

  1. On the first prompt for a workspace, MCP initialization connects every enabled MCP server.
  2. During MCP client creation, OpenCode immediately calls listTools().
  3. On later prompts, OpenCode still calls listTools() again for every connected MCP client inside MCP.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:193
  • packages/opencode/src/server/routes/session.ts:209
  • packages/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:786
  • packages/opencode/src/server/routes/session.ts:817
  • packages/opencode/src/session/prompt.ts:746
  • packages/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:182
  • packages/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:606
  • packages/opencode/src/mcp/index.ts:618
  • packages/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:

  1. First prompt latency:
    • connect all enabled MCP servers
    • list tools for all enabled MCP servers
  2. 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

  1. added
    discussionUsed for feature requests, proposals, ideas, etc. Open discussion
    on Mar 26, 2026
  2. github-actions commented on Mar 26, 2026

    @github-actions
    Contributor

    This issue doesn't fully meet our contributing guidelines.

    What needs to be fixed:

    • The description appears to be AI-generated — it's an extensive, heavily structured wall of text with code paths, multiple option sections, and implementation pseudocode that is not acceptable per our guidelines. Please replace it with a concise, human-written description of the problem and what you'd like to see changed.

    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:

    If you believe this was flagged incorrectly, please let a maintainer know.

  3. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Mar 26, 2026
  4. github-actions commented on Mar 26, 2026

    @github-actions
    Contributor

    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.

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

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)discussionUsed for feature requests, proposals, ideas, etc. Open discussion

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions