This example demonstrates how to use MCP Compose with STDIO transport. The agent spawns the MCP Compose as a subprocess and communicates via standard input/output.
This example shows:
- Two MCP Servers: Calculator and Echo servers (
mcp1.py,mcp2.py) - STDIO Transport: The agent spawns
mcp-composeas a subprocess - Unified Access: Single interface to all tools from multiple servers
┌─────────────────────────────────────────────────────────────┐
│ Pydantic AI Agent │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ MCPServerStdio │ │
│ │ (spawns mcp-compose subprocess) │ │
│ └──────────────────────┬─────────────────────────────────┘ │
└─────────────────────────┼────────────────────────────────────┘
│ STDIO (stdin/stdout)
▼
┌─────────────────────────────────────────────────────────────┐
│ MCP Compose │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Calculator │ │ Echo │ │
│ │ (mcp1.py) │ │ (mcp2.py) │ │
│ │ │ │ │ │
│ │ • add │ │ • ping │ │
│ │ • subtract │ │ • echo │ │
│ │ • multiply │ │ • reverse │ │
│ │ • divide │ │ • uppercase │ │
│ │ │ │ • lowercase │ │
│ │ │ │ • count_words │ │
│ └─────────────────┘ └─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
- STDIO Transport: Agent spawns MCP Compose as a subprocess
- No Separate Server: No need to start the composer in another terminal
- Process Lifecycle: Agent manages the subprocess lifecycle automatically
- Unified Interface: All tools accessible through a single connection
- Pure Python: No external dependencies beyond FastMCP and pydantic-ai
make installThis will install:
mcp-compose(the orchestrator)fastmcp(for the demo MCP servers)
make install-agentThis will install:
pydantic-ai[mcp](AI agent with MCP support)
make agentThat's it! The agent automatically:
- Spawns
mcp-composeas a subprocess - Connects via STDIO transport
- Provides access to all tools from both servers
Once the agent is running:
- "What is 15 plus 27?"
- "Multiply 8 by 9"
- "Reverse the text 'hello world'"
- "Convert 'Hello World' to uppercase"
- "Count the words in 'The quick brown fox jumps'"
With STDIO transport, the client spawns the server as a subprocess:
- Agent starts: Creates an
MCPServerStdiopointing tomcp-compose - Subprocess spawned:
mcp-compose serve --transport stdiois executed - Communication: JSON-RPC messages flow through stdin/stdout
- Lifecycle managed: Agent cleans up subprocess when done
This is different from SSE transport where the server runs independently.
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPServerStdio
# Create MCP server connection with STDIO transport
mcp_server = MCPServerStdio(
'mcp-compose',
args=['serve', '--config', 'mcp_compose.toml', '--transport', 'stdio'],
timeout=300.0,
)
# Create agent with MCP tools
agent = Agent(
model="anthropic:claude-sonnet-4-0",
toolsets=[mcp_server],
)
# Use async context manager to manage subprocess
async with agent:
result = await agent.run("What is 5 + 3?")| File | Description |
|---|---|
mcp_compose.toml |
Configuration for the MCP servers |
mcp1.py |
Calculator MCP server (add, subtract, multiply, divide) |
mcp2.py |
Echo MCP server (ping, echo, reverse, uppercase, etc.) |
agent.py |
Pydantic AI agent using STDIO transport |
Makefile |
Convenience commands |
The mcp_compose.toml defines the managed MCP servers:
[composer]
name = "demo-composer"
conflict_resolution = "prefix" # Tools become calculator:add, echo:ping, etc.
log_level = "INFO"
[[servers.proxied.stdio]]
name = "calculator"
command = ["python", "mcp1.py"]
restart_policy = "never"
[[servers.proxied.stdio]]
name = "echo"
command = ["python", "mcp2.py"]
restart_policy = "never"| Command | Description |
|---|---|
make help |
Show all available commands |
make install |
Install mcp-compose and FastMCP |
make install-agent |
Install pydantic-ai with MCP support |
make agent |
Run the AI agent (spawns composer) |
make clean |
Clean up temporary files |
Use STDIO when:
- ✅ Single client connecting to the MCP server
- ✅ You want the client to manage server lifecycle
- ✅ Running locally without network overhead
- ✅ Simpler deployment (no server to manage separately)
Use SSE/HTTP when:
- ❌ Multiple clients need to connect
- ❌ Server should persist beyond client sessions
- ❌ Need HTTP-based authentication/authorization
- ❌ Deploying as a standalone service
- SSE Example - Server-Sent Events transport
- Streamable HTTP Example - Modern HTTP transport
- User Guide - Complete feature documentation
- Architecture - System design
Found an issue or want to improve this example? Please open an issue or PR!
BSD 3-Clause License - see LICENSE
Made with ❤️ by Datalayer