Skip to content

Documentation navigation

Connecting MCP Servers

Connect external Model Context Protocol tool servers to your agents.

#Connecting MCP Servers

Your agent's tools do not have to be functions you wrote. With the Model Context Protocol (MCP), you can plug an agent into tools that someone else built and runs (a filesystem server, a calendar or email integration, an internal data service), and the agent uses them exactly like the tools you define with @agent.toolify().

This guide explains the mental model: what an MCP connection is, where the tools actually run, how you choose a transport, and how you authenticate to a server you do not own. For the exhaustive field reference see the MCP API Reference; for copy-paste runnable setups see the MCP examples.

#What This Is and Why It Matters

MCP is an open standard for exposing tools to AI agents. An MCP server is a small program that advertises a set of tools and knows how to run them. There is a growing ecosystem of these servers (official ones, community ones, and ones you write yourself), and they all speak the same protocol.

The point for you is reuse. Instead of writing a wrapper around the Google Calendar API or a file-reading tool from scratch, you point your agent at an MCP server that already does it. The agent then sees those tools alongside your own and decides when to call them.

You describe a connection with the public MCPServer model and register it on an Agent (or a Swarm) with register_mcp_servers(...). From that point the server's tools are part of the scope's tool surface, indistinguishable to the model from the functions you wrote yourself.

Python
from maivn import Agent, MCPServer
from maivn.messages import HumanMessage

agent = Agent(name='assistant', api_key='...')

agent.register_mcp_servers(MCPServer(
    name='calendar',
    transport='http',
    url='https://mcp.example.com/api',
))

response = agent.invoke([
    HumanMessage(content='What meetings do I have tomorrow?')
])
print(response.response)

#Where MCP Tools Run (the Trust Boundary)

This is the most important thing to understand before you wire up a server: MCP tool calls are initiated by the SDK in your application environment, not by mAIvn's servers.

  • A stdio server launches as a local subprocess on your machine.
  • An http server is an endpoint you configure. Its tool code and data handling run wherever that endpoint is hosted.

The mAIvn runtime receives the tool schemas (names, descriptions, and argument shapes) and orchestrates which tool the agent should call. The SDK then performs the configured stdio or HTTP call. Credentials are not sent to mAIvn's orchestrator, but an HTTP MCP endpoint receives the headers and tool inputs you send it, so assess that endpoint as a separate data custodian.

That boundary is also why authentication to an external server is entirely yours to manage (see Authenticating to the External Server): the credentials are your credentials for that provider and are unrelated to the mAIvn api_key you pass to the SDK.

#Choosing a Transport

MCPServer supports two transports, and the choice is about where the server lives:

  • stdio (the default) — launch a local subprocess and talk to it over stdin/stdout. Use this for servers you run on the same machine as your agent. Requires either a command to run or an auto_setup block.
  • http — connect to a long-running endpoint you control. Use this for a service that runs elsewhere, or one shared across several agents. Requires a url.

From the SDK's perspective the two are interchangeable once connected. The agent calls the tools the same way regardless of transport. You can register one server or several at once and mix transports freely; the examples page shows a single agent driving both at once.

Construction validates the transport literal and non-empty name/separator. Missing HTTP URLs or stdio commands are detected when discovery or a call creates the runtime, not at construction. Rate-limit fields do not enforce a quota.

Set stdio_response_timeout_seconds explicitly to bound each response wait; None waits indefinitely. The SDK does not warn when it is omitted. HTTP uses request_timeout_seconds or 30 seconds when unset.

#Installing third-party servers on demand

Many MCP servers are distributed as Python packages you would normally install and launch yourself. An MCPAutoSetup block lets the SDK resolve and run the package for you (via uvx, into an isolated environment), so you do not hand-write command and args and you do not pollute your global Python. Auto-setup is used for stdio servers; HTTP ignores it. The uvx binary must be available on PATH or selected with uvx_command. Set the working directory on MCPServer; the compatibility MCPAutoSetup.working_dir field is not applied by this launcher. See the API reference for the fields and the examples page for a working fetch-server setup.

#Naming and Reframing the Server's Tools

When the SDK discovers a server's tools it gives each one a prefixed name so tools from different servers (and your own functions) never collide. By default the prefix is the server's name, joined with __. A server named tools exposing read_file surfaces as tools__read_file. You can change the prefix and separator, or drop the prefix entirely to keep the server's original tool names. The SDK replaces spaces and hyphens with underscores, but does not perform full provider-name validation. Choose unique names using letters, digits, and underscores and keep the resulting prefix-plus-tool name within provider limits.

Current MCP compilation does not apply tool_overrides, even though the model accepts that compatibility field. It does not validate unknown override keys or apply the server's output schema. Use an application wrapper for custom names, output validation, or retry behavior.

Use default_tool_args and tool_defaults for configured arguments. In this SDK, those values also become injected arguments: they are hidden from the model by default and win over model-supplied values. Explicit injected_tool_args wins over both. See the API reference.

#Authenticating to the External Server

The credentials for an external MCP server are your credentials for that provider, unrelated to your mAIvn api_key, and they stay in your environment. How you present them depends on the transport.

HTTP servers take credentials through headers, typically a bearer token. Read the token from the environment (or your secret manager) rather than hard-coding it. Any other headers the provider expects (API keys, tenant identifiers) go in the same dictionary.

Python
import os
from maivn import MCPServer

MCPServer(
    name='calendar',
    transport='http',
    url='https://mcp.example.com/api',
    headers={'Authorization': f'Bearer {os.environ["CALENDAR_TOKEN"]}'},
)

stdio servers read credentials from the subprocess environment. By default the SDK launches the subprocess with only a minimal runtime baseline (such as PATH), so a third-party server does not silently inherit every secret in your shell. You opt the credentials in explicitly, either by setting them with env, or by forwarding named variables from the parent process with inherit_env_allowlist:

Python
from maivn import MCPServer

# Pass exactly the variables the server needs...
MCPServer(
    name='local_tools',
    transport='stdio',
    command='python',
    args=['-m', 'my_mcp_server'],
    env={'PROVIDER_API_KEY': 'explicit-token'},
)

# ...or forward specific variables from the parent environment
MCPServer(
    name='local_tools',
    transport='stdio',
    command='python',
    args=['-m', 'my_mcp_server'],
    inherit_env_allowlist=['PROVIDER_API_KEY'],
)

Set inherit_env=True only for trusted subprocesses that genuinely need your full shell environment.

#When an MCP Call Fails

HTTP failures raise HTTPX errors. A JSON-RPC error response raises MCPRuntimeError; malformed responses can raise TypeError. A tool's MCP result object is otherwise returned by the transport.

The compatibility fields raise_on_tool_error, soft_error_handling, max_calls_per_minute, and max_calls_per_day are not used by this transport. They do not add retries, scan response bodies, or pace calls. Put those controls in the MCP server or your application when required.

#Lifecycle

Close each MCP server explicitly, and close the HTTP client your application owns. The current Agent.close() and Swarm.close() compatibility methods do nothing; there is no close_mcp_servers() method.

Python
try:
    response = agent.invoke('Summarize the available records.')
finally:
    for server in agent.list_mcp_servers():
        server.close()
    agent.client.close()

When agents share a client, close it once at the owning application's shutdown, after all users have finished. MCPServer.close() terminates its active subprocess or closes its HTTP connection.

  • MCP API Reference — every MCPServer, MCPAutoSetup, and MCPSoftErrorHandling field, the full parameter tables, and the tool-name mapping and override semantics.
  • MCP Examples — runnable stdio, HTTP, multi-server, uvx, rate-limit, and structured-output setups you can copy.
  • Tools and Dependencies — how MCP tools sit alongside your own functions, and how application wrappers customize tool behavior.
  • Multi-Agent — register MCP servers on the agents inside a Swarm.
  • Core Concepts — the scope/tool mental model that MCP plugs into.
  • SDK Overview — start here if MCP is your first stop in the SDK.