mcp_server_fastmcp.py 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. from __future__ import annotations
  2. from fastapi import FastAPI
  3. from mcp.server.fastmcp import FastMCP
  4. from mcp.server.transport_security import TransportSecuritySettings
  5. from news_mcp.config import CLUSTERS_TTL_HOURS, DEFAULT_TOPICS, DB_PATH
  6. from news_mcp.jobs.poller import refresh_clusters
  7. from news_mcp.storage.sqlite_store import SQLiteClusterStore
  8. mcp = FastMCP(
  9. "news-mcp",
  10. transport_security=TransportSecuritySettings(enable_dns_rebinding_protection=False),
  11. )
  12. @mcp.tool(description="What is happening right now? Return the latest deduplicated news clusters for a topic.")
  13. async def get_latest_events(topic: str = "crypto", limit: int = 5):
  14. limit = max(1, min(int(limit), 20))
  15. # Refresh opportunistically (v1 simple: refresh every call but bounded to small RSS pull)
  16. refresh_clusters(topic=topic, limit=50)
  17. store = SQLiteClusterStore(DB_PATH)
  18. clusters = store.get_latest_clusters(topic=topic, ttl_hours=CLUSTERS_TTL_HOURS, limit=limit)
  19. # Ensure the response is compact and agent-friendly.
  20. out = []
  21. for c in clusters:
  22. out.append(
  23. {
  24. "cluster_id": c.get("cluster_id"),
  25. "headline": c.get("headline"),
  26. "summary": c.get("summary"),
  27. "entities": c.get("entities", []),
  28. "sentiment": c.get("sentiment", "neutral"),
  29. "importance": c.get("importance", 0.0),
  30. "sources": c.get("sources", []),
  31. "timestamp": c.get("timestamp"),
  32. }
  33. )
  34. return out
  35. app = FastAPI(title="News MCP Server")
  36. app.mount("/mcp", mcp.sse_app())
  37. @app.get("/")
  38. def root():
  39. return {"status": "ok", "transport": "fastmcp+sse", "mount": "/mcp", "tools": ["get_latest_events"]}
  40. @app.get("/health")
  41. def health():
  42. return {"status": "ok", "ttl_hours": CLUSTERS_TTL_HOURS, "db": str(DB_PATH)}