from collections.abc import Sequence from typing import Any from django.conf import settings from mcp.server import MCPServer from mcp.server.auth.middleware.auth_context import AuthContextMiddleware from mcp.server.auth.middleware.bearer_auth import ( BearerAuthBackend, ) from mcp.server.auth.provider import TokenVerifier from mcp.server.transport_security import TransportSecuritySettings from starlette.middleware.authentication import AuthenticationMiddleware from starlette.types import ASGIApp from mcp_server.auth import ( FactoryJWTVerifier, RequireFactoryJWTMiddleware, ) from mcp_server.context import authenticated_user_claims from mcp_server.tools.batch_stats import register_batch_stat_tools from mcp_server.tools.datasets import register_dataset_tools from mcp_server.tools.wprs import register_wpr_tools PROTOCOL_REVISION = "2026-07-28" mcp = MCPServer( name="factory", title="Factory MCP", description="Factory 面向 Agent 的受控业务能力入口。", instructions="所有工具均使用当前请求携带的 Factory JWT 身份执行。", version=settings.SYS_VERSION, ) @mcp.tool() def factory_server_info() -> dict[str, Any]: """返回 Factory MCP 服务版本及协议基础信息。""" return { "name": "factory", "system_version": settings.SYS_VERSION, "protocol_revision": PROTOCOL_REVISION, "authentication": "factory_jwt", "domain_tools_ready": True, } @mcp.tool() def factory_whoami() -> dict[str, Any]: """返回当前 Factory JWT 对应的用户身份。""" return authenticated_user_claims() register_dataset_tools(mcp) register_wpr_tools(mcp) register_batch_stat_tools(mcp) def create_app( *, allowed_hosts: Sequence[str] | None = None, allowed_origins: Sequence[str] | None = None, token_verifier: TokenVerifier | None = None, ) -> ASGIApp: """创建仅接受 Factory JWT 的 MCP v2 Streamable HTTP 应用。""" transport_security = TransportSecuritySettings( enable_dns_rebinding_protection=True, allowed_hosts=list(settings.MCP_ALLOWED_HOSTS if allowed_hosts is None else allowed_hosts), allowed_origins=list(settings.MCP_ALLOWED_ORIGINS if allowed_origins is None else allowed_origins), ) app: ASGIApp = mcp.streamable_http_app( streamable_http_path=settings.MCP_PATH, json_response=True, max_request_body_size=settings.MCP_MAX_REQUEST_BODY_SIZE, transport_security=transport_security, host=settings.MCP_HOST, ) # 包装顺序保证先解析 Bearer JWT,再写入 MCP 请求上下文,最后强制认证。 app = RequireFactoryJWTMiddleware(app) app = AuthContextMiddleware(app) app = AuthenticationMiddleware( app, backend=BearerAuthBackend(token_verifier or FactoryJWTVerifier()), ) return app application = create_app()