Transform Strands Agents into MCP servers, exposing agent tools to any MCP-compatible client
Project description
strands-mcp-server
Bidirectional MCP integration for Strands Agents. Expose agents as MCP servers. Connect to any MCP server as a client.
pipx install strands-mcp-server
What This Does
This package provides two Python tools (mcp_server and mcp_client) and a CLI that connects Strands Agents to the Model Context Protocol ecosystem.
Core functionality:
- mcp_server tool: Turns a Strands Agent into an MCP server
- mcp_client tool: Connects to any MCP server and uses its tools
- strands-mcp-server CLI: stdio MCP server for Claude Desktop/Kiro integration
Concepts
The Model Context Protocol (MCP)
MCP is a protocol that allows AI applications to expose and consume "tools" (functions) over a standard interface. Think of it as an API specification for AI tool sharing.
Key concepts:
- MCP Server: Exposes tools that clients can call
- MCP Client: Connects to servers and calls their tools
- Transport: How messages are sent (HTTP, stdio, SSE)
- Tools: Functions with typed parameters and descriptions
How This Package Works
┌─────────────────────────────┐
│ Your Strands Agent │
│ tools: [calculator, ...] │
└─────────────────────────────┘
↓
┌───────────────┐
│ mcp_server │ ← Tool that exposes agent
└───────────────┘
↓
MCP Protocol (HTTP/stdio)
↓
┌─────────────────────────────┐
│ MCP Clients │
│ • Claude Desktop │
│ • Other agents │
│ • Custom clients │
└─────────────────────────────┘
Reverse direction:
┌─────────────────────────────┐
│ Your Strands Agent │
└─────────────────────────────┘
↓
┌───────────────┐
│ mcp_client │ ← Tool that connects to servers
└───────────────┘
↓
MCP Protocol (HTTP/stdio/SSE)
↓
┌─────────────────────────────┐
│ Remote MCP Server │
│ (another agent or service)│
└─────────────────────────────┘
Usage
1. As a Server (Expose Your Agent)
Use the mcp_server tool to expose your agent's tools to MCP clients.
from strands import Agent
from strands_tools import calculator, shell, file_read
from strands_mcp_server import mcp_server
agent = Agent(
name="my-agent",
tools=[calculator, shell, file_read, mcp_server]
)
# Start HTTP server (runs in background thread)
agent("start mcp server on port 8000")
# Server is now running at http://localhost:8000/mcp
# Clients can connect and use calculator, shell, file_read tools
What happens:
- Agent's tools are converted to MCP tool definitions
- HTTP server starts on port 8000 with MCP protocol handlers
- Clients send JSON-RPC requests to list/call tools
- Server executes tools using agent's tool registry
- Results returned in MCP format
Transport modes:
| Transport | Execution | Use Case |
|---|---|---|
http |
Background thread (non-blocking) | Production servers, multi-node |
stdio |
Foreground (blocks current thread) | CLI entrypoints, Claude Desktop |
# HTTP: Returns immediately, server runs in background
agent.tool.mcp_server(action="start", transport="http", port=8000, agent=agent)
# stdio: Blocks until terminated (for CLI tools)
agent.tool.mcp_server(action="start", transport="stdio", agent=agent)
Stateless mode:
For production deployments with load balancing, use stateless mode. Each request creates a fresh session with no state persistence.
agent.tool.mcp_server(
action="start",
transport="http",
port=8000,
stateless=True, # Enable stateless mode
agent=agent
)
2. As a Client (Connect to Other Servers)
Use the mcp_client tool to connect your agent to remote MCP servers.
from strands import Agent
from strands_mcp_server import mcp_client
agent = Agent(tools=[mcp_client])
# Connect to a server
agent.tool.mcp_client(
action="connect",
connection_id="remote-agent",
transport="http",
server_url="http://localhost:8000/mcp"
)
# List available tools
result = agent.tool.mcp_client(
action="list_tools",
connection_id="remote-agent"
)
# Call a remote tool
result = agent.tool.mcp_client(
action="call_tool",
connection_id="remote-agent",
tool_name="calculator",
tool_args={"expression": "42 * 89"}
)
What happens:
- Client establishes connection to remote server
- Retrieves tool definitions from server
- Calls tools by sending JSON-RPC requests
- Server executes tool and returns result
- Client receives and returns formatted result
Supported transports:
# HTTP (most common)
agent.tool.mcp_client(
action="connect",
connection_id="server1",
transport="http",
server_url="http://localhost:8000/mcp"
)
# stdio (launch subprocess)
agent.tool.mcp_client(
action="connect",
connection_id="local",
transport="stdio",
command="python",
args=["server.py"]
)
# SSE (server-sent events)
agent.tool.mcp_client(
action="connect",
connection_id="sse-server",
transport="sse",
server_url="http://localhost:8000/sse"
)
3. CLI for Claude Desktop/Kiro
The strands-mcp-server command provides a stdio MCP server for integration with Claude Desktop and similar tools.
Two modes of operation:
Local Mode
Exposes tools from a ./tools/ directory. Strands handles hot reloading automatically.
# Project structure:
# my-project/
# tools/
# weather.py (with @tool decorator)
# database.py (with @tool decorator)
strands-mcp-server --cwd /path/to/my-project
Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"my-project": {
"command": "strands-mcp-server",
"args": ["--cwd", "/absolute/path/to/my-project"]
}
}
}
What happens:
- CLI creates agent with
load_tools_from_directory=True - Strands loads all
@tooldecorated functions from./tools/ - Starts MCP server in stdio mode (reads stdin, writes stdout)
- Claude Desktop communicates via stdio using MCP protocol
- Tools execute in agent context, results returned to Claude
Proxy Mode
Acts as a bridge between stdio (Claude Desktop) and an HTTP MCP server.
# Terminal 1: Start your agent with HTTP server
python my_agent.py # Uses mcp_server tool on port 8000
# Terminal 2: Not needed - Claude connects directly via config
Claude Desktop config:
{
"mcpServers": {
"remote-agent": {
"command": "strands-mcp-server",
"args": ["--upstream-url", "http://localhost:8000/mcp"]
}
}
}
What happens:
- CLI connects to upstream HTTP server as MCP client
- Retrieves tool list from upstream
- Creates stdio MCP server for Claude Desktop
- Forwards all tool calls from Claude to upstream server
- Returns upstream results back to Claude via stdio
Why this exists: Claude Desktop only speaks stdio MCP. If your agent runs an HTTP MCP server, the CLI bridges the protocols.
API Reference
mcp_server Tool
Purpose: Expose Strands Agent as MCP server.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
action |
str | required | start, stop, status, or list |
server_id |
str | "default" |
Unique identifier for this server |
transport |
str | "http" |
http (background) or stdio (foreground) |
port |
int | 8000 |
Port for HTTP server |
tools |
list[str] | None |
Tool names to expose (None = all) |
expose_agent |
bool | True |
Add invoke_agent tool for full conversations |
stateless |
bool | False |
No session state (for multi-node) |
agent |
Agent | required | Parent agent (auto-injected) |
Examples:
# Start HTTP server
agent("start mcp server on port 8000")
# Start with only specific tools
agent.tool.mcp_server(
action="start",
tools=["calculator", "file_read"],
agent=agent
)
# Production stateless mode
agent.tool.mcp_server(
action="start",
stateless=True,
agent=agent
)
# Get status
agent.tool.mcp_server(action="status", agent=agent)
mcp_client Tool
Purpose: Connect to and use remote MCP servers.
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
action |
str | required | connect, disconnect, list_tools, call_tool, list_connections |
connection_id |
str | None | Identifier for this connection |
transport |
str | None | http, stdio, or sse |
server_url |
str | None | URL for http/sse transport |
command |
str | None | Command for stdio transport |
args |
list[str] | None | Arguments for stdio command |
tool_name |
str | None | Tool to call (for call_tool action) |
tool_args |
dict | None | Tool arguments (for call_tool action) |
Examples:
# Connect
agent.tool.mcp_client(
action="connect",
connection_id="server1",
transport="http",
server_url="http://localhost:8000/mcp"
)
# List tools
agent.tool.mcp_client(
action="list_tools",
connection_id="server1"
)
# Call tool
agent.tool.mcp_client(
action="call_tool",
connection_id="server1",
tool_name="calculator",
tool_args={"expression": "2 + 2"}
)
# Disconnect
agent.tool.mcp_client(
action="disconnect",
connection_id="server1"
)
CLI Options
strands-mcp-server [OPTIONS]
| Option | Description |
|---|---|
--cwd PATH |
Working directory (for local mode) |
--upstream-url URL |
Upstream server URL (for proxy mode) |
--system-prompt TEXT |
Custom system prompt |
--no-agent-invocation |
Disable invoke_agent tool |
--debug |
Enable debug logging |
Agent-to-Agent Communication
A common pattern: multiple specialized agents sharing tools via MCP.
from strands import Agent
from strands_tools import calculator, http_request, file_read
from strands_mcp_server import mcp_server, mcp_client
# Agent 1: Data specialist
data_agent = Agent(
name="data-agent",
tools=[file_read, calculator, mcp_server]
)
data_agent.tool.mcp_server(
action="start",
port=8001,
agent=data_agent
)
# Agent 2: Web specialist
web_agent = Agent(
name="web-agent",
tools=[http_request, mcp_server]
)
web_agent.tool.mcp_server(
action="start",
port=8002,
agent=web_agent
)
# Coordinator agent
coordinator = Agent(
name="coordinator",
tools=[mcp_client]
)
# Connect to both specialists
coordinator.tool.mcp_client(
action="connect",
connection_id="data",
transport="http",
server_url="http://localhost:8001/mcp"
)
coordinator.tool.mcp_client(
action="connect",
connection_id="web",
transport="http",
server_url="http://localhost:8002/mcp"
)
# Use their specialized tools
coordinator("""
1. Use web agent to fetch data from https://api.example.com/data
2. Use data agent to analyze the numbers
3. Summarize the results
""")
Why this works:
- Each agent exposes its tools via MCP
- Coordinator doesn't need to have all tools
- Tools execute in their native agent context
- Clean separation of concerns
Production Deployment
Stateless Mode
For production with load balancing:
agent.tool.mcp_server(
action="start",
transport="http",
port=8000,
stateless=True, # No session state
agent=agent
)
What stateless means:
- Each request gets a fresh transport/session
- No state persists between requests
- Can distribute requests across multiple nodes
- Load balancer doesn't need sticky sessions
Example production server:
# production_server.py
from strands import Agent
from strands_mcp_server import mcp_server
agent = Agent(
name="production-agent",
tools=[...],
load_tools_from_directory=True
)
agent.tool.mcp_server(
action="start",
transport="http",
port=8000,
stateless=True,
agent=agent
)
# Keep running
import time
while True:
time.sleep(60)
All instances can run identical code because of stateless mode. Load balancer can distribute requests freely.
Technical Details
Tool Conversion
Strands tools are automatically converted to MCP tool definitions:
# Strands tool
{
"name": "calculator",
"description": "Perform calculations",
"inputSchema": {
"json": {
"type": "object",
"properties": {
"expression": {"type": "string"}
},
"required": ["expression"]
}
}
}
# Becomes MCP Tool
types.Tool(
name="calculator",
description="Perform calculations",
inputSchema={
"type": "object",
"properties": {
"expression": {"type": "string"}
},
"required": ["expression"]
}
)
invoke_agent Tool
When expose_agent=True (default), an additional invoke_agent tool is added:
{
"name": "invoke_agent",
"description": "Invoke full agent with a prompt",
"inputSchema": {
"type": "object",
"properties": {
"prompt": {"type": "string"}
},
"required": ["prompt"]
}
}
This allows clients to have full conversational access to the agent, not just individual tools.
Implementation detail: Creates a fresh agent instance with clean message history to avoid tool block mismatches.
Transport Implementations
HTTP (StreamableHTTP):
- Uses
StreamableHTTPSessionManagerfrom MCP SDK - Starlette ASGI app with Uvicorn server
- CORS middleware enabled
- Runs in daemon background thread
stdio:
- Uses
stdio_server()from MCP SDK - Reads JSON-RPC from stdin
- Writes JSON-RPC to stdout
- Blocks current thread (for CLI use)
- Logging goes to stderr (stdin/stdout reserved for protocol)
Troubleshooting
Tools not loading in CLI
Check working directory:
strands-mcp-server --cwd /absolute/path/to/project --debug
Verify ./tools/ exists relative to --cwd and contains .py files with @tool decorator.
Connection refused
Verify server is running:
curl http://localhost:8000/mcp
Should return an HTTP response (not necessarily success, but should connect).
Port already in use
Find and kill process:
lsof -i :8000
kill -9 <PID>
stdio mode blocking
This is expected behavior. The stdio transport blocks the current thread and processes stdin/stdout continuously. Use http transport if you need non-blocking execution.
Testing
pytest # All tests
pytest tests/test_mcp_server.py # Server tests only
pytest --cov # With coverage
Tests are covering:
- Server startup/shutdown
- Client connections
- Tool listing and calling
- Error handling
- Transport modes
- Stateless/stateful behavior
Links
- Documentation: https://cagataycali.github.io/strands-mcp-server/
- Source: https://github.com/cagataycali/strands-mcp-server
- PyPI: https://pypi.org/project/strands-mcp-server/
- Strands Agents: https://strandsagents.com
- MCP Specification: https://modelcontextprotocol.io/
License
Apache 2.0
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file strands_mcp_server-0.1.0.tar.gz.
File metadata
- Download URL: strands_mcp_server-0.1.0.tar.gz
- Upload date:
- Size: 31.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f4b9cd6712d07e83fea159ae68da191d551f2b46c135aa566a86c8c51ef3ab4f
|
|
| MD5 |
ca543845b8fac42192153de74ff6c2ec
|
|
| BLAKE2b-256 |
b2c2c55dc6f33cddb3f1222f8e68b2f3a6212587f15051a88f213fd1d3ae977e
|
File details
Details for the file strands_mcp_server-0.1.0-py3-none-any.whl.
File metadata
- Download URL: strands_mcp_server-0.1.0-py3-none-any.whl
- Upload date:
- Size: 28.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.6.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
68113067ef3053dcc056fef415eabc4c9d7fb7149fe46ff2cb14d84933bec989
|
|
| MD5 |
1850c2183aa675e770f67ff836a2708a
|
|
| BLAKE2b-256 |
4862777cc41f7d044c5dcc98db7b814aad913647a2f78d14e7b4bb3257eb6615
|