Files
2026-07-13 12:39:17 +08:00

131 lines
3.8 KiB
Python

import os
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from agents import Agent, Runner
from agents.mcp import MCPServer, MCPServerManager, MCPServerStreamableHttp
from agents.model_settings import ModelSettings
MCP_SERVER_URL = os.getenv("MCP_SERVER_URL", "http://localhost:8000/mcp")
INACTIVE_MCP_SERVER_URL = os.getenv("INACTIVE_MCP_SERVER_URL", "http://localhost:8001/mcp")
APP_HOST = "127.0.0.1"
APP_PORT = 9001
USE_MCP_MANAGER = os.getenv("USE_MCP_MANAGER", "1") != "0"
class AddRequest(BaseModel):
a: int
b: int
class RunRequest(BaseModel):
input: str
class ReconnectRequest(BaseModel):
failed_only: bool = True
@asynccontextmanager
async def lifespan(app: FastAPI):
server = MCPServerStreamableHttp({"url": MCP_SERVER_URL})
inactive_server = MCPServerStreamableHttp({"url": INACTIVE_MCP_SERVER_URL})
servers = [server, inactive_server]
if USE_MCP_MANAGER:
async with MCPServerManager(
servers=servers,
connect_in_parallel=True,
) as manager:
app.state.mcp_manager = manager
app.state.mcp_servers = servers
yield
return
await server.connect()
app.state.mcp_servers = servers
app.state.active_servers = [server]
try:
yield
finally:
await server.cleanup()
app = FastAPI(lifespan=lifespan)
@app.get("/health")
async def health() -> dict[str, object]:
if USE_MCP_MANAGER:
manager: MCPServerManager = app.state.mcp_manager
return {
"connected_servers": [server.name for server in manager.active_servers],
"failed_servers": [server.name for server in manager.failed_servers],
}
active_servers = _get_active_servers()
return {
"connected_servers": [server.name for server in active_servers],
"failed_servers": [],
}
@app.get("/tools")
async def list_tools() -> dict[str, object]:
active_servers = _get_active_servers()
if not active_servers:
return {"tools": []}
tools = await active_servers[0].list_tools()
return {"tools": [tool.name for tool in tools]}
@app.post("/add")
async def add(req: AddRequest) -> dict[str, object]:
active_servers = _get_active_servers()
if not active_servers:
raise HTTPException(status_code=503, detail="No MCP servers available")
result = await active_servers[0].call_tool("add", {"a": req.a, "b": req.b})
return {"result": result.model_dump(mode="json")}
@app.post("/run")
async def run_agent(req: RunRequest) -> dict[str, object]:
if not os.getenv("OPENAI_API_KEY"):
raise HTTPException(status_code=400, detail="OPENAI_API_KEY is required")
servers = _get_active_servers()
if not servers:
raise HTTPException(status_code=503, detail="No MCP servers available")
agent = Agent(
name="FastAPI Agent",
instructions="Use the MCP tools when needed.",
mcp_servers=servers,
model_settings=ModelSettings(tool_choice="auto"),
)
result = await Runner.run(starting_agent=agent, input=req.input)
return {"output": result.final_output}
@app.post("/reconnect")
async def reconnect(req: ReconnectRequest) -> dict[str, object]:
if not USE_MCP_MANAGER:
raise HTTPException(status_code=400, detail="MCPServerManager is disabled")
manager: MCPServerManager = app.state.mcp_manager
servers = await manager.reconnect(failed_only=req.failed_only)
return {"connected_servers": [server.name for server in servers]}
def _get_active_servers() -> list[MCPServer]:
if USE_MCP_MANAGER:
manager: MCPServerManager = app.state.mcp_manager
return list(manager.active_servers)
return list(app.state.active_servers)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host=APP_HOST, port=APP_PORT)