Skip to content

fix(aws-strands): make the template MCP-client warning able to fire - #2615

Merged
ranst91 merged 1 commit into
mainfrom
claude/vibrant-grothendieck-f2564a
Sep 3, 2026
Merged

fix(aws-strands): make the template MCP-client warning able to fire#2615
ranst91 merged 1 commit into
mainfrom
claude/vibrant-grothendieck-f2564a

Conversation

@ranst91

@ranst91 ranst91 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

The problem

The TypeScript bridge's constructor carried a warning meant to catch an McpClient handed straight into the template Agent's tools array. It could never fire, and its comment gave the wrong reason for the behaviour it was warning about.

The check was unreachable. It scanned this._templateFields.tools, which is agent.tools.slice() off the template Agent, for an entry with a connect method and no name. Measured against the installed @strands-agents/sdk 1.1.0, that list cannot hold a client: flattenTools (dist/src/agent/agent.js) routes an McpClient into a separate _mcpClients array and passes only the rest into the ToolRegistry that Agent.tools reads from. Probed directly, new Agent({ systemPrompt: "x", tools: [new McpClient({ transport })] }) gives agent.tools.length === 0 and agent._mcpClients.length === 1.

The comment was wrong. It said Strands resolves a connected client's tools into agent.tools at construction time, so only an unconnected one would show up as a bare client. The SDK does no such thing at construction. Agent.initialize(), which is async and runs on the first invocation, is what calls client.listTools() and registers the result; McpClient.listTools() connects lazily on its own. Connected versus unconnected makes no difference. The real distinction is that the adapter clones the resolved registry before initialize() has ever run, which is what this package's README already explains.

The change

The warning is kept, because the failure it names is real and silent: MCP tools missing from every per-thread agent, with nothing at construction time to say so. It now reads the template's MCP client list instead of its tool list, through the existing _readTemplateField helper, which tries the public name before the underscore one and returns undefined rather than throwing when neither is there.

The message drops the connected-versus-unconnected framing, says how many client entries are in play, and tells the caller to resolve the tools and then drop the client from tools. That last part matters for a caller who passed both the client and its resolved tools, who would otherwise be warned on every construction with nothing left to fix.

The comment now states the actual mechanism.

Tests

Both directions, in agent-config-forwarded-real-sdk.test.ts alongside the rest of the template-forwarding coverage, against a genuine Agent (the routing is an instanceof McpClient check, so a fabricated template could not exercise it):

  • An McpClient in tools produces exactly one warning naming McpClient. The same test pins template.tools as empty first, so the assertion is about the warning firing and not about a client that happened to resolve. This test fails on main and passes with the change.
  • A template carrying an ordinary resolved tool stays quiet.

The client is constructed with a stub transport cast to never: McpClient's constructor only stores the transport, so the suite needs no live MCP server.

Verification

  • pnpm exec vitest run in integrations/aws-strands/typescript: 76 files, 1613 tests, all passing.
  • Same suite with src/agent.ts reverted to main: the new warning test fails, the other 1612 pass.
  • pnpm exec tsc --noEmit clean; prettier --check clean on the three touched files.

Docs

README.md gained a short paragraph pointing out that the adapter warns at construction time, placed in the existing "Passing tools to the Agent" section right after the resolve-and-spread example. That section's resolved-versus-unresolved explanation landed in #2611 and needed no correction here.

The constructor's MCP warning scanned `_templateFields.tools`, which is
`agent.tools.slice()` from the template Agent, for an entry that looks like
a bare `McpClient`. Measured against `@strands-agents/sdk` 1.1.0 that list
can never hold one: the SDK's `flattenTools` routes an `McpClient` into a
separate internal client list and only non-client entries reach the tool
registry that `Agent.tools` reads from. `new Agent({ tools: [client] })`
leaves `agent.tools` empty and the client in `_mcpClients`, so the loop
iterated a list the thing it was looking for cannot appear in.

The comment's stated reason was wrong too. The SDK does not resolve a
connected client's tools at construction time; `Agent.initialize()`, which
runs on the first invocation, is what calls `client.listTools()` and
registers the result, and `McpClient.listTools()` connects lazily. So
connected-versus-unconnected makes no difference. The real distinction is
that the adapter clones the resolved registry before `initialize()` has run,
which is what the README already says.

The warning is worth keeping: MCP tools silently missing from every
per-thread agent is exactly the kind of failure a construction-time line
should name. So it now reads the template's client list instead, through
`_readTemplateField`, which tries the public name before the underscore one
and yields `undefined` rather than throwing if neither is present. The
message drops the connected-versus-unconnected framing and tells the caller
to resolve the tools and drop the client from `tools`, which also keeps a
caller who passed both from being warned forever.

Tests cover both directions against a real `Agent`: an `McpClient` in
`tools` warns (and `agent.tools` is pinned empty in the same test, so the
assertion is about the warning and not about a client that resolved), and a
template carrying an ordinary resolved tool stays quiet. The first fails
before this change.
@ranst91
ranst91 requested a review from a team as a code owner September 3, 2026 08:08
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Python Preview Packages

Version 0.0.0.dev1788422932 published to TestPyPI.

Warning: These packages are built from contributor code that may not yet have been vetted for correctness or security. Install at your own risk and do not use in production.

Install with uv

Add the TestPyPI index to your pyproject.toml:

[[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
explicit = true

Then install the packages you need:

# Core SDK
uv add 'ag-ui-protocol==0.0.0.dev1788422932' --index testpypi

# Integrations (each already depends on the matching ag-ui-protocol preview)
uv add 'ag-ui-langgraph==0.0.0.dev1788422932' --index testpypi
uv add 'ag-ui-crewai==0.0.0.dev1788422932' --index testpypi
# NOTE: ag-ui-agent-spec depends on pyagentspec (git-only, not on PyPI).
# You will need to install pyagentspec separately from its git repo.
uv add 'ag-ui-agent-spec==0.0.0.dev1788422932' --index testpypi
uv add 'ag_ui_adk==0.0.0.dev1788422932' --index testpypi
uv add 'ag_ui_strands==0.0.0.dev1788422932' --index testpypi

Install with pip

pip install \
  --index-url https://test.pypi.org/simple/ \
  --extra-index-url https://pypi.org/simple/ \
  ag-ui-protocol==0.0.0.dev1788422932

Use --extra-index-url https://pypi.org/simple/ so pip can resolve
transitive dependencies (pydantic, fastapi, etc.) from real PyPI.


Commit: 6436619

@pkg-pr-new

pkg-pr-new Bot commented Sep 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

@ag-ui/a2a-middleware

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/a2a-middleware@2615

@ag-ui/a2ui-middleware

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/a2ui-middleware@2615

@ag-ui/event-throttle-middleware

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/event-throttle-middleware@2615

@ag-ui/mcp-apps-middleware

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/mcp-apps-middleware@2615

@ag-ui/mcp-middleware

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/mcp-middleware@2615

@ag-ui/a2a

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/a2a@2615

@ag-ui/adk

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/adk@2615

@ag-ui/ag2

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/ag2@2615

@ag-ui/agno

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/agno@2615

@ag-ui/aws-strands

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/aws-strands@2615

@ag-ui/claude-agent-sdk

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/claude-agent-sdk@2615

@ag-ui/claude-managed-agents

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/claude-managed-agents@2615

@ag-ui/crewai

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/crewai@2615

@ag-ui/langchain

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/langchain@2615

@ag-ui/langgraph

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/langgraph@2615

@ag-ui/llamaindex

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/llamaindex@2615

@ag-ui/mastra

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/mastra@2615

@ag-ui/pydantic-ai

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/pydantic-ai@2615

@ag-ui/vercel-ai-sdk

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/vercel-ai-sdk@2615

@ag-ui/watsonx

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/watsonx@2615

@ag-ui/a2ui-toolkit

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/a2ui-toolkit@2615

create-ag-ui-app

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/create-ag-ui-app@2615

@ag-ui/client

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/client@2615

@ag-ui/core

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/core@2615

@ag-ui/encoder

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/encoder@2615

@ag-ui/proto

pnpm add https://pkg.pr.new/ag-ui-protocol/ag-ui/@ag-ui/proto@2615

commit: 01e239d

@ranst91
ranst91 merged commit a6fa2a5 into main Sep 3, 2026
40 checks passed
@ranst91
ranst91 deleted the claude/vibrant-grothendieck-f2564a branch September 3, 2026 11:07
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