"""Owned loopback HTTP fixture for cross-language SDK smoke tests. No database/auth service.""" import asyncio import base64 import json import socket import sys from contextlib import asynccontextmanager from datetime import datetime, timezone from pathlib import Path from types import SimpleNamespace from uuid import UUID import uvicorn from fastapi import FastAPI sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "unit")) from test_mcp_query import Repository, Connection, Verifier, PERMISSIONS from app.mcp import application, contexts, query_service from app.mcp.application import McpQueryApplication from app.mcp.config import McpSettings from app.mcp.dispatch import McpDispatchMiddleware from app.mcp.models import QueryResult application.McpQueryRepository = contexts.McpQueryRepository = Repository contexts.permissions_for_context = query_service.permissions_for_context = ( lambda project: PERMISSIONS ) @asynccontextmanager async def query_scope(identity, project): yield SimpleNamespace( project=SimpleNamespace(project_id=UUID(project)), connection=Connection() ) async def execute(scope, binding, tool, args): return QueryResult( source=tool.name, source_ref="fixture:query", queried_at=datetime.now(timezone.utc), semantics=tool.semantics, data=[{"id": "P-1"}], ) async def main(): sock = socket.socket() sock.bind(("127.0.0.1", 0)) port = sock.getsockname()[1] settings = McpSettings( enabled=True, issuer_uri="http://localhost/realms/test", resource_uri=f"http://127.0.0.1:{port}/mcp", _env_file=None, ) class JwtFixtureVerifier(Verifier): async def verify_token(self, token): try: payload = json.loads( base64.urlsafe_b64decode(token.split(".")[1] + "==") ) value = self.identities.get(payload.get("fixture")) if value is not None: value.subject = payload["sub"] value.claims = {"sub": value.subject} return value except (ValueError, IndexError, KeyError): return None verifier = JwtFixtureVerifier() for identity in verifier.identities.values(): identity.resource = settings.resource_uri runtime = McpQueryApplication( settings, verifier=verifier, scope_factory=query_scope, executor=execute ) @asynccontextmanager async def lifespan(app): async with runtime.lifespan(): yield app = FastAPI(lifespan=lifespan) app.state.mcp_runtime = runtime app.include_router(runtime.router, prefix="/api/v1") app.add_middleware(McpDispatchMiddleware, runtime=runtime) server = uvicorn.Server(uvicorn.Config(app, log_level="error", access_log=False)) serving = asyncio.create_task(server.serve(sockets=[sock])) while not server.started: if serving.done(): await serving raise RuntimeError("MCP fixture exited before listening") await asyncio.sleep(0.01) print(f"http://127.0.0.1:{port}/mcp", flush=True) await serving if __name__ == "__main__": asyncio.run(main())