refactor: api

This commit is contained in:
Junyan Qin
2025-08-07 09:06:24 +08:00
parent 70ad92ca16
commit 0f35458cf7
+98 -94
View File
@@ -10,110 +10,114 @@ from .. import group
@group.group_class('mcp', '/api/v1/mcp') @group.group_class('mcp', '/api/v1/mcp')
class MCPRouterGroup(group.RouterGroup): class MCPRouterGroup(group.RouterGroup):
async def initialize(self) -> None: async def initialize(self) -> None:
@self.route('/servers', methods=['GET'], auth_type=group.AuthType.USER_TOKEN) @self.route('/servers', methods=['GET', 'POST'], auth_type=group.AuthType.USER_TOKEN)
async def _() -> str: async def _() -> str:
"""获取MCP服务器列表""" """获取MCP服务器列表"""
if not self.ap or not self.ap.provider_cfg or not self.ap.provider_cfg.data: if quart.request.method == 'GET':
return self.success(data={'servers': []}) if not self.ap or not self.ap.provider_cfg or not self.ap.provider_cfg.data:
return self.success(data={'servers': []})
servers = self.ap.provider_cfg.data.get('mcp', {}).get('servers', []) servers = self.ap.provider_cfg.data.get('mcp', {}).get('servers', [])
# 获取每个服务器的状态和工具信息 # 获取每个服务器的状态和工具信息
mcp_loader = None mcp_loader = None
for loader_name, loader in self.ap.tool_mgr.loaders.items(): for loader_name, loader in self.ap.tool_mgr.loaders.items():
if loader_name == 'mcp': if loader_name == 'mcp':
mcp_loader = loader mcp_loader = loader
break break
servers_with_status = [] servers_with_status = []
for server in servers: for server in servers:
server_info = { server_info = {
'name': server['name'], 'name': server['name'],
'mode': server['mode'], 'mode': server['mode'],
'enable': server['enable'], 'enable': server['enable'],
'config': server, 'config': server,
'status': 'disconnected', 'status': 'disconnected',
'tools': [], 'tools': [],
'error': None, 'error': None,
}
# 检查服务器连接状态
if mcp_loader and server['name'] in mcp_loader.sessions:
session = mcp_loader.sessions[server['name']]
server_info['status'] = 'connected'
server_info['tools'] = [
{'name': func.name, 'description': func.description, 'parameters': func.parameters}
for func in session.functions
]
elif server['enable']:
server_info['status'] = 'error'
server_info['error'] = 'Failed to connect'
servers_with_status.append(server_info)
return self.success(data={'servers': servers_with_status})
elif quart.request.method == 'POST':
data = await quart.request.json
# 验证必填字段
required_fields = ['name', 'mode']
for field in required_fields:
if field not in data:
return self.http_status(400, -1, f'Missing required field: {field}')
# 检查provider_cfg是否可用
if not self.ap or not self.ap.provider_cfg or not self.ap.provider_cfg.data:
return self.http_status(500, -1, 'Provider configuration not available')
# 获取当前配置
mcp_config = self.ap.provider_cfg.data.get('mcp', {'servers': []})
servers = mcp_config['servers']
# 检查服务器名称是否重复
for server in servers:
if server['name'] == data['name']:
return self.http_status(400, -1, 'Server name already exists')
# 创建新服务器配置
new_server = {
'name': data['name'],
'mode': data['mode'],
'enable': data.get('enable', True),
} }
# 检查服务器连接状态 # 根据模式添加配置
if mcp_loader and server['name'] in mcp_loader.sessions: if data['mode'] == 'stdio':
session = mcp_loader.sessions[server['name']] new_server.update(
server_info['status'] = 'connected' {'command': data.get('command', ''), 'args': data.get('args', []), 'env': data.get('env', {})}
server_info['tools'] = [ )
{'name': func.name, 'description': func.description, 'parameters': func.parameters} elif data['mode'] == 'sse':
for func in session.functions new_server.update(
] {
elif server['enable']: 'url': data.get('url', ''),
server_info['status'] = 'error' 'headers': data.get('headers', {}),
server_info['error'] = 'Failed to connect' 'timeout': data.get('timeout', 10),
}
)
servers_with_status.append(server_info) # 添加到配置
servers.append(new_server)
self.ap.provider_cfg.data['mcp'] = mcp_config
return self.success(data={'servers': servers_with_status}) # 保存配置
await self.ap.provider_cfg.dump_config()
@self.route('/servers', methods=['POST'], auth_type=group.AuthType.USER_TOKEN) # 如果启用,尝试重新加载MCP loader
async def _() -> str: if new_server['enable']:
"""创建MCP服务器配置""" ctx = taskmgr.TaskContext.new()
data = await quart.request.json wrapper = self.ap.task_mgr.create_user_task(
self._reload_mcp_loader(ctx),
# 验证必填字段 kind='mcp-operation',
required_fields = ['name', 'mode'] name=f'mcp-reload-{new_server["name"]}',
for field in required_fields: label=f'Reloading MCP loader for {new_server["name"]}',
if field not in data: context=ctx,
return self.http_status(400, -1, f'Missing required field: {field}') )
return self.success(data={'task_id': wrapper.id})
# 检查provider_cfg是否可用 else:
if not self.ap or not self.ap.provider_cfg or not self.ap.provider_cfg.data: return self.success()
return self.http_status(500, -1, 'Provider configuration not available') else:
return self.http_status(405, -1, 'Method not allowed')
# 获取当前配置
mcp_config = self.ap.provider_cfg.data.get('mcp', {'servers': []})
servers = mcp_config['servers']
# 检查服务器名称是否重复
for server in servers:
if server['name'] == data['name']:
return self.http_status(400, -1, 'Server name already exists')
# 创建新服务器配置
new_server = {
'name': data['name'],
'mode': data['mode'],
'enable': data.get('enable', True),
}
# 根据模式添加配置
if data['mode'] == 'stdio':
new_server.update(
{'command': data.get('command', ''), 'args': data.get('args', []), 'env': data.get('env', {})}
)
elif data['mode'] == 'sse':
new_server.update(
{'url': data.get('url', ''), 'headers': data.get('headers', {}), 'timeout': data.get('timeout', 10)}
)
# 添加到配置
servers.append(new_server)
self.ap.provider_cfg.data['mcp'] = mcp_config
# 保存配置
await self.ap.provider_cfg.dump_config()
# 如果启用,尝试重新加载MCP loader
if new_server['enable']:
ctx = taskmgr.TaskContext.new()
wrapper = self.ap.task_mgr.create_user_task(
self._reload_mcp_loader(ctx),
kind='mcp-operation',
name=f'mcp-reload-{new_server["name"]}',
label=f'Reloading MCP loader for {new_server["name"]}',
context=ctx,
)
return self.success(data={'task_id': wrapper.id})
return self.success()
@self.route('/servers/<server_name>', methods=['GET', 'PUT', 'DELETE'], auth_type=group.AuthType.USER_TOKEN) @self.route('/servers/<server_name>', methods=['GET', 'PUT', 'DELETE'], auth_type=group.AuthType.USER_TOKEN)
async def _(server_name: str) -> str: async def _(server_name: str) -> str: