
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
MCPClientstraight intoAgent(tools=[...])and Strands manages the connection lifecycle for you. - For Streamable HTTP,
MCPClient(url=..., headers=...)builds the transport; for stdio, pass a callback that opensstdio_client(...). - Built-in OAuth uses the client credentials grant for machine-to-machine setups; AWS IAM (SigV4) servers use the separate
mcp-proxy-for-awspackage. tool_filters(with strings or regexes) andprefixkeep tool lists small and names unique.strands-agents1.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.
uvinstalled, souvxcan 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:
MCPClienttakes 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'ToolProviderinterface. @latestpulls 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.
MCPClientexpects a function such aslambda: stdio_client(...). - Using tools outside the
withblock. In manual mode, agent calls must happen while the session is open. - Unpinned
@latestservers. Pin versions in production. - Old server code.
mcp.server.FastMCPand SSE come from older SDK versions. - Duplicate tool names. Two servers with the same tool name confuse the model. Set a
prefixon each client, or useprefix_with_server_name=Truewithload_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.











