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:
@@ -6,6 +6,9 @@ from fastapi.security import OAuth2PasswordBearer
|
||||
from jose import JWTError, jwt
|
||||
|
||||
from app.core.config import settings
|
||||
from app.mcp.config import McpSettings
|
||||
|
||||
mcp_resource_settings = McpSettings()
|
||||
|
||||
oauth2_optional = OAuth2PasswordBearer(
|
||||
tokenUrl="keycloak", auto_error=False
|
||||
@@ -29,6 +32,13 @@ def _decode_keycloak_token(token: str) -> dict:
|
||||
algorithms=[settings.KEYCLOAK_ALGORITHM],
|
||||
audience=settings.KEYCLOAK_AUDIENCE or None,
|
||||
)
|
||||
# A resource-bound MCP token must never authorize product REST APIs,
|
||||
# including when another audience overlaps the configured API audience.
|
||||
audience = payload.get("aud", [])
|
||||
audiences = [audience] if isinstance(audience, str) else audience
|
||||
if (isinstance(audiences, list) and mcp_resource_settings.audience in audiences
|
||||
or payload.get("azp") == mcp_resource_settings.host_client_id):
|
||||
raise JWTError("MCP resource tokens cannot authorize product REST APIs")
|
||||
if settings.KEYCLOAK_ACCESS_TOKEN_MAX_AGE_SECONDS <= 0:
|
||||
return payload
|
||||
|
||||
|
||||
Reference in New Issue
Block a user