Menu

AI

Strands Agents MCP Tutorial: Connect MCP Servers to AWS's Open Source Agent SDK

Connect MCP servers to Strands Agents with MCPClient. Covers stdio and Streamable HTTP, OAuth and AWS IAM auth, tool filters, prefixes, config files and elicitation.

By: Irina ShvayaNovember 2, 2026

Strands Agents MCP Tutorial: Connect MCP Servers to AWS's Open Source Agent SDK

This tutorial is part of Build an MCP Server, within The MCP Guide. Want it built for you? See MCP development.

Strands Agents is the open source agent SDK from AWS, for Python and TypeScript. Its MCP support centers on one class, MCPClient. You pass it to an Agent as if it were a tool, and Strands opens the connection, lists the server's tools and closes it when the agent is done.

This tutorial builds a Python agent with a local stdio server, moves it to Streamable HTTP, adds OAuth or AWS IAM auth, then filters and prefixes tools. Code was checked against the Strands MCP tools page and MCP transports page on 2 November 2026, when strands-agents 1.63.0 was current on PyPI.

Key Takeaways

  • Pass an MCPClient straight into Agent(tools=[...]) and Strands manages the connection lifecycle for you.
  • For Streamable HTTP, MCPClient(url=..., headers=...) builds the transport; for stdio, pass a callback that opens stdio_client(...).
  • Built-in OAuth uses the client credentials grant for machine-to-machine setups; AWS IAM (SigV4) servers use the separate mcp-proxy-for-aws package.
  • tool_filters (with strings or regexes) and prefix keep tool lists small and names unique.
  • strands-agents 1.63.0 accepts MCP Python SDK versions from 1.23.0 up to (not including) 2.4, so it works with SDK v2.

Prerequisites

  • Python 3.10 or later.
  • pip install strands-agents
  • Model access. Strands describes Amazon Bedrock as its default model provider, with Anthropic, OpenAI, Google, Ollama and others available.
  • uv installed, so uvx can run Python-packaged MCP servers.

Minimal working example (stdio)

The docs' quickstart connects to AWS's documentation MCP server:

from mcp import stdio_client, StdioServerParameters
from strands import Agent
from strands.tools.mcp import MCPClient

mcp_client = MCPClient(lambda: stdio_client(
    StdioServerParameters(
        command="uvx",
        args=["awslabs.aws-documentation-mcp-server@latest"]
    )
))

agent = Agent(tools=[mcp_client])
agent("What is AWS Lambda?")

What to notice:

  • MCPClient takes a function that opens the transport, not an open transport. Strands calls it when it needs a connection.
  • Passing the client in tools=[...] is the "managed integration" the docs recommend. The client implements Strands' ToolProvider interface.
  • @latest pulls whatever version was published most recently. Pin a version for anything beyond a demo.

Our AWS MCP server profile covers AWS's own MCP servers and what they can touch.

Manual lifecycle

If you need to control when the session opens, use a with block and list tools yourself:

with mcp_client:
    tools = mcp_client.list_tools_sync()
    agent = Agent(tools=tools)
    agent("What is AWS Lambda?")  # must run inside the block

Remote servers (Streamable HTTP)

Pass a URL and Strands builds the Streamable HTTP transport from the installed mcp package:

import os

from strands import Agent
from strands.tools.mcp import MCPClient

github_mcp_client = MCPClient(
    url="https://api.githubcopilot.com/mcp/",
    headers={"Authorization": f"Bearer {os.getenv('MCP_PAT')}"},
)

agent = Agent(tools=[github_mcp_client])

For your own test server, point url at http://localhost:8000/mcp. The FastMCP notes server in our langchain-mcp-adapters tutorial works. Strands also supports SSE through mcp.client.sse.sse_client, but SSE is deprecated in MCP; see SSE vs Streamable HTTP.

Authentication

OAuth (client credentials)

For OAuth-protected servers, pass an auth dict and Strands handles tokens:

import os

from strands.tools.mcp import MCPClient

oauth_mcp_client = MCPClient(
    url="https://api.example.com/mcp/",
    auth={
        "client_id": os.environ["OAUTH_CLIENT_ID"],
        "client_secret": os.environ["OAUTH_CLIENT_SECRET"],
        "scopes": ["mcp:tools"],
    },
)

The docs say this uses the OAuth "client_credentials grant, which suits machine-to-machine deployments where no user is present." Token acquisition and refresh are automatic. scopes is advisory: if the server advertises its own scopes, Strands uses those instead. For interactive sign-in, pass an httpx.Auth implementation such as the MCP SDK's OAuthClientProvider as auth_provider. auth and auth_provider cannot be combined, and OAuth works over Streamable HTTP only.

AWS IAM (SigV4)

Some MCP servers on AWS use SigV4 signing with IAM credentials instead of OAuth. For those, Strands' docs point to the mcp-proxy-for-aws package. Their example targets the bedrock-agentcore service:

pip install mcp-proxy-for-aws
from mcp_proxy_for_aws.client import aws_iam_streamablehttp_client
from strands.tools.mcp import MCPClient

mcp_client = MCPClient(lambda: aws_iam_streamablehttp_client(
    endpoint="https://your-service.us-east-1.amazonaws.com/mcp",
    aws_region="us-east-1",
    aws_service="bedrock-agentcore"
))

It signs each request with your AWS credentials, so the IAM role the agent runs as decides what the server allows. Give that role the least access that works. The docs link the package's PyPI page for details.

Filter and prefix tools

Load only the tools the agent needs:

import re

from mcp import stdio_client, StdioServerParameters
from strands.tools.mcp import MCPClient

filtered_client = MCPClient(
    lambda: stdio_client(StdioServerParameters(
        command="uvx",
        args=["awslabs.aws-documentation-mcp-server@latest"]
    )),
    tool_filters={"allowed": [re.compile(r"^search_.*")]},
)

tool_filters accepts exact strings or compiled regexes under "allowed" and "rejected". Allowed is applied first, then rejected.

When two servers both have a search tool, set a prefix:

aws_docs_client = MCPClient(
    lambda: stdio_client(StdioServerParameters(
        command="uvx",
        args=["awslabs.aws-documentation-mcp-server@latest"]
    )),
    prefix="aws_docs",
)

The agent sees aws_docs_search_documentation, but Strands still sends the original name to the server.

Many servers from one config

MCPClient.load_servers() reads the standard mcpServers shape and expands ${VAR} placeholders, so secrets stay in the environment:

from strands import Agent
from strands.tools.mcp import MCPClient

clients = MCPClient.load_servers(
    {
        "mcpServers": {
            "documentation": {
                "command": "uvx",
                "args": ["awslabs.aws-documentation-mcp-server@latest"],
            },
            "protected-api": {
                "url": "https://api.example.com/mcp/",
                "auth": {
                    "client_id": "${OAUTH_CLIENT_ID}",
                    "client_secret": "${OAUTH_CLIENT_SECRET}",
                    "scopes": ["mcp:tools"],
                },
            },
        }
    },
    prefix_with_server_name=True,
)

agent = Agent(tools=clients)

Add a tool

Tools live on the server. Add a function, restart the server, and the next agent run lists it. If you use tool_filters, make sure the new name matches your allowed patterns.

Strands' docs include a server example that imports from mcp.server import FastMCP and runs over SSE. With MCP Python SDK v2 installed, that import no longer exists. Use from mcp.server import MCPServer or the standalone fastmcp package, and serve over Streamable HTTP. Our FastMCP tutorial shows the current pattern.

Elicitation

Servers can pause a tool call to ask for input, such as confirming a deletion. Strands supports this with an elicitation_callback on MCPClient that returns an ElicitResult from mcp.types. Wire it to a real prompt for a person, not an automatic "accept," or the confirmation is meaningless.

The TypeScript version

Strands also ships a TypeScript SDK. The docs' equivalent of the Python quickstart passes an McpClient to the agent, and the client "connects lazily on first use":

const mcpClient = new McpClient({
  transport: new StdioClientTransport({
    command: 'uvx',
    args: ['awslabs.aws-documentation-mcp-server@latest'],
  }),
})

const agent = new Agent({
  tools: [mcpClient],
})

await agent.invoke('What is AWS Lambda?')

Agent and McpClient come from @strands-agents/sdk; the transports come from the official MCP TypeScript SDK. TypeScript options mirror Python with camelCase names: toolFilters, prefix, elicitationCallback and McpClient.loadServers().

Production checklist

Before an agent runs unattended, work through this list. Each item comes from the options shown above.

  • Pin server versions instead of @latest.
  • Load only the tools each agent needs with tool_filters.
  • Use OAuth client credentials or IAM, never personal tokens, for unattended agents.
  • Give the agent's IAM role or OAuth client the smallest scope that works.
  • Prefix tools whenever an agent uses more than one server.
  • Log tool calls and keep a human approval step in front of anything destructive. Our permissions and approvals lesson explains the options.

Test with the MCP Inspector

npx @modelcontextprotocol/inspector --cli http://localhost:8000/mcp --transport http --method tools/list

You can also call a tool directly from Python with mcp_client.call_tool_sync(tool_use_id=..., name=..., arguments=...) to check results without the model. Our MCP Inspector lesson covers more.

Pitfalls

  • Passing a transport instead of a callback. MCPClient expects a function such as lambda: stdio_client(...).
  • Using tools outside the with block. In manual mode, agent calls must happen while the session is open.
  • Unpinned @latest servers. Pin versions in production.
  • Old server code. mcp.server.FastMCP and SSE come from older SDK versions.
  • Duplicate tool names. Two servers with the same tool name confuse the model. Set a prefix on each client, or use prefix_with_server_name=True with load_servers().

Next step

The free MCP course explains transports, auth and elicitation step by step. If you need an MCP server for agents on AWS, with IAM or OAuth set up properly, talk to our MCP development team.

More in the MCP Guide

Free tools: server.json Validator · MCP Error Code Lookup

Latest research: State of MCP: October 2026

Frequently asked questions

Does Strands Agents support MCP in TypeScript?

Yes. The docs show McpClient from @strands-agents/sdk with StdioClientTransport or StreamableHTTPClientTransport, plus toolFilters, prefix and McpClient.loadServers().

Do I need AWS to use Strands with MCP?

No. Strands works with several model providers and any MCP server. AWS-specific pieces, such as Bedrock models or IAM-signed servers, are optional.

How do I connect to an MCP server on Bedrock AgentCore?

For IAM-authenticated endpoints, install mcp-proxy-for-aws and wrap aws_iam_streamablehttp_client in MCPClient, with aws_service="bedrock-agentcore" and your region.

Which MCP Python SDK version does Strands need?

strands-agents 1.63.0 requires mcp>=1.23.0,<2.4. That covers both SDK v1 and current v2 releases up to 2.3.x.

You Might Also like to Read

Get a FREE Website Audit

Enter your website and get a 20–30 page SEO, GEO, AEO & CRO audit within 24 hours. Completely free.

Don't have a site yet? Get in touch →

Ready to speak with a marketing expert?
Give us a call! (916) 866-7893

Websites Launched
1407
Websites Launched
Marketing Experts
29
Marketing Experts
Hours of Dedicated Work
204533
Hours of Dedicated Work
Irina S.Benjamin G.Jeanette M.David G.