MCP (Model Context Protocol) Integration in the OpenAI Agents SDK enables agents to use tools provided by MCP servers. Think of MCP as a "universal tool protocol" that allows different systems to expose tools to AI models in a standardized way. This is essential for integrating with external tool providers, sharing tools across applications, and building a tool ecosystem.
Core Concepts
What is MCP?
MCP (Model Context Protocol) is:
A protocol for exposing tools to AI models
Standardized - consistent interface across providers
Language-agnostic - works with any programming language
Extensible - supports custom tool types
Community-driven - open ecosystem of tool providers
from agents.mcp import ToolFilterStatic
filter_config = ToolFilterStatic(
include=["tool1", "tool2"], # Only include these
exclude=["tool3"], # Exclude these
)
config = MCPConfig(
tool_filter=filter_config,
)
Dynamic Tool Filter
Filter tools dynamically:
Python
from agents.mcp import ToolFilterCallable, ToolFilterContext
defdynamic_filter(context: ToolFilterContext) -> ToolFilter:
"""Dynamic tool filtering."""# Filter based on contextif context.context.user_tier == "free":
return ToolFilterStatic(include=["basic_tool"])
else:
return ToolFilterStatic(include=["basic_tool", "premium_tool"])
config = MCPConfig(
tool_filter=dynamic_filter,
)
Tool Filter Context
Context available for filtering:
Python
@dataclassclassToolFilterContext:
agent: Agent
"""The agent requesting tools."""
context: Any"""User-provided context."""
tool_name: str | None"""Specific tool name if filtering one tool."""
MCP Tool Metadata
MCPToolMetaContext
Context for tool metadata resolution:
Python
@dataclassclassMCPToolMetaContext:
agent: Agent
"""The agent."""
tool_name: str"""The tool name."""
original_schema: dict"""The original schema from MCP."""
result = await Runner.run(agent, input)
# Trace includes MCP tool callsfor span in result.trace.spans:
if span.name.startswith("mcp_"):
print(f"MCP operation: {span.name}")
MCP Span Types
MCP creates specific spans:
mcp_list_tools - Listing available tools
mcp_call_tool - Calling a tool
mcp_approve - Approval process
MCP Best Practices
1. Use Appropriate Server Type
Choose the right server type:
Python
# Good - local server
server = MCPServerStdio(params=...)
# Good - remote server
server = MCPServerSse(params=...)
# Avoid - wrong type for use case
server = MCPServerStdio(params=...) # For remote server
2. Filter Tools
Filter tools to reduce complexity:
Python
# Good - filter tools
config = MCPConfig(
tool_filter=ToolFilterStatic(include=["tool1", "tool2"]),
)
# Avoid - all tools
config = MCPConfig() # Might be too many tools
# Good - approval for sensitive tools
server = MCPServerStdio(
params=...,
approval=approve_sensitive,
)
# Avoid - no approval
server = MCPServerStdio(params=...) # All tools auto-approved
@pytest.mark.asyncioasyncdeftest_mcp_tool():
"""Test MCP tool call."""
server = MockMCPServer()
agent = Agent(mcp_servers=[server])
result = await Runner.run(agent, "Call the MCP tool")
assert"mcp_result"in result.final_output
Mock MCP Server
Mock MCP server for testing:
Python
classMockMCPServer:
"""Mock MCP server for testing."""asyncdeflist_tools(self):
return [MockTool("test_tool")]
asyncdefcall_tool(self, name, arguments):
returnf"Mock result for {name}"
MCP and Security
Secure Connections
Use secure connections for MCP:
Python
# Good - secure connection
server = MCPServerSse(
params=MCPServerSseParams(
url="https://example.com/mcp",
headers={"Authorization": "Bearer token"},
)
)
# Avoid - insecure connection
server = MCPServerSse(
params=MCPServerSseParams(
url="http://example.com/mcp", # Not secure
)
)
Tool Validation
Validate MCP tools:
Python
defvalidate_mcp_tool(tool: MCPServerTool) -> bool:
"""Validate MCP tool."""# Check tool schemaifnot tool.input_schema:
returnFalse# Check tool nameifnot re.match(r'^[a-z_]+$', tool.name):
returnFalsereturnTrue
config = MCPConfig(
tool_filter=lambda ctx: [t for t in tools if validate_mcp_tool(t)],
)