Skip to content

Commit 8da6e51

Browse files
Merge pull request #7 from Agent-Hellboy/fix_issue#6
Add logging inside framework
2 parents 84be8ec + 9574d3c commit 8da6e51

File tree

5 files changed

+113
-6
lines changed

5 files changed

+113
-6
lines changed

README.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ This project was created after encountering several issues(I faced it while tryi
1010

1111
## Usage
1212

13+
To see detailed debug logs from the framework, configure logging in your application before importing or running the server:
14+
15+
```python
16+
import logging
17+
logging.basicConfig(level=logging.DEBUG)
18+
```
19+
20+
21+
1322
Run the example server:
1423
```bash
1524
pip install .
@@ -18,8 +27,63 @@ Run the example server:
1827

1928
**Note:** Targeting Cursor as a client only.
2029

30+
## Writing Your Own Tool
31+
32+
To create a tool with this framework, use the `@tool_registry.register` decorator. For example:
33+
34+
```python
35+
from pymcp.registry import tool_registry
36+
37+
@tool_registry.register
38+
def my_tool(a: int, b: int) -> str:
39+
"""Adds two numbers and returns the result as a string."""
40+
return f"Result: {a + b}"
41+
```
42+
43+
## Hosting the Server with FastAPI and Uvicorn
44+
45+
The framework provides a FastAPI app instance (`pymcp.server.app`). You can use this app to run your server with Uvicorn:
46+
47+
```python
48+
from pymcp.server import app
49+
import uvicorn
50+
51+
if __name__ == "__main__":
52+
uvicorn.run(app, host="0.0.0.0", port=8088)
53+
```
54+
55+
## Configuring Middleware
56+
57+
You can add custom middleware to the FastAPI app provided by the framework. For example, to add a custom middleware:
58+
59+
```python
60+
from pymcp.server import app
61+
from fastapi import Request
62+
63+
@app.middleware("http")
64+
async def custom_middleware(request: Request, call_next):
65+
# Custom logic before request
66+
response = await call_next(request)
67+
# Custom logic after request
68+
return response
69+
```
70+
71+
You can add this before running the server with Uvicorn as shown above.
2172

2273
Request flow of an example mcp server
2374
![mcp](./mcp.png)
2475

76+
## Logging
77+
78+
By default, the framework does not configure logging. To see debug or info logs from the framework, configure logging in your application (before importing or running the server):
79+
80+
```python
81+
import logging
82+
logging.basicConfig(level=logging.DEBUG) # or INFO, WARNING, etc.
83+
```
84+
85+
This allows you to control the verbosity and destination of log messages from both your code and the framework.
86+
87+
88+
2589

example/run_server.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import logging
2+
13
from pymcp.registry import tool_registry
24
from pymcp.server import app
35

6+
logging.basicConfig(level=logging.DEBUG)
47

58
@tool_registry.register
69
def addNumbersTool(a: float, b: float) -> str:
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import uvicorn
2+
from fastapi import FastAPI
3+
from fastapi.responses import JSONResponse
4+
5+
app = FastAPI()
6+
7+
8+
@app.get("/hello")
9+
async def hello():
10+
return JSONResponse({"message": "Hello from FastAPI!"})
11+
12+
13+
if __name__ == "__main__":
14+
uvicorn.run(app, host="0.0.0.0", port=5005)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import requests
2+
3+
from pymcp.registry import tool_registry
4+
from pymcp.server import app
5+
6+
7+
@tool_registry.register
8+
def callFlaskHelloTool() -> str:
9+
"""Calls the /hello endpoint of the Flask API server running on port 5005 and returns the message."""
10+
try:
11+
resp = requests.get("http://127.0.0.1:5005/hello", timeout=2)
12+
resp.raise_for_status()
13+
data = resp.json()
14+
return f"Flask API says: {data.get('message', 'No message')}"
15+
except Exception as e:
16+
return f"Error calling Flask API: {e}"
17+
18+
19+
if __name__ == "__main__":
20+
import uvicorn
21+
22+
print(
23+
"[INFO] Make sure to start the Flask API server (flask_api_server.py) before running this example."
24+
)
25+
uvicorn.run(app, host="0.0.0.0", port=8088)

pymcp/server.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import json
3+
import logging
34
from uuid import uuid4
45

56
from fastapi import FastAPI, Request
@@ -33,8 +34,8 @@ async def root():
3334
@app.get("/sse-cursor")
3435
async def sse_cursor(request: Request):
3536
session_id = str(uuid4())
36-
print("[MCP] SSE => /sse-cursor connected")
37-
print(f"[MCP] Created sessionId: {session_id}")
37+
logging.debug("[MCP] SSE => /sse-cursor connected")
38+
logging.debug(f"[MCP] Created sessionId: {session_id}")
3839
queue = asyncio.Queue()
3940
sessions = get_sessions(app)
4041
sessions[session_id] = {"initialized": False, "queue": queue}
@@ -63,7 +64,7 @@ async def message(request: Request):
6364
status_code=404, content={"error": "Invalid or missing sessionId"}
6465
)
6566
data = await request.json()
66-
print(f"[MCP] POST /message => body: {data} query: {session_id}")
67+
logging.debug(f"[MCP] POST /message => method: {data.get('method', 'unknown')} query: {session_id}")
6768
rpc_id = data.get("id")
6869
method = data.get("method")
6970
queue = sessions[session_id]["queue"]
@@ -149,9 +150,9 @@ async def handle_rpc_method(method, data, session_id, rpc_id, sessions):
149150
"id": rpc_id,
150151
"result": {"tools": tools_list, "count": len(tools_list)},
151152
}
152-
print(f"[TOOLS] Sending {len(tools_list)} tools to Cursor")
153-
print(f"[TOOLS] Tool names: {[t['name'] for t in tools_list]}")
154-
print(f"[TOOLS] Tool schemas: {json.dumps(tools_list, indent=2)}")
153+
logging.debug(f"[TOOLS] Sending {len(tools_list)} tools to Cursor")
154+
logging.debug(f"[TOOLS] Tool names: {[t['name'] for t in tools_list]}")
155+
logging.debug(f"[TOOLS] Tool schemas: {json.dumps(tools_list, indent=2)}")
155156
await queue.put(json.dumps(result))
156157
elif method == "tools/call":
157158
tool_name = data.get("params", {}).get("name")

0 commit comments

Comments
 (0)