Skip to content

Commit 35bff7a

Browse files
committed
add fastmcp test script
1 parent e4a0715 commit 35bff7a

2 files changed

Lines changed: 94 additions & 0 deletions

File tree

mcp_debugger.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from fastmcp import FastMCP
2+
import sqlite3
3+
import json
4+
import os
5+
6+
from pathlib import Path
7+
8+
# Create the MCP server
9+
mcp = FastMCP("MCP Database Debugger")
10+
11+
# Use absolute path relative to this script
12+
DB_PATH = Path(__file__).parent / "mcp.db"
13+
14+
def get_db_connection():
15+
if not os.path.exists(DB_PATH):
16+
raise FileNotFoundError(f"Database not found at {DB_PATH}")
17+
conn = sqlite3.connect(DB_PATH)
18+
conn.row_factory = sqlite3.Row
19+
return conn
20+
21+
@mcp.tool()
22+
def get_database_stats() -> dict:
23+
"""Get counts of events and alerts in the database."""
24+
conn = get_db_connection()
25+
try:
26+
cursor = conn.cursor()
27+
total_events = cursor.execute("SELECT count(*) FROM mcp_auth_events").fetchone()[0]
28+
total_alerts = cursor.execute("SELECT count(*) FROM mcp_alerts").fetchone()[0]
29+
open_alerts = cursor.execute("SELECT count(*) FROM mcp_alerts WHERE status='open'").fetchone()[0]
30+
return {
31+
"total_events": total_events,
32+
"total_alerts": total_alerts,
33+
"open_alerts": open_alerts
34+
}
35+
finally:
36+
conn.close()
37+
38+
@mcp.tool()
39+
def get_recent_events(limit: int = 5) -> str:
40+
"""Get the most recent authentication events."""
41+
conn = get_db_connection()
42+
try:
43+
cursor = conn.cursor()
44+
rows = cursor.execute("SELECT * FROM mcp_auth_events ORDER BY timestamp DESC LIMIT ?", (limit,)).fetchall()
45+
# Convert rows to dicts and handle datetime serialization via str default
46+
return json.dumps([dict(row) for row in rows], default=str, indent=2)
47+
finally:
48+
conn.close()
49+
50+
if __name__ == "__main__":
51+
mcp.run(show_banner=False)

test_client.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from fastmcp import Client
2+
from mcp_debugger import mcp
3+
import asyncio
4+
import json
5+
6+
async def main():
7+
# client = Client(mcp) # This works according to overload signatures!
8+
9+
# Using 'with' context manager for automatic connection/cleanup
10+
# Note: Client might be async. Let's assume standard usage pattern.
11+
# FastMCP client docs usually imply sync usage for simple scripts or async.
12+
# Given the __init__ signature didn't show async, but `run_async` did...
13+
# The overload `Client(transport: FastMCP)` returns a Client.
14+
15+
print("Connecting to MCP Server...")
16+
async with Client(mcp) as client:
17+
print("\n--- Listing Tools ---")
18+
tools = await client.list_tools()
19+
for tool in tools:
20+
print(f"- {tool.name}: {tool.description}")
21+
22+
print("\n--- Calling get_database_stats ---")
23+
result = await client.call_tool("get_database_stats")
24+
# FastMCP CallToolResult usually has 'content' or is iterable?
25+
# Let's print the raw result to see what we got
26+
print(f"Result type: {type(result)}")
27+
print(f"Result content: {result}")
28+
29+
# If it has content, usually it's a list of TextContent or ImageContent path
30+
if hasattr(result, 'content'):
31+
for content in result.content:
32+
if hasattr(content, 'text'):
33+
print(content.text)
34+
35+
print(f"\n--- Calling get_recent_events (limit=2) ---")
36+
result_events = await client.call_tool("get_recent_events", arguments={"limit": 2})
37+
if hasattr(result_events, 'content'):
38+
for content in result_events.content:
39+
if hasattr(content, 'text'):
40+
print(content.text)
41+
42+
if __name__ == "__main__":
43+
asyncio.run(main())

0 commit comments

Comments
 (0)