MCP Server Tools¶
axio-tools-mcp lets you plug any
MCP (Model Context Protocol) server into an
Axio agent. Tools are loaded at runtime from the server and wrapped as regular
Tool objects. The agent has no idea they came from MCP.
Install¶
pip install axio-tools-mcp
Loading tools¶
load_mcp_tools connects to one or more servers and returns a flat list of
tools plus the open sessions:
import asyncio
from axio import Agent, MemoryContextStore
from axio_transport_anthropic import AnthropicTransport
from axio_tools_mcp import load_mcp_tools, MCPServerConfig
async def main() -> None:
servers = [
MCPServerConfig(name="fs", command="mcp-server-filesystem", args=["--root", "."]),
]
tools, sessions = await load_mcp_tools(servers)
try:
agent = Agent(
system="You are a helpful assistant.",
tools=tools,
transport=AnthropicTransport(),
)
reply = await agent.run("List the files here.", MemoryContextStore())
print(reply)
finally:
for session in sessions:
await session.close()
asyncio.run(main())
Sessions must be closed when you’re done. Use try/finally as above, or an
AsyncExitStack for cleaner lifecycle management.
Server configuration¶
MCPServerConfig supports two transport types: stdio (local subprocess)
and HTTP.
Stdio (local subprocess)¶
MCPServerConfig(
name="filesystem",
command="mcp-server-filesystem",
args=["--root", "/home/user/project"],
env={"MY_VAR": "value"}, # optional extra environment variables
)
Field |
Description |
|---|---|
|
Server identifier - used as tool name prefix |
|
Executable to run |
|
Arguments passed to the command |
|
Extra environment variables (merged with the current environment) |
|
Handshake timeout in seconds (default: |
|
Pin one MCP revision (default: negotiated, see below) |
HTTP¶
MCPServerConfig(
name="remote",
url="http://mcp-server.internal:3000/mcp",
headers={"Authorization": "Bearer my-token"},
)
Field |
Description |
|---|---|
|
Server identifier - used as tool name prefix |
|
HTTP endpoint URL |
|
HTTP headers sent with every request |
|
Connect and read timeout in seconds (default: |
|
Pin one MCP revision (default: negotiated, see below) |
Protocol revisions¶
The transport is aiohttp-tiny-mcp,
which speaks 2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25 and
2026-07-28.
The handshake starts on 2025-06-18, because every current server answers it.
A server that answers with another revision selects it, and a server that
refuses and names what it supports gets a second handshake on the newest
revision both sides speak. Set protocol_version to pin one revision instead;
a pinned revision is never replaced, and a server that refuses it fails to
connect.
A server that pages its tool list is read to the end, so every page becomes tools.
Tool naming¶
Tools are prefixed with the server name and a double underscore:
{server_name}__{tool_name}
For example, a read_file tool from a server named fs becomes fs__read_file.
This prevents name collisions when multiple servers expose tools with the same name.
Multiple servers¶
Pass multiple configs to load_mcp_tools - tools from all servers are merged
into a single flat list:
tools, sessions = await load_mcp_tools([
MCPServerConfig(name="fs", command="mcp-server-filesystem", args=["--root", "."]),
MCPServerConfig(name="git", command="mcp-server-git"),
MCPServerConfig(name="web", url="http://localhost:4000/mcp"),
])
Error handling¶
load_mcp_tools logs a server that fails to connect and skips it, so the other
servers still load. Connect sessions individually to see the failure itself:
from axio_tools_mcp import MCPSession, MCPServerConfig
session = MCPSession(MCPServerConfig(name="fs", command="mcp-server-filesystem"))
try:
await session.connect()
tools = await session.list_tools()
except Exception as exc:
print(f"Server unavailable: {exc}")
tools = []
A tool that fails on the server returns an error result, and the Axio tool
raises RuntimeError with the text the server sent.