"""MCP server API(/tools/mcp-servers,skills-design §6)。 支持两种传输协议:streamable-http / stdio。 stdio 模式通过 /start、/stop、/restart 控制子进程生命周期。 """ from fastapi import APIRouter, Depends, Query from fastapi import status as http_status from app.api.v1.deps import get_optional_tool_runtime from app.application.tool_runtime.runtime import ToolRuntime from app.integrations.mcp.process_manager import get_process_manager from app.schemas.mcp import ( CreateMcpServerRequest, McpServerResponse, McpServerStatusResponse, UpdateMcpServerRequest, ) from app.services import mcp as mcp_service router = APIRouter(prefix="/tools/mcp-servers", tags=["mcp"]) @router.post( "", response_model=McpServerResponse, status_code=http_status.HTTP_201_CREATED, ) async def register_mcp_server( payload: CreateMcpServerRequest, runtime: ToolRuntime | None = Depends(get_optional_tool_runtime), ) -> McpServerResponse: """注册 MCP server。 streamable-http:同步拉取工具清单并注册到运行时。 stdio:只存 DB,需后续调用 /start 启动子进程后拉取工具。 """ return await mcp_service.register_mcp_server( name=payload.name, transport=payload.transport, endpoint_url=payload.endpoint_url, auth_token=payload.auth_token, command=payload.command, args_json=payload.args_json, env_json=payload.env_json, cwd=payload.cwd, status=payload.status, runtime=runtime, process_manager=get_process_manager(), ) @router.get("", response_model=list[McpServerResponse]) async def list_mcp_servers( status: str | None = Query(default=None, description="按状态过滤:enabled/disabled"), ) -> list[McpServerResponse]: """列举 MCP server(含工具清单摘要)。""" return await mcp_service.list_mcp_servers(status=status) @router.patch( "/{server_id}", response_model=McpServerResponse, ) async def update_mcp_server( server_id: str, payload: UpdateMcpServerRequest, runtime: ToolRuntime | None = Depends(get_optional_tool_runtime), ) -> McpServerResponse: """更新 MCP server 字段(部分更新)。""" return await mcp_service.update_mcp_server( server_id, status=payload.status, endpoint_url=payload.endpoint_url, auth_token=payload.auth_token, command=payload.command, args_json=payload.args_json, env_json=payload.env_json, cwd=payload.cwd, runtime=runtime, process_manager=get_process_manager(), ) @router.delete("/{server_id}", status_code=http_status.HTTP_204_NO_CONTENT) async def delete_mcp_server( server_id: str, runtime: ToolRuntime | None = Depends(get_optional_tool_runtime), ) -> None: """删除 MCP server(先 stop 子进程再删)。""" await mcp_service.delete_mcp_server( server_id, runtime=runtime, process_manager=get_process_manager(), ) @router.post( "/{server_id}/start", response_model=McpServerStatusResponse, ) async def start_mcp_server( server_id: str, runtime: ToolRuntime | None = Depends(get_optional_tool_runtime), ) -> McpServerStatusResponse: """启动 stdio MCP server 子进程,拉取工具并注册。""" return await mcp_service.start_mcp_server( server_id, runtime=runtime, process_manager=get_process_manager(), ) @router.post( "/{server_id}/stop", response_model=McpServerStatusResponse, ) async def stop_mcp_server( server_id: str, runtime: ToolRuntime | None = Depends(get_optional_tool_runtime), ) -> McpServerStatusResponse: """停止 stdio MCP server 子进程,注销工具。""" return await mcp_service.stop_mcp_server( server_id, runtime=runtime, process_manager=get_process_manager(), ) @router.post( "/{server_id}/restart", response_model=McpServerStatusResponse, ) async def restart_mcp_server( server_id: str, runtime: ToolRuntime | None = Depends(get_optional_tool_runtime), ) -> McpServerStatusResponse: """重启 stdio MCP server。""" return await mcp_service.restart_mcp_server( server_id, runtime=runtime, process_manager=get_process_manager(), ) @router.get( "/{server_id}/status", response_model=McpServerStatusResponse, ) async def get_mcp_server_status( server_id: str, ) -> McpServerStatusResponse: """查询 MCP server 进程状态。""" return await mcp_service.get_mcp_server_status( server_id, process_manager=get_process_manager(), ) @router.post( "/{server_id}/refresh", response_model=McpServerResponse, ) async def refresh_mcp_server_tools( server_id: str, runtime: ToolRuntime | None = Depends(get_optional_tool_runtime), ) -> McpServerResponse: """重新拉取 MCP server 工具清单并注册到运行时。""" return await mcp_service.refresh_mcp_server_tools( server_id, runtime=runtime, process_manager=get_process_manager(), )