Agno’s MCP integration also supports handling connections to multiple servers, specifying server parameters and using your own MCP servers:
Connecting to Multiple MCP Servers
You can use multiple MCP servers in a single agent by using the MultiMCPTools
class.
import asyncio
import os
from agno.agent import Agent
from agno.tools.mcp import MultiMCPTools
async def run_agent(message: str) -> None:
"""Run the Airbnb and Google Maps agent with the given message."""
env = {
**os.environ,
"GOOGLE_MAPS_API_KEY": os.getenv("GOOGLE_MAPS_API_KEY"),
}
async with MultiMCPTools(
[
"npx -y @openbnb/mcp-server-airbnb --ignore-robots-txt",
"npx -y @modelcontextprotocol/server-google-maps",
],
env=env,
) as mcp_tools:
agent = Agent(
tools=[mcp_tools],
markdown=True,
show_tool_calls=True,
)
await agent.aprint_response(message, stream=True)
# Example usage
if __name__ == "__main__":
# Pull request example
asyncio.run(
run_agent(
"What listings are available in Cape Town for 2 people for 3 nights from 1 to 4 August 2025?"
)
)
Understanding Server Parameters
The recommended way to configure MCPTools
or MultiMCPTools
is to use the command
or url
parameters.
Alternatively, you can use the server_params
parameter with MCPTools
to configure the connection to the MCP server in more detail.
When using the stdio transport, the server_params
parameter should be an instance of StdioServerParameters
. It contains the following keys:
command
: The command to run the MCP server.
- Use
npx
for mcp servers that can be installed via npm (or node
if running on Windows).
- Use
uvx
for mcp servers that can be installed via uvx.
args
: The arguments to pass to the MCP server.
env
: Optional environment variables to pass to the MCP server. Remember to include all current environment variables in the env
dictionary. If env
is not provided, the current environment variables will be used.
e.g.
{
**os.environ,
"GOOGLE_MAPS_API_KEY": os.getenv("GOOGLE_MAPS_API_KEY"),
}
When using the SSE transport, the server_params
parameter should be an instance of SSEClientParams
. It contains the following fields:
url
: The URL of the MCP server.
headers
: Headers to pass to the MCP server (optional).
timeout
: Timeout for the connection to the MCP server (optional).
sse_read_timeout
: Timeout for the SSE connection itself (optional).
When using the Streamable HTTP transport, the server_params
parameter should be an instance of StreamableHTTPClientParams
. It contains the following fields:
url
: The URL of the MCP server.
headers
: Headers to pass to the MCP server (optional).
timeout
: Timeout for the connection to the MCP server (optional).
sse_read_timeout
: how long (in seconds) the client will wait for a new event before disconnecting. All other HTTP operations are controlled by timeout
(optional).
terminate_on_close
: Whether to terminate the connection when the client is closed (optional).
More Flexibility
You can also create the MCP server yourself and pass it to the MCPTools
constructor.
import asyncio
from pathlib import Path
from textwrap import dedent
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.mcp import MCPTools
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def create_filesystem_agent(session):
"""Create and configure a filesystem agent with MCP tools."""
# Initialize the MCP toolkit
mcp_tools = MCPTools(session=session)
await mcp_tools.initialize()
# Create an agent with the MCP toolkit
return Agent(
model=OpenAIChat(id="gpt-4o"),
tools=[mcp_tools],
instructions=dedent("""\
You are a filesystem assistant. Help users explore files and directories.
- Navigate the filesystem to answer questions
- Use the list_allowed_directories tool to find directories that you can access
- Provide clear context about files you examine
- Use headings to organize your responses
- Be concise and focus on relevant information\
"""),
markdown=True,
show_tool_calls=True,
)
async def run_agent(message: str) -> None:
"""Run the filesystem agent with the given message."""
# Initialize the MCP server
server_params = StdioServerParameters(
command="npx",
args=[
"-y",
"@modelcontextprotocol/server-filesystem",
str(Path(__file__).parent.parent.parent.parent), # Set this to the root of the project you want to explore
],
)
# Create a client session to connect to the MCP server
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
agent = await create_filesystem_agent(session)
# Run the agent
await agent.aprint_response(message, stream=True)
# Example usage
if __name__ == "__main__":
# Basic example - exploring project license
asyncio.run(run_agent("What is the license for this project?"))