|
4 | 4 |
|
5 | 5 | class FastMCPServer(DurableObject): |
6 | 6 | def __init__(self, state, env): |
| 7 | + from fastapi import FastAPI, Request |
| 8 | + from pydantic import BaseModel |
| 9 | + from fastapi_mcp import FastApiMCP |
7 | 10 | from exceptions import HTTPException, http_exception |
8 | | - from mcp.server.fastmcp import FastMCP |
9 | | - self.state = state |
10 | | - mcp = FastMCP("Demo") |
11 | | - |
12 | | - @mcp.tool() |
13 | | - def add(a: int, b: int) -> int: |
14 | | - """Add two numbers""" |
15 | | - return a + b |
16 | | - |
17 | | - @mcp.resource("greeting://{name}") |
18 | | - def get_greeting(name: str) -> str: |
19 | | - """Get a personalized greeting""" |
20 | | - return f"Hello, {name}!" |
21 | | - |
22 | | - @mcp.tool() |
23 | | - def calculate_bmi(weight_kg: float, height_m: float) -> float: |
24 | | - """Calculate BMI given weight in kg and height in meters""" |
25 | | - return weight_kg / (height_m**2) |
26 | | - |
27 | | - @mcp.prompt() |
28 | | - def echo_prompt(message: str) -> str: |
29 | | - """Create an echo prompt""" |
30 | | - return f"Please process this message: {message}" |
31 | | - |
32 | | - # mcp depends on uvicorn and imports it at the top scope that we have to patch that to move the |
33 | | - # import into the function that uses it. |
34 | | - # TODO(now): Change uvicorn to optional in mcp |
35 | | - app = mcp.sse_app() |
36 | | - # Starlette default http exception handler is sync which starlette tries to run in threadpool |
37 | | - # in https://github.com/encode/starlette/blob/master/starlette/_exception_handler.py#L61. |
38 | | - # Since we don't support threads we need to override it with the same function but async. |
39 | | - # TODO(now): change starlette's http_exception to be async, it is strictly slower to spawn a new |
40 | | - # thread |
| 11 | + |
| 12 | + app = FastAPI() |
41 | 13 | app.add_exception_handler(HTTPException, http_exception) |
| 14 | + |
| 15 | + mcp = FastApiMCP( |
| 16 | + app, |
| 17 | + # Optional parameters |
| 18 | + name="My API MCP", |
| 19 | + description="My API description", |
| 20 | + ) |
| 21 | + |
| 22 | + # Mount the MCP server directly to your FastAPI app |
| 23 | + mcp.mount() |
| 24 | + # Auto-generated operation_id (something like "read_user_users__user_id__get") |
| 25 | + @app.get("/") |
| 26 | + async def root(): |
| 27 | + return {"message": "Hello, World!"} |
| 28 | + |
| 29 | + @app.get("/env") |
| 30 | + async def root(req: Request): |
| 31 | + env = req.scope["env"] |
| 32 | + return {"message": "Here is an example of getting an environment variable: " + env.MESSAGE} |
| 33 | + |
| 34 | + class Item(BaseModel): |
| 35 | + name: str |
| 36 | + description: str | None = None |
| 37 | + price: float |
| 38 | + tax: float | None = None |
| 39 | + |
| 40 | + @app.post("/items/") |
| 41 | + async def create_item(item: Item): |
| 42 | + return item |
| 43 | + |
| 44 | + @app.put("/items/{item_id}") |
| 45 | + async def create_item(item_id: int, item: Item, q: str | None = None): |
| 46 | + result = {"item_id": item_id, **item.dict()} |
| 47 | + if q: |
| 48 | + result.update({"q": q}) |
| 49 | + return result |
| 50 | + |
| 51 | + @app.get("/items/{item_id}") |
| 52 | + async def read_item(item_id: int): |
| 53 | + return {"item_id": item_id} |
| 54 | + |
| 55 | + mcp.setup_server() |
42 | 56 | self.mcp = mcp |
43 | 57 | self.app = app |
44 | 58 |
|
|
0 commit comments