Skip to content

feat: support in-process fastmcp server #546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions examples/mcp/in_process/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# MCP In-Process Example

This example uses an in-process fastmcp server in [server.py](server.py).

Run the example via:

```
uv run python -m examples.mcp.in_process.main
```

## Details

The example uses the `FastMCPServer` class from `agents.mcp.fastmcp`. The server is invoked in-process like a function call.

Empty file.
52 changes: 52 additions & 0 deletions examples/mcp/in_process/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import asyncio
import os
import shutil
import subprocess
import time
from typing import Any

from agents import Agent, Runner, gen_trace_id, trace
from agents.mcp import MCPServer
from agents.mcp.fastmcp import FastMCPServer
from agents.model_settings import ModelSettings

from .server import mcp


async def run(mcp_server: MCPServer):
agent = Agent(
name="Assistant",
instructions="Use the tools to answer the questions.",
mcp_servers=[mcp_server],
model_settings=ModelSettings(tool_choice="required"),
)

# Use the `add` tool to add two numbers
message = "Add these numbers: 7 and 22."
print(f"Running: {message}")
result = await Runner.run(starting_agent=agent, input=message)
print(result.final_output)

# Run the `get_weather` tool
message = "What's the weather in Tokyo?"
print(f"\n\nRunning: {message}")
result = await Runner.run(starting_agent=agent, input=message)
print(result.final_output)

# Run the `get_secret_word` tool
message = "What's the secret word?"
print(f"\n\nRunning: {message}")
result = await Runner.run(starting_agent=agent, input=message)
print(result.final_output)


async def main():
async with FastMCPServer(mcp) as server:
trace_id = gen_trace_id()
with trace(workflow_name="In-Process Example", trace_id=trace_id):
print(f"View trace: https://platform.openai.com/traces/trace?trace_id={trace_id}\n")
await run(server)


if __name__ == "__main__":
asyncio.run(main())
29 changes: 29 additions & 0 deletions examples/mcp/in_process/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import random

import requests
from fastmcp.server import FastMCP

# Create server
mcp = FastMCP("Echo Server")


@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
print(f"[debug-server] add({a}, {b})")
return a + b


@mcp.tool()
def get_secret_word() -> str:
print("[debug-server] get_secret_word()")
return random.choice(["apple", "banana", "cherry"])


@mcp.tool()
def get_current_weather(city: str) -> str:
print(f"[debug-server] get_current_weather({city})")

endpoint = "https://wttr.in"
response = requests.get(f"{endpoint}/{city}")
return response.text
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "openai-agents"
version = "0.0.11"
description = "OpenAI Agents SDK"
readme = "README.md"
requires-python = ">=3.9"
requires-python = ">=3.10"
license = "MIT"
authors = [{ name = "OpenAI", email = "[email protected]" }]
dependencies = [
Expand All @@ -14,12 +14,12 @@ dependencies = [
"requests>=2.0, <3",
"types-requests>=2.0, <3",
"mcp>=1.6.0, <2; python_version >= '3.10'",
"fastmcp>=2.2.0"
]
classifiers = [
"Typing :: Typed",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand Down
55 changes: 55 additions & 0 deletions src/agents/mcp/fastmcp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from pathlib import Path
from typing import Any

from fastmcp.client import Client, ClientTransport
from fastmcp.server import FastMCP
from pydantic import AnyUrl
from mcp.types import CallToolResult, Tool

from ..mcp import MCPServer


class FastMCPServer(MCPServer):
"""
Support fastmcp transport implementations, include in-memory fastmcp servers.
"""

def __init__(
self,
transport: ClientTransport | FastMCP | AnyUrl | Path | str,
name: str | None = None,
):
self._client = Client(transport)
if not name:
if isinstance(transport, FastMCP):
name = transport.name
else:
name = str(transport)
self._name = name

async def connect(self):
await self._client.__aenter__()

async def cleanup(self):
await self._client.__aexit__(None, None, None)

async def __aenter__(self):
await self.connect()
return self

async def __aexit__(self, exc_type, exc_value, traceback):
await self._client.__aexit__(exc_type, exc_value, traceback)

@property
def name(self) -> str:
return self._name

async def list_tools(self) -> list[Tool]:
return await self._client.list_tools()

async def call_tool(
self, tool_name: str, arguments: dict[str, Any] | None
) -> CallToolResult:
return await self._client.call_tool(
tool_name, arguments, _return_raw_result=True
)
Loading