Skip to main content
Lesson 5 of 14 · MCP for Developers: Servers and Integrations

RunContext: Manage the MCP Client and the Agent

Lesson 5 of 14 Updated November 2, 2026 Developer
On this page
  1. The conductor of your agent
  2. Create the agent
  3. Open the context
  4. Register an MCP client
  5. Add local functions
  6. Start the conversation
  7. Key takeaways

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 with context manager
  • register_mcp_client connects an MCP server and discovers its tools
  • register_func registers local Python functions as tools
  • continue_on_fn_error=True ensures your agent’s resilience
  • The entire workflow is asynchronous (async/await)