| description | Model Context Protocol client and server for tool interop | ||
|---|---|---|---|
| tags |
|
Import: from selectools.mcp import MCPClient
Stability: beta
from selectools import Agent, AgentConfig
from selectools.providers.stubs import LocalProvider
from selectools.mcp import mcp_tools, MCPServerConfig
# Connect to an MCP server and use its tools
with mcp_tools(MCPServerConfig(command="python", args=["server.py"])) as tools:
agent = Agent(
tools=tools,
provider=LocalProvider(),
config=AgentConfig(model="gpt-4o-mini"),
)
result = agent.run("Search for Python tutorials")
print(result.content)!!! tip "See Also"
- Tools Module -- custom tool creation with @tool
- Agent Module -- the Agent class that consumes MCP tools
Added in: v0.17.1
Connect to any MCP-compatible tool server and expose selectools tools as MCP servers. Requires pip install selectools[mcp].
from selectools import Agent, AgentConfig
from selectools.providers import OpenAIProvider
from selectools.mcp import mcp_tools, MCPServerConfig
# Connect to an MCP server and get tools
with mcp_tools(MCPServerConfig(command="python", args=["server.py"])) as tools:
agent = Agent(
provider=OpenAIProvider(),
config=AgentConfig(model="gpt-4.1-mini"),
tools=tools,
)
result = agent.run("Search for Python tutorials")MCP tools are regular selectools Tool objects. All existing features work automatically: traces, observers, guardrails, policies, evals, cost tracking.
from selectools.mcp import MCPServerConfig
# stdio transport (local subprocess)
config = MCPServerConfig(
command="python",
args=["my_server.py"],
name="search",
)
# Streamable HTTP transport (remote)
config = MCPServerConfig(
url="http://api.example.com/mcp",
transport="streamable-http",
headers={"Authorization": "Bearer token"},
name="api",
)| Field | Default | Description |
|---|---|---|
name |
Auto-generated | Human-readable server name |
transport |
"stdio" |
"stdio" or "streamable-http" |
command |
Command for stdio (e.g., "python") |
|
args |
[] |
Command arguments |
url |
URL for HTTP transport | |
headers |
None |
HTTP headers (auth, etc.) |
timeout |
30.0 |
Connection/call timeout (seconds) |
max_retries |
2 |
Retries on transport failure |
auto_reconnect |
True |
Auto-reconnect on failure |
circuit_breaker_threshold |
3 |
Failures before circuit opens |
circuit_breaker_cooldown |
60.0 |
Seconds before retry after circuit opens |
screen_output |
True |
Screen outputs for prompt injection |
cache_tools |
True |
Cache tool list after first fetch |
Direct client for advanced use cases.
from selectools.mcp import MCPClient, MCPServerConfig
# Async context manager (preferred)
async with MCPClient(config) as client:
tools = await client.list_tools()
result = await client._call_tool("search", {"query": "python"})
# Sync context manager
with MCPClient(config) as client:
tools = client.list_tools_sync()If an MCP server fails repeatedly, the circuit breaker opens and tool calls fail immediately instead of waiting for timeouts:
config = MCPServerConfig(
command="python",
args=["unreliable_server.py"],
circuit_breaker_threshold=3, # Open after 3 failures
circuit_breaker_cooldown=60.0, # Retry after 60 seconds
)config = MCPServerConfig(
command="python",
args=["server.py"],
max_retries=3, # Retry up to 3 times
retry_backoff=1.0, # 1s, 2s, 4s exponential backoff
)Connect to multiple MCP servers simultaneously.
from selectools.mcp import MultiMCPClient, MCPServerConfig
async with MultiMCPClient([
MCPServerConfig(command="python", args=["search.py"], name="search"),
MCPServerConfig(url="http://api.example.com/mcp",
transport="streamable-http", name="api"),
]) as client:
tools = await client.list_all_tools()
# Tools are prefixed: search_web_search, api_query, etc.
agent = Agent(provider=p, tools=tools, config=c)If one server fails to connect, the others still work:
async with MultiMCPClient(configs) as client:
print(f"Active: {client.active_servers}") # ["search"]
print(f"Failed: {client.failed_servers}") # ["api"]
tools = await client.list_all_tools() # Only search toolsTool names are prefixed with the server name to avoid collisions:
MultiMCPClient(configs, prefix_tools=True) # search_query, api_fetch
MultiMCPClient(configs, prefix_tools=False) # Raises ValueError on collisionTurn any selectools @tool function into an MCP server:
from selectools import tool
from selectools.mcp import MCPServer
@tool(description="Get weather for a city")
def get_weather(city: str) -> str:
return f"72°F in {city}"
@tool(description="Search documents")
def search(query: str) -> str:
return f"Results for: {query}"
server = MCPServer(tools=[get_weather, search])
server.serve(transport="stdio")
# or: server.serve(transport="streamable-http", port=8080)This server can be used by Claude Desktop, Cursor, VS Code, or other selectools agents.
import asyncio
from selectools import Agent, AgentConfig, tool
from selectools.providers import AnthropicProvider
from selectools.mcp import MCPClient, MCPServerConfig
@tool(description="Local calculator")
def multiply(a: int, b: int) -> str:
return str(a * b)
async def main():
config = MCPServerConfig(command="python", args=["math_server.py"])
async with MCPClient(config) as client:
mcp_tools = await client.list_tools()
# Mix local + MCP tools
agent = Agent(
provider=AnthropicProvider(),
config=AgentConfig(model="claude-haiku-4-5"),
tools=[multiply] + mcp_tools,
)
# Agent automatically selects the right tool
result = await agent.arun("Add 5 and 3") # Uses MCP 'add' tool
result2 = await agent.arun("Multiply 6 by 7") # Uses local 'multiply'
asyncio.run(main())Evaluate MCP-powered agents like any other:
from selectools.evals import EvalSuite, TestCase
suite = EvalSuite(
agent=agent, # Agent with MCP tools
cases=[
TestCase(input="Add 10 and 20", expect_tool="add"),
TestCase(input="Search for Python", expect_tool="search"),
],
)
report = suite.run()
print(report.accuracy)| Symbol | Description |
|---|---|
MCPServerConfig(...) |
Server connection configuration |
MCPClient(config) |
Single-server client |
MultiMCPClient(configs) |
Multi-server client |
MCPServer(tools) |
Expose tools as MCP server |
mcp_tools(config) |
Context manager shortcut |
MCPError |
Base MCP exception |
MCPConnectionError |
Connection failure |
MCPToolError |
Tool call failure |
| # | File | Description |
|---|---|---|
| 41 | 41_mcp_client.py |
Connect to an MCP server and use its tools |
| 42 | 42_mcp_server.py |
Expose selectools tools as an MCP server |