Skip to content

Conversation

@ktsaou
Copy link

@ktsaou ktsaou commented Jan 4, 2026

Problem

MCP tools are listed on every prompt build, which calls listTools per MCP server sequentially. A slow MCP server can slow all LLM requests.

Solution

  • Add a per-mcp-server cache of raw MCP listTools results in MCP state.
  • Cache validity is tracked by a per-mcp-server sequence counter.
  • On a cache hit, rebuild AI SDK Tool objects from cached MCP tool definitions so the behavior matches a fresh listTools fetch.
  • Empty tool lists are treated as valid cache entries.

Invalidation events (existing flows only)

  • MCP ToolsChanged notification (now consumed to invalidate that server).
  • MCP add/connect/disconnect (existing endpoints).
  • MCP listTools failure (existing behavior: mark failed + remove client) also invalidates cache.
  • Instance disposal clears caches.

Behavior details

  • If cache is valid, MCP.tools returns immediately without calling MCP listTools.
  • If cache is invalid or missing, MCP.tools blocks and refreshes (same as current behavior for a fresh fetch).
  • Failure behavior is unchanged: failed status + client removal.

Tests

  • Added MCP tools cache tests (cache hit, ToolsChanged invalidation, empty tools).
  • Ran: bun test test/mcp/tools-cache.test.ts (from packages/opencode).

Notes

  • No new config watcher; config reload behavior remains unchanged.

@ktsaou
Copy link
Author

ktsaou commented Jan 4, 2026

The current codebase has another problem which I have not addressed: You cannot select MCP servers before sending the first LLM request. You have to send "hello" in order to be able to select MCP servers because MCP servers are initialized on the first LLM request.

I didn't do anything about it.

The biggest problem addressed by this PR is that a slow listTools on a single MCP server, slows down all the LLM requests (listTools is called before every LLM request).

With this PR, MCP listTools are cached per MCP server, and are called again only when they are invalidated.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant