Skip to content

contrib/strands: add cache_tools toggle to TemporalMCPClient#1571

Merged
brianstrauch merged 4 commits into
mainfrom
strands-mcp-cache-tools
Jun 2, 2026
Merged

contrib/strands: add cache_tools toggle to TemporalMCPClient#1571
brianstrauch merged 4 commits into
mainfrom
strands-mcp-cache-tools

Conversation

@brianstrauch
Copy link
Copy Markdown
Member

@brianstrauch brianstrauch commented Jun 1, 2026

What changed

Adds a cache_tools option to TemporalMCPClient controlling how often an MCP server's tool list is fetched inside a workflow.

  • cache_tools=True: tools are listed once at the beginning of the workflow and reused for its lifetime.
  • cache_tools=False (default): tools are re-listed on every agent turn, so an MCP server restarted mid-workflow (tools added/removed/renamed) is picked up.

Worker-startup tool discovery (_TOOL_CACHE/populate_cache) is replaced by a per-server {server}-list-tools activity executed from inside the workflow, so the tool schema is recorded in history and replay-safe.

Why the hook-based design

Strands invokes ToolProvider.load_tools() exactly once at Agent construction, on a separate run_async thread that has no workflow runtime — so load_tools() cannot call workflow.execute_activity. Instead the activity is dispatched from a BeforeModelCallEvent hook, which runs on the workflow loop just before the tool registry is read each turn. TemporalAgent registers the hook per TemporalMCPClient provider and reconciles the registry (replace existing, register_tool new, delete removed). cache_tools=True lists once (guarded by _fetched); cache_tools=False re-lists each turn.

A nuance: with cache_tools=True the listing happens on the first turn rather than literally at construction (forced by the threading constraint) — the activity history is identical to a construction-time fetch, and the registry is populated before it is ever read.

Tests

  • Updated the three existing activity-sequence / factory-count assertions in test_mcp.py for the new leading {server}-list-tools activity and the lazy single-connection model.
  • The idle-timeout test's exact factory-call count became timing-dependent under the lazy-connection model (the list→call gap can fall under the 100ms idle window), so it's relaxed to >= 1; deterministic reuse is still covered by test_mcp_reuses_connection (factory == 1, default timeout).
  • Added one focused cache_tools=False test asserting one list-tools per model call.

All 13 strands tests pass; poe lint is clean.

🤖 Generated with Claude Code

Replace worker-startup tool discovery with a per-server {server}-list-tools
activity executed from inside the workflow. TemporalMCPClient.cache_tools
(default True) lists tools once at the start of the workflow; cache_tools=False
re-lists on every agent turn so a mid-workflow MCP server restart is picked up.

Strands calls load_tools() once at agent construction on a separate run_async
thread with no workflow runtime, so the activity is dispatched from a
BeforeModelCallEvent hook (which runs on the workflow loop before the registry
is read each turn) that reconciles added/removed/renamed tools.
@brianstrauch brianstrauch requested review from a team as code owners June 1, 2026 22:18
@brianstrauch brianstrauch enabled auto-merge (squash) June 1, 2026 23:17
@brianstrauch brianstrauch merged commit c8a052c into main Jun 2, 2026
26 of 27 checks passed
@brianstrauch brianstrauch deleted the strands-mcp-cache-tools branch June 2, 2026 19:50
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.

2 participants