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:
2026-10-19 18:46:58 +08:00
parent 2b6fc5aa52
commit be6317eb48
117 changed files with 12703 additions and 638 deletions
+27 -2
View File
@@ -1,11 +1,12 @@
from fastapi import FastAPI
from contextlib import asynccontextmanager
from contextlib import asynccontextmanager, AsyncExitStack
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.middleware.cors import CORSMiddleware
import logging
from datetime import datetime
from app.api.problem_details import install_problem_details_handlers
from app.api.health import router as health_router
from app.api.v1.rest_router import api_router
from app.infra.db.dynamic_manager import project_connection_manager
from app.infra.db.postgresql.workbench_event_hub import workbench_event_hubs
@@ -24,13 +25,21 @@ logger.setLevel(logging.INFO)
@asynccontextmanager
async def lifespan(app: FastAPI):
app.state.startup_complete = False
logger.info("**********************************************************")
logger.info(str(datetime.now()))
logger.info("TJWater CloudService is starting...")
logger.info("**********************************************************")
try:
yield
async with AsyncExitStack() as stack:
if mcp_runtime is not None:
await stack.enter_async_context(mcp_runtime.lifespan())
app.state.startup_complete = True
try:
yield
finally:
app.state.startup_complete = False
finally:
await workbench_event_hubs.close_all()
await project_connection_manager.close_all()
@@ -40,6 +49,14 @@ async def lifespan(app: FastAPI):
logger.info("Database connections closed")
# Disabled deployments do not import the MCP SDK or acquire business credentials.
from app.mcp.config import McpSettings
mcp_settings = McpSettings()
mcp_runtime = None
if mcp_settings.enabled:
from app.mcp.application import McpQueryApplication
mcp_runtime = McpQueryApplication(mcp_settings)
# 根据环境配置决定是否启用文档
is_production = settings.ENVIRONMENT.lower() == "production"
@@ -56,8 +73,13 @@ app = FastAPI(
# Include Routers
app.state.startup_complete = False
app.include_router(health_router)
app.include_router(api_router, prefix="/api/v1")
install_problem_details_handlers(app)
from app.api.v1.endpoints.mcp_queries import router as mcp_context_router
app.state.mcp_runtime = mcp_runtime
app.include_router(mcp_context_router, prefix="/api/v1")
# Legacy routers without version prefix
# app.include_router(api_router)
@@ -65,6 +87,9 @@ install_problem_details_handlers(app)
app.add_middleware(GZipMiddleware, minimum_size=1000)
# 添加审计中间件(可选,记录关键操作)
app.add_middleware(AuditMiddleware)
if mcp_runtime is not None:
from app.mcp.dispatch import McpDispatchMiddleware
app.add_middleware(McpDispatchMiddleware, runtime=mcp_runtime)
# 配置 CORS 中间件
# 确保这是你最后一个添加的 app.add_middleware
app.add_middleware(