feat(server): integrate MCP queries and investigation messaging
Add project-bound OAuth MCP queries and controlled analysis with scoped evidence, limits, timeouts and a nearby-model spatial query using EPSG:4326 inputs. Default nearby searches to 200 meters and five results. Integrate investigation messaging/presentation, health/readiness and typed history; remove duplicate web search and fix online simulation and compressed baseline writes. Include project migrations 023-025; keep local credentials and demo seeding excluded. Validation: 319 focused pytest checks; real PostGIS temporary-table regression; read-only Jinqian bridge radius comparison; cross-language MCP discovery/calls.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
"""Resolve authoritative metadata and project routing for each MCP request."""
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, AsyncIterator
|
||||
from psycopg import AsyncConnection
|
||||
from app.auth.project_dependencies import ProjectContext
|
||||
from app.infra.db.project_routing import ActiveProjectRouting
|
||||
from fastapi import HTTPException
|
||||
from mcp.server.auth.provider import AccessToken
|
||||
|
||||
from app.auth.metadata_dependencies import get_current_metadata_user
|
||||
from app.auth.project_dependencies import (
|
||||
resolve_project_context,
|
||||
resolve_project_business_routing,
|
||||
resolve_project_simulation_routing,
|
||||
get_project_pg_connection,
|
||||
get_project_timescale_connection,
|
||||
)
|
||||
from app.infra.db.metadb.database import get_metadata_session
|
||||
from app.infra.db.metadb.repositories.metadata_repository import MetadataRepository
|
||||
from app.infra.db.project_routing import activate_project_routing
|
||||
|
||||
|
||||
class QueryMetadataRepository(MetadataRepository):
|
||||
async def get_project_db_routing(self, project_id, role):
|
||||
routing = await super().get_project_db_routing(project_id, role)
|
||||
# Existing connection generators obtain routing before awaiting a pool.
|
||||
# End that implicit SELECT transaction here, before the network wait.
|
||||
await self.session.commit()
|
||||
return routing
|
||||
|
||||
|
||||
@dataclass
|
||||
class QueryScope:
|
||||
project: ProjectContext
|
||||
user: Any
|
||||
connection: AsyncConnection
|
||||
routing: ActiveProjectRouting
|
||||
metadata: QueryMetadataRepository
|
||||
|
||||
@asynccontextmanager
|
||||
async def simulation_routing(self) -> AsyncIterator[ActiveProjectRouting]:
|
||||
"""Resolve both databases before a native calculation can modify its model."""
|
||||
routing = await resolve_project_simulation_routing(self.project, self.metadata)
|
||||
await self.metadata.session.commit()
|
||||
with activate_project_routing(routing):
|
||||
yield routing
|
||||
|
||||
@asynccontextmanager
|
||||
async def timescale(self):
|
||||
# Metadata repository here is used only to resolve a known project DB.
|
||||
async with asynccontextmanager(get_project_timescale_connection)(
|
||||
self.project, self.metadata
|
||||
) as conn:
|
||||
await self.metadata.session.commit()
|
||||
yield conn
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def project_scope(principal: AccessToken, project_id: str):
|
||||
if not principal.claims:
|
||||
raise HTTPException(401, "MCP identity is missing")
|
||||
async with asynccontextmanager(get_metadata_session)() as session:
|
||||
metadata = QueryMetadataRepository(session)
|
||||
user = await get_current_metadata_user(principal.claims, metadata)
|
||||
project = await resolve_project_context(project_id, user, metadata)
|
||||
routing = await resolve_project_business_routing(project, metadata)
|
||||
# End the metadata read before any external query/IO waits.
|
||||
await session.commit()
|
||||
async with asynccontextmanager(get_project_pg_connection)(
|
||||
project, metadata
|
||||
) as conn:
|
||||
await session.commit()
|
||||
with activate_project_routing(routing):
|
||||
yield QueryScope(project, user, conn, routing, metadata)
|
||||
Reference in New Issue
Block a user