factory/mcp_server/server.py

90 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()