Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
@@ -10,6 +10,11 @@ import uvicorn
|
|
10 |
from sse_starlette import EventSourceResponse
|
11 |
import anyio
|
12 |
import asyncio
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
app = FastAPI()
|
15 |
|
@@ -32,33 +37,43 @@ def airtable_request(method, endpoint="", data=None):
|
|
32 |
|
33 |
# Tool to list records
|
34 |
async def list_records_tool(request: mcp_types.CallToolRequest):
|
|
|
35 |
try:
|
36 |
records = airtable_request("GET")
|
37 |
-
|
38 |
"success": True,
|
39 |
"result": json.dumps(records)
|
40 |
}
|
|
|
|
|
41 |
except Exception as e:
|
42 |
-
|
43 |
"success": False,
|
44 |
"error": str(e)
|
45 |
}
|
|
|
|
|
46 |
|
47 |
# Tool to create a record
|
48 |
async def create_record_tool(request: mcp_types.CallToolRequest):
|
|
|
49 |
try:
|
50 |
record_data = request.input.get("record_data", {})
|
51 |
data = {"records": [{"fields": record_data}]}
|
52 |
-
|
53 |
-
|
54 |
"success": True,
|
55 |
-
"result": json.dumps(
|
56 |
}
|
|
|
|
|
57 |
except Exception as e:
|
58 |
-
|
59 |
"success": False,
|
60 |
"error": str(e)
|
61 |
}
|
|
|
|
|
62 |
|
63 |
# Define tools separately (for Deep Agent to discover them)
|
64 |
tools = [
|
@@ -81,8 +96,9 @@ tool_handlers = {
|
|
81 |
}
|
82 |
|
83 |
# Create MCP server
|
84 |
-
mcp_server = Server(name="airtable-mcp")
|
85 |
mcp_server.tool_handlers = tool_handlers # Set as attribute
|
|
|
86 |
|
87 |
# Initialize SseServerTransport
|
88 |
transport = SseServerTransport("/airtable/mcp")
|
@@ -90,12 +106,17 @@ transport = SseServerTransport("/airtable/mcp")
|
|
90 |
# SSE endpoint for GET requests
|
91 |
@app.get("/airtable/mcp")
|
92 |
async def handle_sse(request: Request):
|
|
|
93 |
async def sse_writer():
|
|
|
94 |
async with sse_stream_writer, write_stream_reader:
|
|
|
95 |
await sse_stream_writer.send(
|
96 |
-
{"event": "endpoint", "data":
|
97 |
)
|
|
|
98 |
async for session_message in write_stream_reader:
|
|
|
99 |
await sse_stream_writer.send(
|
100 |
{
|
101 |
"event": "message",
|
@@ -109,13 +130,18 @@ async def handle_sse(request: Request):
|
|
109 |
async with transport.connect_sse(request.scope, request.receive, request._send) as streams:
|
110 |
read_stream, write_stream = streams
|
111 |
write_stream_reader = write_stream # Since streams are MemoryObject streams
|
|
|
112 |
await mcp_server.run(read_stream, write_stream, mcp_server.create_initialization_options())
|
113 |
return EventSourceResponse(sse_stream_reader, data_sender_callable=sse_writer)
|
114 |
|
115 |
# Message handling endpoint for POST requests
|
116 |
@app.post("/airtable/mcp")
|
117 |
async def handle_post_message(request: Request):
|
|
|
|
|
|
|
118 |
await transport.handle_post_message(request.scope, request.receive, request._send)
|
|
|
119 |
return Response(status_code=202)
|
120 |
|
121 |
# Health check endpoint
|
@@ -123,6 +149,11 @@ async def handle_post_message(request: Request):
|
|
123 |
async def health_check():
|
124 |
return {"status": "healthy"}
|
125 |
|
|
|
|
|
|
|
|
|
|
|
126 |
if __name__ == "__main__":
|
127 |
port = int(os.getenv("PORT", 7860))
|
128 |
uvicorn.run(app, host="0.0.0.0", port=port)
|
|
|
10 |
from sse_starlette import EventSourceResponse
|
11 |
import anyio
|
12 |
import asyncio
|
13 |
+
import logging
|
14 |
+
|
15 |
+
# Set up logging
|
16 |
+
logging.basicConfig(level=logging.DEBUG)
|
17 |
+
logger = logging.getLogger(__name__)
|
18 |
|
19 |
app = FastAPI()
|
20 |
|
|
|
37 |
|
38 |
# Tool to list records
|
39 |
async def list_records_tool(request: mcp_types.CallToolRequest):
|
40 |
+
logger.debug(f"Received list_records_tool request: {request}")
|
41 |
try:
|
42 |
records = airtable_request("GET")
|
43 |
+
response = {
|
44 |
"success": True,
|
45 |
"result": json.dumps(records)
|
46 |
}
|
47 |
+
logger.debug(f"list_records_tool response: {response}")
|
48 |
+
return response
|
49 |
except Exception as e:
|
50 |
+
response = {
|
51 |
"success": False,
|
52 |
"error": str(e)
|
53 |
}
|
54 |
+
logger.error(f"list_records_tool error: {response}")
|
55 |
+
return response
|
56 |
|
57 |
# Tool to create a record
|
58 |
async def create_record_tool(request: mcp_types.CallToolRequest):
|
59 |
+
logger.debug(f"Received create_record_tool request: {request}")
|
60 |
try:
|
61 |
record_data = request.input.get("record_data", {})
|
62 |
data = {"records": [{"fields": record_data}]}
|
63 |
+
response_data = airtable_request("POST", data=data)
|
64 |
+
response = {
|
65 |
"success": True,
|
66 |
+
"result": json.dumps(response_data)
|
67 |
}
|
68 |
+
logger.debug(f"create_record_tool response: {response}")
|
69 |
+
return response
|
70 |
except Exception as e:
|
71 |
+
response = {
|
72 |
"success": False,
|
73 |
"error": str(e)
|
74 |
}
|
75 |
+
logger.error(f"create_record_tool error: {response}")
|
76 |
+
return response
|
77 |
|
78 |
# Define tools separately (for Deep Agent to discover them)
|
79 |
tools = [
|
|
|
96 |
}
|
97 |
|
98 |
# Create MCP server
|
99 |
+
mcp_server = Server(name="airtable-mcp")
|
100 |
mcp_server.tool_handlers = tool_handlers # Set as attribute
|
101 |
+
mcp_server.tools = tools # Set tools as attribute for Deep Agent to discover
|
102 |
|
103 |
# Initialize SseServerTransport
|
104 |
transport = SseServerTransport("/airtable/mcp")
|
|
|
106 |
# SSE endpoint for GET requests
|
107 |
@app.get("/airtable/mcp")
|
108 |
async def handle_sse(request: Request):
|
109 |
+
logger.debug("Handling SSE connection request")
|
110 |
async def sse_writer():
|
111 |
+
logger.debug("Starting SSE writer")
|
112 |
async with sse_stream_writer, write_stream_reader:
|
113 |
+
endpoint_data = "/airtable/mcp?session_id={session_id}"
|
114 |
await sse_stream_writer.send(
|
115 |
+
{"event": "endpoint", "data": endpoint_data}
|
116 |
)
|
117 |
+
logger.debug(f"Sent endpoint event: {endpoint_data}")
|
118 |
async for session_message in write_stream_reader:
|
119 |
+
logger.debug(f"Sending message via SSE: {session_message}")
|
120 |
await sse_stream_writer.send(
|
121 |
{
|
122 |
"event": "message",
|
|
|
130 |
async with transport.connect_sse(request.scope, request.receive, request._send) as streams:
|
131 |
read_stream, write_stream = streams
|
132 |
write_stream_reader = write_stream # Since streams are MemoryObject streams
|
133 |
+
logger.debug("Running MCP server with streams")
|
134 |
await mcp_server.run(read_stream, write_stream, mcp_server.create_initialization_options())
|
135 |
return EventSourceResponse(sse_stream_reader, data_sender_callable=sse_writer)
|
136 |
|
137 |
# Message handling endpoint for POST requests
|
138 |
@app.post("/airtable/mcp")
|
139 |
async def handle_post_message(request: Request):
|
140 |
+
logger.debug("Handling POST message request")
|
141 |
+
body = await request.body()
|
142 |
+
logger.debug(f"Received POST message body: {body}")
|
143 |
await transport.handle_post_message(request.scope, request.receive, request._send)
|
144 |
+
logger.debug("POST message handled successfully")
|
145 |
return Response(status_code=202)
|
146 |
|
147 |
# Health check endpoint
|
|
|
149 |
async def health_check():
|
150 |
return {"status": "healthy"}
|
151 |
|
152 |
+
# Endpoint to list tools (for debugging)
|
153 |
+
@app.get("/tools")
|
154 |
+
async def list_tools():
|
155 |
+
return {"tools": [tool.model_dump() for tool in tools]}
|
156 |
+
|
157 |
if __name__ == "__main__":
|
158 |
port = int(os.getenv("PORT", 7860))
|
159 |
uvicorn.run(app, host="0.0.0.0", port=port)
|