Skip to content

fix(openai-agents): clear the agent SDK's MCP tool cache in invalidateToolsCache - #242

Draft
campoy wants to merge 1 commit into
mainfrom
fix/openai-agents-typescript-mcp-cache-invalidation-keeps-old-tools
Draft

campoy wants to merge 1 commit into
mainfrom
fix/openai-agents-typescript-mcp-cache-invalidation-keeps-old-tools

Conversation

@campoy

@campoy campoy commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

What was changed

  • statelessMcpServer() and statefulMcpServer() references now call invalidateServerToolsCache(name) from @openai/agents-core in invalidateToolsCache(), as native MCP servers do. The agent SDK keeps a shared tool list per server name, and before this change the references never cleared it, so the next run reused the old list.
  • A stateful reference also marks its next list-tools Activity with { invalidateToolsCache: true }. The dedicated Worker then calls invalidateToolsCache() on the Worker-side server before it lists, so a factory server with its own cache (cacheToolsList: true) lists again too. Other listings keep their empty input.
  • Both are behind patched('openai-agents-mcp-invalidate-tools-cache'), asked only when invalidateToolsCache() is called (and, for a stateless reference, only when it caches).
  • New test MCP invalidateToolsCache makes the next run list tools again in test-openai-agents.ts, for both references.

No public API change.

Why?

See #241. After invalidateToolsCache(), the next agent run in the same Workflow still got the old tool names and schemas. No list-tools Activity ran, and nothing warned.

Replay and rollback

The next run after invalidateToolsCache() now schedules a list-tools Activity that it skipped before. Without the gate, an open Workflow that invalidated and then ran the agent again would fail replay with [TMPRL1100].

  • Runs recorded before this change replay on it: the gate returns false for them, so they keep the old list.
  • Runs that recorded the marker need a build that keeps the gate. The rollback target is a build that asks the same patched() only on replay (workflowInfo().unsafe.isReplaying && patched(...)), so new runs keep the old behavior and marked runs keep the new one. Worker Versioning also works.

Checklist

  1. Closes [Bug] openai-agents (TypeScript): invalidateToolsCache() on a plugin MCP server keeps the old tool list #241

  2. How was this tested:

    • The new test fails on main at c664a34 on its one assertion: both references get ['old_tool'] after invalidateToolsCache(). It passes with this change. With only the Worker-side part removed, the stateful reference still gets ['old_tool'].
    • Locally in Docker (Node 24.22.0, pnpm 10.27.0): make lint (8 existing warnings, none in changed files), make test (208 passed, 207 on main), make build, check_npm_package.py, smoke.mjs, check_conventions.py and Prettier on the changed files pass.
    • [Bug] openai-agents (TypeScript): invalidateToolsCache() on a plugin MCP server keeps the old tool list #241's reproduction exits 1 on npm 1.24.0 and on main, and 0 with this change.
    • Replay check with a dev server (Temporal CLI 1.9.1), histories recorded with no Workflow cache, stateless and stateful, with and without invalidateToolsCache(), plus stateless runs held open before and after it:
      • main histories replay on main, on this change and on the gate-keeping rollback build (6 of 6 each).
      • This change's histories replay on it and on the rollback build (6 of 6). On main, the 3 with the marker fail with [TMPRL1100] ... Non-deprecated patch marker encountered, as expected for a gate.
      • Without the gate, the 2 main histories that invalidated fail with [TMPRL1100] Activity type of scheduled event 'invokeModelActivity' does not match ... '<server>-list-tools'. That is what the gate prevents.
      • Held runs carried across a Worker change finish with no failed Workflow Task: a main run held after invalidateToolsCache() keeps the old list on this change; one held before it lists again; on the rollback build, a run that recorded the marker lists again and one that didn't keeps the old list. The carried histories replay on this change and on the rollback build.
      • A control with the MCP server renamed fails all 6 main histories with [TMPRL1100].

    CI covers the other Node versions and platforms.

  3. Any docs updates needed?
    No. The README doesn't describe MCP tool caching; the agent SDK's MCP guide already says to call invalidateToolsCache().

Not covered

  • A stateless factory that returns one shared server instance with its own cache. Each stateless Activity call normally builds a new server, so there is nothing to clear there.
  • Open question: the patch ID name. Other gates in this plugin may settle on a naming scheme.

Related: #209 and #210 change the same files (mcp-client.ts, stateful-mcp-client.ts, and #209 the stateful listTools handler in stateful-mcp-provider.ts). Whichever merges second needs a small rebase.

…eToolsCache

statelessMcpServer() and statefulMcpServer() references now clear the agent
SDK's shared tool cache for their server name when invalidateToolsCache() is
called, as native MCP servers do, so the next run lists tools again. A stateful
reference also has the next listing clear the Worker-side server's own cache.

Runs recorded before this change reused the cached tool list, so the new
behavior is behind the patch 'openai-agents-mcp-invalidate-tools-cache'.

This branch has not been deployed

No deployments
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.

[Bug] openai-agents (TypeScript): invalidateToolsCache() on a plugin MCP server keeps the old tool list

1 participant