[4/n] Add docs for MCP (#338)

Just adding docs.

(Repeat of #324)
This commit is contained in:
Rohan Mehta 2025-03-25 13:27:15 -04:00 committed by GitHub
commit 362a9dc078
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 69 additions and 103 deletions

51
docs/mcp.md Normal file
View file

@ -0,0 +1,51 @@
# Model context protocol
The [Model context protocol](https://modelcontextprotocol.io/introduction) (aka MCP) is a way to provide tools and context to the LLM. From the MCP docs:
> MCP is an open protocol that standardizes how applications provide context to LLMs. Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools.
The Agents SDK has support for MCP. This enables you to use a wide range of MCP servers to provide tools to your Agents.
## MCP servers
Currently, the MCP spec defines two kinds of servers, based on the transport mechanism they use:
1. **stdio** servers run as a subprocess of your application. You can think of them as running "locally".
2. **HTTP over SSE** servers run remotely. You connect to them via a URL.
You can use the [`MCPServerStdio`][agents.mcp.server.MCPServerStdio] and [`MCPServerSse`][agents.mcp.server.MCPServerSse] classes to connect to these servers.
For example, this is how you'd use the [official MCP filesystem server](https://www.npmjs.com/package/@modelcontextprotocol/server-filesystem).
```python
async with MCPServerStdio(
params={
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", samples_dir],
}
) as server:
tools = await server.list_tools()
```
## Using MCP servers
MCP servers can be added to Agents. The Agents SDK will call `list_tools()` on the MCP servers each time the Agent is run. This makes the LLM aware of the MCP server's tools. When the LLM calls a tool from an MCP server, the SDK calls `call_tool()` on that server.
```python
agent=Agent(
name="Assistant",
instructions="Use the tools to achieve the task",
mcp_servers=[mcp_server_1, mcp_server_2]
)
```
## Caching
Every time an Agent runs, it calls `list_tools()` on the MCP server. This can be a latency hit, especially if the server is a remote server. To automatically cache the list of tools, you can pass `cache_tools_list=True` to both [`MCPServerStdio`][agents.mcp.server.MCPServerStdio] and [`MCPServerSse`][agents.mcp.server.MCPServerSse]. You should only do this if you're certain the tool list will not change.
If you want to invalidate the cache, you can call `invalidate_tools_cache()` on the servers.
## End-to-end example
View complete working examples at [examples/mcp](https://github.com/openai/openai-agents-python/tree/main/examples/mcp).

3
docs/ref/mcp/server.md Normal file
View file

@ -0,0 +1,3 @@
# `MCP Servers`
::: agents.mcp.server

3
docs/ref/mcp/util.md Normal file
View file

@ -0,0 +1,3 @@
# `MCP Util`
::: agents.mcp.util

View file

@ -28,6 +28,7 @@ nav:
- results.md - results.md
- streaming.md - streaming.md
- tools.md - tools.md
- mcp.md
- handoffs.md - handoffs.md
- tracing.md - tracing.md
- context.md - context.md
@ -60,6 +61,8 @@ nav:
- ref/models/interface.md - ref/models/interface.md
- ref/models/openai_chatcompletions.md - ref/models/openai_chatcompletions.md
- ref/models/openai_responses.md - ref/models/openai_responses.md
- ref/mcp/server.md
- ref/mcp/util.md
- Tracing: - Tracing:
- ref/tracing/index.md - ref/tracing/index.md
- ref/tracing/create.md - ref/tracing/create.md
@ -107,6 +110,8 @@ plugins:
show_signature_annotations: true show_signature_annotations: true
# Makes the font sizes nicer # Makes the font sizes nicer
heading_level: 3 heading_level: 3
# Show inherited members
inherited_members: true
extra: extra:
# Remove material generation message in footer # Remove material generation message in footer

View file

@ -1,94 +0,0 @@
import functools
import json
from typing import Any
from mcp.types import Tool as MCPTool
from .. import _debug
from ..exceptions import AgentsException, ModelBehaviorError, UserError
from ..logger import logger
from ..run_context import RunContextWrapper
from ..tool import FunctionTool, Tool
from .server import MCPServer
class MCPUtil:
"""Set of utilities for interop between MCP and Agents SDK tools."""
@classmethod
async def get_all_function_tools(cls, servers: list[MCPServer]) -> list[Tool]:
"""Get all function tools from a list of MCP servers."""
tools = []
tool_names: set[str] = set()
for server in servers:
server_tools = await cls.get_function_tools(server)
server_tool_names = {tool.name for tool in server_tools}
if len(server_tool_names & tool_names) > 0:
raise UserError(
f"Duplicate tool names found across MCP servers: "
f"{server_tool_names & tool_names}"
)
tool_names.update(server_tool_names)
tools.extend(server_tools)
return tools
@classmethod
async def get_function_tools(cls, server: MCPServer) -> list[Tool]:
"""Get all function tools from a single MCP server."""
tools = await server.list_tools()
return [cls.to_function_tool(tool, server) for tool in tools]
@classmethod
def to_function_tool(cls, tool: MCPTool, server: MCPServer) -> FunctionTool:
"""Convert an MCP tool to an Agents SDK function tool."""
invoke_func = functools.partial(cls.invoke_mcp_tool, server, tool)
return FunctionTool(
name=tool.name,
description=tool.description or "",
params_json_schema=tool.inputSchema,
on_invoke_tool=invoke_func,
strict_json_schema=False,
)
@classmethod
async def invoke_mcp_tool(
cls, server: MCPServer, tool: MCPTool, context: RunContextWrapper[Any], input_json: str
) -> str:
"""Invoke an MCP tool and return the result as a string."""
try:
json_data: dict[str, Any] = json.loads(input_json) if input_json else {}
except Exception as e:
if _debug.DONT_LOG_TOOL_DATA:
logger.debug(f"Invalid JSON input for tool {tool.name}")
else:
logger.debug(f"Invalid JSON input for tool {tool.name}: {input_json}")
raise ModelBehaviorError(
f"Invalid JSON input for tool {tool.name}: {input_json}"
) from e
if _debug.DONT_LOG_TOOL_DATA:
logger.debug(f"Invoking MCP tool {tool.name}")
else:
logger.debug(f"Invoking MCP tool {tool.name} with input {input_json}")
try:
result = await server.call_tool(tool.name, json_data)
except Exception as e:
logger.error(f"Error invoking MCP tool {tool.name}: {e}")
raise AgentsException(f"Error invoking MCP tool {tool.name}: {e}") from e
if _debug.DONT_LOG_TOOL_DATA:
logger.debug(f"MCP tool {tool.name} completed.")
else:
logger.debug(f"MCP tool {tool.name} returned {result}")
# The MCP tool result is a list of content items, whereas OpenAI tool outputs are a single
# string. We'll try to convert.
if len(result.content) == 1:
return result.content[0].model_dump_json()
elif len(result.content) > 1:
return json.dumps([item.model_dump() for item in result.content])
else:
logger.error(f"Errored MCP tool result: {result}")
return "Error running tool."

View file

@ -175,10 +175,10 @@ class MCPServerStdio(_MCPServerWithClientSession):
"""Create a new MCP server based on the stdio transport. """Create a new MCP server based on the stdio transport.
Args: Args:
params: The params that configure the server. This includes: params: The params that configure the server. This includes the command to run to
- The command (e.g. `python` or `node`) that starts the server. start the server, the args to pass to the command, the environment variables to
- The args to pass to the server command (e.g. `foo.py` or `server.js`). set for the server, the working directory to use when spawning the process, and
- The environment variables to set for the server. the text encoding used when sending/receiving messages to the server.
cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
cached and only fetched from the server once. If `False`, the tools list will be cached and only fetched from the server once. If `False`, the tools list will be
fetched from the server on each call to `list_tools()`. The cache can be fetched from the server on each call to `list_tools()`. The cache can be
@ -235,11 +235,9 @@ class MCPServerSse(_MCPServerWithClientSession):
"""Create a new MCP server based on the HTTP with SSE transport. """Create a new MCP server based on the HTTP with SSE transport.
Args: Args:
params: The params that configure the server. This includes: params: The params that configure the server. This includes the URL of the server,
- The URL of the server. the headers to send to the server, the timeout for the HTTP request, and the
- The headers to send to the server. timeout for the SSE connection.
- The timeout for the HTTP request.
- The timeout for the SSE connection.
cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be cache_tools_list: Whether to cache the tools list. If `True`, the tools list will be
cached and only fetched from the server once. If `False`, the tools list will be cached and only fetched from the server once. If `False`, the tools list will be