feat(mcp): add FastMCP server with 14 tools for LLM agent access

- Add backend/innercontext/mcp_server.py with tools covering products,
  inventory, routines, skin snapshots, medications, lab results, and
  grooming schedule
- Mount MCP app at /mcp in main.py using combine_lifespans
- Fix test isolation: patch app.router.lifespan_context in conftest to
  avoid StreamableHTTPSessionManager single-run limitation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Piotr Oleszczyk 2026-02-28 17:59:11 +01:00
parent 4954d4f449
commit ac829171d9
5 changed files with 1101 additions and 2 deletions

View file

@ -1,4 +1,5 @@
import os
from contextlib import asynccontextmanager
# Must be set before importing db (which calls create_engine at module level)
os.environ.setdefault("DATABASE_URL", "sqlite://")
@ -13,6 +14,18 @@ from db import get_session
from main import app
@asynccontextmanager
async def _db_only_lifespan(a):
"""Lifespan without the MCP server for test isolation.
StreamableHTTPSessionManager.run() can only be called once per instance,
which conflicts with the per-test TestClient lifecycle. We replace the
combined (db + MCP) lifespan with one that only does DB setup.
"""
db_module.create_db_and_tables()
yield
@pytest.fixture()
def session(monkeypatch):
"""Per-test fresh SQLite in-memory database with full isolation."""
@ -32,8 +45,11 @@ def session(monkeypatch):
@pytest.fixture()
def client(session):
def client(session, monkeypatch):
"""TestClient using the per-test session for every request."""
# Replace combined (db+MCP) lifespan with DB-only to avoid the
# StreamableHTTPSessionManager single-run limitation.
monkeypatch.setattr(app.router, "lifespan_context", _db_only_lifespan)
def _override():
yield session