Files
next-tjwater-server/app/main.py
T
jiang be6317eb48 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.
2026-10-19 18:46:58 +08:00

102 lines
3.5 KiB
Python

from fastapi import FastAPI
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
from app.infra.db.metadb.database import close_metadata_engine
from app.infra.db.timescaledb.sync_pool import close_all_timescale_pools
from app.native.wndb.core.connection import close_all_project_pools
from app.core.config import settings
# 导入审计中间件
from app.infra.audit.middleware import AuditMiddleware
logger = logging.getLogger()
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:
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()
close_all_timescale_pools()
close_all_project_pools()
await close_metadata_engine()
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"
app = FastAPI(
lifespan=lifespan,
title=settings.PROJECT_NAME,
description="TJWater Server - 供水管网智能管理系统",
version="1.0.0",
docs_url=None if is_production else "/docs",
redoc_url=None if is_production else "/redoc",
openapi_url=None if is_production else "/openapi.json",
redirect_slashes=False,
)
# 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)
# 配置中间件
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(
CORSMiddleware,
allow_origins=settings.cors_allowed_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)