feat(mcp): add MCP server with availability tool
parent
bb5ce5e71a
commit
1b23493167
@ -0,0 +1,3 @@
|
|||||||
|
from app.mcp.server import mcp
|
||||||
|
|
||||||
|
__all__ = ["mcp"]
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
|
from app.mcp.tools import check_availability as check_availability_impl
|
||||||
|
|
||||||
|
mcp = FastMCP(
|
||||||
|
"Personal Agent MCP",
|
||||||
|
streamable_http_path="/",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool(description="Check Google Calendar availability for a time range.")
|
||||||
|
def check_availability(
|
||||||
|
start: str,
|
||||||
|
end: str,
|
||||||
|
calendar_ids: list[str] | None = None,
|
||||||
|
) -> dict[str, object]:
|
||||||
|
return check_availability_impl(start=start, end=end, calendar_ids=calendar_ids)
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from app.config import get_settings
|
||||||
|
from app.core.service import CoreAgentService
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
core_service = CoreAgentService(settings=settings, logger=logging.getLogger("personal-agent.mcp"))
|
||||||
|
|
||||||
|
|
||||||
|
def check_availability(
|
||||||
|
start: str, end: str, calendar_ids: list[str] | None = None
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Return free/busy availability for a time range on one or more calendars."""
|
||||||
|
result = core_service.check_availability(start=start, end=end, calendar_ids=calendar_ids)
|
||||||
|
return {
|
||||||
|
"start": result.start,
|
||||||
|
"end": result.end,
|
||||||
|
"available": result.available,
|
||||||
|
"busy_slots": [
|
||||||
|
{
|
||||||
|
"calendar_id": slot.calendar_id,
|
||||||
|
"start": slot.start,
|
||||||
|
"end": slot.end,
|
||||||
|
}
|
||||||
|
for slot in result.busy_slots
|
||||||
|
],
|
||||||
|
"checked_calendars": result.checked_calendars,
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
|
from starlette.applications import Starlette
|
||||||
|
from starlette.routing import Mount
|
||||||
|
|
||||||
|
from app.mcp import mcp
|
||||||
|
|
||||||
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def lifespan(_: Starlette):
|
||||||
|
async with mcp.session_manager.run():
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
app = Starlette(
|
||||||
|
routes=[
|
||||||
|
Mount("/mcp", app=mcp.streamable_http_app()),
|
||||||
|
],
|
||||||
|
lifespan=lifespan,
|
||||||
|
)
|
||||||
Loading…
Reference in New Issue