fix: 修复MCP插件创建和测试时的500错误

问题:MCP SDK使用anyio TaskGroup,与FastAPI请求上下文不兼容,
导致在请求中直接await MCP操作时报RuntimeError: No response returned

解决方案:
- 将MCP连接操作放到后台任务执行,避免阻塞请求
- 添加is_registered()和get_session_status()同步检查方法
- 测试时先检查会话是否存在,不存在则触发后台注册
- 改进ExceptionGroup错误处理,显示详细错误信息
- 状态同步改用异步队列,避免阻塞

修改文件:
- backend/app/api/mcp_plugins.py: 重写test_plugin和create_plugin_simple
- backend/app/mcp/facade.py: 添加同步检查方法和改进错误处理
- backend/app/mcp/status_sync.py: 使用异步队列同步状态
- backend/app/services/mcp_test_service.py: 使用同步检查代替异步ensure
This commit is contained in:
snemc
2026-01-24 10:03:59 +08:00
parent 165a02ea75
commit 980cc5b0e5
4 changed files with 282 additions and 95 deletions
+19 -30
View File
@@ -25,32 +25,20 @@ logger = get_logger(__name__)
class MCPTestService:
"""MCP插件测试服务(使用统一门面重构)"""
async def _ensure_plugin_registered(
self,
plugin: MCPPlugin,
user_id: str
) -> bool:
def _check_plugin_registered(self, plugin: MCPPlugin, user_id: str) -> bool:
"""
确保插件已注册到统一门面
检查插件是否已注册(同步方法,不触发新的连接)
Args:
plugin: 插件配置
user_id: 用户ID
Returns:
是否成功
是否已注册
"""
if plugin.plugin_type in ("http", "streamable_http", "sse") and plugin.server_url:
return await mcp_client.ensure_registered(
user_id=user_id,
plugin_name=plugin.plugin_name,
url=plugin.server_url,
plugin_type=plugin.plugin_type,
headers=plugin.headers
)
return False
return mcp_client.is_registered(user_id, plugin.plugin_name)
async def test_plugin_connection(
self,
plugin: MCPPlugin,
@@ -58,27 +46,28 @@ class MCPTestService:
) -> MCPTestResult:
"""
简单连接测试
注意:调用此方法前,需要确保插件已通过后台任务注册。
Args:
plugin: 插件配置
user_id: 用户ID
Returns:
测试结果
"""
start_time = time.time()
try:
# 确保插件已注册
registered = await self._ensure_plugin_registered(plugin, user_id)
if not registered:
# 检查插件是否已注册(不触发新连接)
if not self._check_plugin_registered(plugin, user_id):
return MCPTestResult(
success=False,
message="插件注册失败",
error="无法创建MCP客户端",
suggestions=["检查插件配置", "请确认服务器URL正确"]
message="插件注册",
error="MCP会话不存在,请先启用插件",
suggestions=["先启用插件", "如果已启用,请稍等片刻后重试"]
)
# 使用统一门面测试连接
test_result = await mcp_client.test_connection(user_id, plugin.plugin_name)