How to Integrate MCP Tools and Hosted MCP Tools into Agents in openai-agents-python

The openai-agents-python SDK enables MCP tool integration by passing MCPServer instances to an Agent's mcp_servers parameter for automatic discovery, or by wrapping specific tools in HostedMCPTool objects for direct invocation.

The OpenAI Agents SDK (openai-agents-python) ships with native support for the Model Context Protocol (MCP), allowing agents to discover and invoke external tools hosted on MCP servers. This integration enables your agents to leverage specialized capabilities from external processes or remote services without hardcoding tool implementations. Whether you need automatic tool discovery from a running server or prefer to explicitly wrap specific MCP tools for direct agent use, the SDK provides dedicated utilities in the agents.mcp package.

MCP Architecture and Core Components

The MCP implementation in openai-agents-python centers on several key classes that handle server lifecycle, tool conversion, and execution flow.

  • MCPServer – Abstract base class in src/agents/mcp/server.py defining the interface for MCP backends, with concrete implementations like MCPServerStdio for local processes.
  • MCPServerManager – Context manager in src/agents/mcp/manager.py that starts and stops one or more MCP servers during an agent run.
  • HostedMCPTool – Wrapper class in src/agents/tool.py that converts an MCP tool definition into a standard function tool the LLM can invoke directly.
  • MCPUtil – Utility class in src/agents/mcp/util.py providing to_function_tool() and to_mcp_tool() for converting between MCP definitions and SDK objects.
  • MCPListToolsItem – Run item type in src/agents/items.py representing the initial tool discovery request sent to MCP servers.

Method 1: Automatic Tool Discovery via MCPServer

The simplest way to integrate MCP tools is to pass a list of MCPServer instances to the Agent constructor via the mcp_servers parameter. The SDK automatically discovers available tools before the first model turn.

When you configure an agent with mcp_servers, the run-loop performs the following actions:

  1. Server initialization – The MCPServerManager initializes all configured servers before the first agent turn.
  2. Tool discovery – The agent emits a MCPListToolsItem to enumerate available tools from each server.
  3. Conversion – The MCPUtil.to_function_tool() helper transforms each McpTool definition (defined in src/agents/tool.py) into a FunctionTool that gets injected into the model request payload.
  4. Invocation – When the LLM calls an MCP tool, the SDK creates an MCPApprovalRequestItem, routes it through HostedMCPTool, and forwards the request to the appropriate MCPServer.
from agents import Agent
from agents.mcp.server import MCPServerStdio

# Configure a local MCP server via stdio

server = MCPServerStdio(
    command="python -m my_mcp_server",
    env={}
)

# Create an agent with automatic MCP tool discovery

agent = Agent(
    name="MCPAgent",
    model="gpt-4o-mini",
    mcp_servers=[server],  # Tools discovered automatically

)

response = agent.run("What tools are available?")

Method 2: Direct Integration with HostedMCPTool

For scenarios requiring explicit tool control or when you want to expose a specific MCP tool without running discovery, use the HostedMCPTool class. This approach wraps a single MCP tool as a standard function tool that you append directly to the agent's tools list.

The HostedMCPTool constructor requires:

  • tool_config: An McpTool definition created via MCPUtil.to_mcp_tool().
  • server_name: The identifier tying the tool to a specific MCPServer instance.
from agents import Agent, HostedMCPTool
from agents.mcp.server import MCPServerStdio
from agents.mcp.util import MCPUtil

server = MCPServerStdio(command="python -m my_mcp_server")

# Define the MCP tool metadata explicitly

tool_config = MCPUtil.to_mcp_tool(
    name="list_documents",
    description="Return a list of document IDs available to the agent.",
    parameters={"type": "object", "properties": {}}
)

# Wrap as a hosted tool

hosted_tool = HostedMCPTool(
    tool_config=tool_config,
    server_name=server.server_name
)

# Add to agent's tools list

agent = Agent(
    name="HostedToolAgent",
    model="gpt-4o-mini",
    mcp_servers=[server],
    tools=[hosted_tool]
)

Understanding the MCP Execution Flow

When an agent invokes an MCP tool, the SDK orchestrates a specific request-response lifecycle defined in src/agents/run_internal/run_steps.py and src/agents/items.py.

Approval Request Phase

The LLM generates a tool call targeting an MCP-hosted function. The SDK creates a ToolRunMCPApprovalRequest (internal step) and surfaces it as an MCPApprovalRequestItem. The HostedMCPTool instance associated with the specific server handles the approval callback.

Execution Phase

Upon approval, the SDK forwards the request to the MCPServer implementation. For stdio servers, this involves writing the JSON-RPC request to the process's stdin and parsing the response from stdout.

Response Phase

The MCP server returns the tool result, which the SDK wraps as an MCPApprovalResponseItem in src/agents/items.py. This item feeds back into the conversation history for the next model turn.

Complete Example: Building an MCP Server and Client

Below is a complete workflow demonstrating both server implementation and agent integration.

Step 1: Create a Simple MCP Server

This example server implements the required list_tools and call_tool methods via stdio:


# my_mcp_server.py

import json
import sys

def handle_request(req: dict) -> dict:
    if req["type"] == "list_tools":
        return {
            "type": "list_tools_response",
            "tools": [
                {
                    "name": "echo",
                    "description": "Return the supplied text unchanged.",
                    "parameters": {
                        "type": "object",
                        "properties": {"text": {"type": "string"}},
                        "required": ["text"]
                    }
                }
            ]
        }
    
    if req["type"] == "call_tool" and req["tool"] == "echo":
        return {
            "type": "call_tool_response",
            "output": req["arguments"]["text"]
        }
    
    return {"type": "error", "message": "unknown request"}

# Process stdin/stdout loop

for line in sys.stdin:
    payload = json.loads(line)
    response = handle_request(payload)
    print(json.dumps(response), flush=True)

Step 2: Register for Automatic Discovery

from agents import Agent
from agents.mcp.server import MCPServerStdio

server = MCPServerStdio(command="python -m my_mcp_server")

agent = Agent(
    name="AutoDiscoveryAgent",
    model="gpt-4o-mini",
    mcp_servers=[server]
)

result = agent.run("Please call the echo tool with text 'Hello MCP'")
print(result.content)  # Output: Hello MCP

Step 3: Use HostedMCPTool for Explicit Registration

from agents import Agent, HostedMCPTool
from agents.mcp.util import MCPUtil
from agents.mcp.server import MCPServerStdio

# Reuse the same server configuration

server = MCPServerStdio(command="python -m my_mcp_server")

# Explicitly define the echo tool

echo_config = MCPUtil.to_mcp_tool(
    name="echo",
    description="Echo back the provided text.",
    parameters={
        "type": "object",
        "properties": {"text": {"type": "string"}},
        "required": ["text"]
    }
)

hosted_echo = HostedMCPTool(
    tool_config=echo_config,
    server_name=server.server_name
)

agent = Agent(
    name="ExplicitToolAgent",
    model="gpt-4o-mini",
    mcp_servers=[server],  # Still required for connection management

    tools=[hosted_echo]
)

Summary

  • Automatic discovery requires passing MCPServer instances to the mcp_servers parameter when constructing an Agent; the SDK handles tool enumeration via MCPListToolsItem and conversion through MCPUtil.to_function_tool() in src/agents/mcp/util.py.
  • Direct tool exposure utilizes HostedMCPTool from src/agents/tool.py to wrap specific MCP tools as regular function tools, bypassing the discovery step while requiring the server in mcp_servers for connection lifecycle management.
  • Server lifecycle is managed by MCPServerManager in src/agents/mcp/manager.py, which orchestrates startup and shutdown of stdio or SSE servers.
  • Execution flow involves MCPApprovalRequestItem and MCPApprovalResponseItem from src/agents/items.py, with the internal step represented by ToolRunMCPApprovalRequest in src/agents/run_internal/run_steps.py.

Frequently Asked Questions

What is the difference between using mcp_servers and HostedMCPTool?

Passing servers to mcp_servers enables automatic tool discovery, where the agent queries the server for all available tools on the first turn using MCPListToolsItem. In contrast, HostedMCPTool allows you to manually expose specific tools by defining the tool schema upfront with MCPUtil.to_mcp_tool() and adding the wrapper directly to the agent's tools list. Both methods require the server to be present in mcp_servers to manage the connection lifecycle.

How does the SDK handle MCP tool approvals?

When an LLM invokes an MCP tool, the SDK creates an MCPApprovalRequestItem (defined in src/agents/items.py) and pauses the model turn. The HostedMCPTool instance associated with the target server processes the request. Once approved (either by default policy or callback), the SDK forwards the request to the MCPServer implementation and wraps the result in an MCPApprovalResponseItem for the next conversation turn.

Can I use remote MCP servers with the openai-agents-python SDK?

Yes. While MCPServerStdio in src/agents/mcp/server.py handles local subprocesses, the abstract MCPServer base class supports custom implementations for remote connections. You can subclass MCPServer to implement SSE (Server-Sent Events) or HTTP-based MCP servers, then pass these instances to the agent's mcp_servers parameter exactly like local stdio servers.

Where does the automatic tool discovery happen in the source code?

Automatic discovery is orchestrated in src/agents/mcp/util.py via MCPUtil.to_function_tool(), which converts McpTool definitions into FunctionTool objects. The discovery request itself originates as a MCPListToolsItem from src/agents/items.py, processed during the agent run initialization phase managed by MCPServerManager in src/agents/mcp/manager.py.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →