server.py 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. from __future__ import annotations
  2. import logging
  3. from pathlib import Path
  4. from fastapi import FastAPI
  5. from fastapi.staticfiles import StaticFiles
  6. from fastapi.templating import Jinja2Templates
  7. from mcp.server.fastmcp import FastMCP
  8. from mcp.server.transport_security import TransportSecuritySettings
  9. from . import config
  10. logger = logging.getLogger("astro-mcp")
  11. mcp = FastMCP(
  12. "astro-mcp",
  13. transport_security=TransportSecuritySettings(
  14. enable_dns_rebinding_protection=False,
  15. ),
  16. )
  17. # Import tools module to register all @mcp.tool() handlers
  18. from . import tools # noqa: E402, F401
  19. # Templates and static files
  20. TEMPLATES_DIR = Path(__file__).resolve().parent.parent.parent / "templates"
  21. STATIC_DIR = Path(__file__).resolve().parent.parent.parent / "static"
  22. templates = Jinja2Templates(directory=str(TEMPLATES_DIR))
  23. def _tool_names() -> list[str]:
  24. return [
  25. "get_planetary_positions",
  26. "calculate_natal_chart",
  27. "calculate_transit_chart",
  28. "calculate_synastry_chart",
  29. "calculate_composite_chart",
  30. "get_transit_preview",
  31. "person_manage",
  32. "list_house_systems",
  33. "calculate_natal_chart_by_id",
  34. "calculate_transit_chart_by_id",
  35. "calculate_synastry_chart_by_id",
  36. "calculate_composite_chart_by_id",
  37. "get_transit_preview_by_id",
  38. ]
  39. def create_app() -> FastAPI:
  40. config.LOG_DIR.mkdir(parents=True, exist_ok=True)
  41. logging.basicConfig(
  42. filename=str(config.LOG_DIR / "server.log"),
  43. level=logging.INFO,
  44. format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
  45. )
  46. app = FastAPI(title="astro-mcp")
  47. # Mount static files
  48. if STATIC_DIR.exists():
  49. app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
  50. # Mount MCP SSE
  51. app.mount("/mcp", mcp.sse_app())
  52. # Dashboard routes
  53. from .dashboard import router as dashboard_router # noqa: E402
  54. app.include_router(dashboard_router)
  55. @app.get("/health")
  56. def health() -> dict:
  57. return {"ok": True, "server": "astro-mcp", "port": config.PORT}
  58. @app.get("/")
  59. def root() -> dict:
  60. return {
  61. "server": "astro-mcp",
  62. "status": "ready",
  63. "tools": _tool_names(),
  64. "mcp": {
  65. "sse": "/mcp/sse",
  66. "messages": "/mcp/messages",
  67. },
  68. }
  69. return app