|
1 | | -# from pydantic import BaseModel, create_model |
2 | 1 |
|
3 | | -# from fastapi import FastAPI, Request |
4 | | -# from fastapi_mcp import FastApiMCP |
| 2 | +from workers import DurableObject |
| 3 | + |
| 4 | + |
| 5 | +class FastMCPServer(DurableObject): |
| 6 | + def __init__(self, state, env): |
| 7 | + 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 |
| 41 | + app.add_exception_handler(HTTPException, http_exception) |
| 42 | + self.mcp = mcp |
| 43 | + self.app = app |
| 44 | + |
| 45 | + async def on_fetch(self, request, env, ctx): |
| 46 | + import asgi |
| 47 | + return await asgi.fetch(self.app, request, env) |
5 | 48 |
|
6 | | -############## NORMAL ############## |
7 | | - |
8 | | -# from js import Response |
9 | | - |
10 | | -# async def on_fetch(request, env): |
11 | | -# return Response.new("Hello") |
12 | | - |
13 | | -#################################### |
14 | | - |
15 | | -############## FASTMCP ############## |
16 | | -from exceptions import HTTPException, http_exception |
17 | | -from mcp.server.fastmcp import FastMCP |
18 | | - |
19 | | -mcp = FastMCP("Demo") |
20 | | - |
21 | | -@mcp.tool() |
22 | | -def add(a: int, b: int) -> int: |
23 | | - """Add two numbers""" |
24 | | - return a + b |
25 | | - |
26 | | -@mcp.resource("greeting://{name}") |
27 | | -def get_greeting(name: str) -> str: |
28 | | - """Get a personalized greeting""" |
29 | | - return f"Hello, {name}!" |
30 | | - |
31 | | -@mcp.tool() |
32 | | -def calculate_bmi(weight_kg: float, height_m: float) -> float: |
33 | | - """Calculate BMI given weight in kg and height in meters""" |
34 | | - return weight_kg / (height_m**2) |
35 | | - |
36 | | -@mcp.prompt() |
37 | | -def echo_prompt(message: str) -> str: |
38 | | - """Create an echo prompt""" |
39 | | - return f"Please process this message: {message}" |
40 | | - |
41 | | -# mcp depends on uvicorn and imports it at the top scope that we have to patch that to move the |
42 | | -# import into the function that uses it. |
43 | | -# TODO(now): Change uvicorn to optional in mcp |
44 | | -app = mcp.sse_app() |
45 | | -# Starlette default http exception handler is sync which starlette tries to run in threadpool |
46 | | -# in https://github.com/encode/starlette/blob/master/starlette/_exception_handler.py#L61. |
47 | | -# Since we don't support threads we need to override it with the same function but async. |
48 | | -# TODO(now): change starlette's http_exception to be async, it is strictly slower to spawn a new |
49 | | -# thread |
50 | | -app.add_exception_handler(HTTPException, http_exception) |
51 | 49 | async def on_fetch(request, env): |
52 | | - import asgi |
53 | | - return await asgi.fetch(app, request, env) |
54 | | - |
55 | | -##################################### |
56 | | - |
57 | | -############## FASTAPI ############## |
58 | | -# from fastapi import FastAPI, Request |
59 | | - |
60 | | -# app = FastAPI() |
61 | | - |
62 | | - |
63 | | -# @app.get("/") |
64 | | -# async def root(): |
65 | | -# message = "This is an example of FastAPI" |
66 | | -# return {"message": message} |
67 | | - |
68 | | - |
69 | | -# @app.get("/env") |
70 | | -# async def env(req: Request): |
71 | | -# env = req.scope["env"] |
72 | | -# return { |
73 | | -# "message": "Here is an example of getting an environment variable: " |
74 | | -# + env.MESSAGE |
75 | | -# } |
76 | | - |
77 | | -# async def on_fetch(request, env): |
78 | | -# import asgi |
79 | | -# return await asgi.fetch(app, request, env) |
80 | | - |
81 | | -##################################### |
| 50 | + id = env.ns.idFromName("A") |
| 51 | + obj = env.ns.get(id) |
| 52 | + return await obj.fetch(request) |
0 commit comments