RunContext: Manage the MCP Client and the Agent
On this page
The conductor of your agent
The RunContext is the component that holds everything together. It connects your AI agent to MCP servers and manages their entire lifecycle: connecting to servers, registering tools, executing conversations, retrieving results, and shutting down cleanly. In the Mistral SDK, it takes the form of an asynchronous context manager that encapsulates all this logic. You open a block, declare what the agent is allowed to use, have your conversation, and everything closes automatically when you exit.
Create the agent
The RunContext does not create the agent; it attaches to one. Your first step is therefore to instantiate an agent via the API.
from mistralai.client import Mistral
# Initialize the Mistral client
client = Mistral(api_key="YOUR_API_KEY")
# Create an agent
agent = client.beta.agents.create(
model="mistral-medium-latest",
name="assistant-mcp",
instructions="You are an assistant capable of using MCP tools.",
)
print(f"Agent created: {agent.id}")
This agent is a persistent entity on the Mistral side: it has a model, a name, and system instructions, and it survives beyond your script. MCP tools, however, are not attached to the agent. Instead, the RunContext provides them dynamically at each execution. This decoupling lets you run the same agent with different tools depending on the context.
Open the context
You use RunContext with async with, which guarantees resource release even if an exception occurs.
from mistralai.extra.run.context import RunContext
from pydantic import BaseModel
# Optional: define a structured output format
class WeatherResult(BaseModel):
location: str
temperature: float
description: str
async with RunContext(
agent_id=agent.id,
output_format=WeatherResult, # Structured format (optional)
continue_on_fn_error=True, # Continue if a tool fails
) as run_ctx:
# Here, register MCP clients and start conversations
pass
Three parameters control this behavior. agent_id specifies the agent you created earlier. output_format accepts a Pydantic model and constrains the final response to that structure—valuable when the output feeds another program rather than a human. Finally, continue_on_fn_error decides what happens to the conversation when a tool raises an error: if set to True, the context continues, and the model receives the error message just as it would a result.
Register an MCP client
Once the context is open, you declare your MCP clients within it.
from mcp import StdioServerParameters
from mistralai.extra.mcp.stdio import MCPClientSTDIO
# Configure the local server
server_params = StdioServerParameters(
command="python",
args=["weather_server.py"],
)
mcp_client = MCPClientSTDIO(stdio_params=server_params)
async with RunContext(
agent_id=agent.id,
continue_on_fn_error=True,
) as run_ctx:
# Register the MCP client
await run_ctx.register_mcp_client(mcp_client=mcp_client)
This single call to register_mcp_client triggers a complete sequence: launching the server process in STDIO mode, negotiating capabilities, retrieving the list of tools, and making those tools available to the model for upcoming conversations. You do not need to write any of this by hand.
You are also not limited to a single server. A single RunContext can aggregate multiple sources, and the model sees the union of their tools as a single catalog:
async with RunContext(agent_id=agent.id) as run_ctx:
await run_ctx.register_mcp_client(mcp_client=mcp_client_weather)
await run_ctx.register_mcp_client(mcp_client=mcp_client_github)
await run_ctx.register_mcp_client(mcp_client=mcp_client_calendar)
Add local functions
Not every capability needs to become an MCP server. For a short function specific to this script, the register_func decorator is enough to expose it to the model as a standard tool.
import random
async with RunContext(agent_id=agent.id) as run_ctx:
await run_ctx.register_mcp_client(mcp_client=mcp_client)
@run_ctx.register_func
def get_user_location(username: str) -> str:
"""Retrieves a user's location.
Args:
username: The username
Returns:
The user's city
"""
locations = {"alice": "Paris", "bob": "Lyon", "charlie": "Marseille"}
return locations.get(username, "Unknown")
From the model’s perspective, there is no difference: it simply sees one more tool. The difference is for you—these functions run in your Python process, without an external server, so they are not reusable outside this script.
Start the conversation
Once the context is populated, all that remains is to talk.
async with RunContext(agent_id=agent.id) as run_ctx:
await run_ctx.register_mcp_client(mcp_client=mcp_client)
# Synchronous execution (waits for the full response)
run_result = await client.beta.conversations.run_async(
run_ctx=run_ctx,
inputs="What is the weather in Paris?",
)
print(run_result.output)
Behind this call, the model analyzes the question, consults the available tools—both from MCP servers and local functions—calls the ones it deems necessary, and then drafts its response based on the results obtained.
The entire cycle looks like this:
1. Create the agent (client.beta.agents.create)
↓
2. Open the RunContext (async with RunContext)
↓
3. Register MCP clients (register_mcp_client)
↓
4. Register local functions (register_func)
↓
5. Start conversations (conversations.run_async)
↓
6. Automatic cleanup (end of context manager)
When you exit the block, the context stops all STDIO server processes it launched—no orphaned Python processes left hanging after an exception.
A final word on continue_on_fn_error=True, whose value is most apparent in production. Without it, the slightest error in a tool interrupts the entire conversation, leaving the user staring at an exception. With it, the model receives the error clearly and has room to maneuver: it can rephrase its request with different arguments, fall back to another tool, or simply explain to the user what failed. An agent that says “the weather service is not responding” is infinitely better than an agent that crashes.
Key takeaways
- The RunContext orchestrates communication between the agent and MCP servers
- Use it as an
async withcontext manager register_mcp_clientconnects an MCP server and discovers its toolsregister_funcregisters local Python functions as toolscontinue_on_fn_error=Trueensures your agent’s resilience- The entire workflow is asynchronous (async/await)