fix(MCP): 修复导入MCP时传输代码丢失导致无法连接的问题

- 前端 MarketPage 提交时随 download_url 发送粘贴的 MCP 代码(handleSubmit+handleCreateApp)
- 后端新增 parse_mcp_config 解析标准 JSON 配置, 提取 url/headers/transport
- upload_app 与 _sync 使用解析器落库 mcp_servers 并自动连通性测试
- _test_mcp_server 连接测试携带 headers 鉴权头
- 优化 MCP 代码输入框占位符为真实配置格式
This commit is contained in:
QihuAI Design committed 2026-07-17 09:43:43 +08:00
1 parent 24ed907ba5
commit 47d38ca173
3 files changed
+4548 -1741

No files matched your search

File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+45 -17
View File
@@ -541,7 +541,10 @@ const CreateToolModal: React.FC<CreateToolModalProps> = ({ appType, onClose, onS
publisherName: 'demo_user', publisherName: 'demo_user',
status: 'published' as const, status: 'published' as const,
icon: appType === 'skill' ? 'S' : appType === 'agent' ? 'A' : 'M', icon: appType === 'skill' ? 'S' : appType === 'agent' ? 'A' : 'M',
}); // 关键修复:把粘贴的 MCP 传输代码随提交一起发给后端,否则后端拿不到代码、URL 为空、永远连不上
mcpCode: appType === 'mcp' ? mcpCode.trim() : undefined,
mcpTransport: appType === 'mcp' ? mcpTransport : undefined,
} as any);
}, 1500); }, 1500);
}, 2000); }, 2000);
}; };
@@ -721,13 +724,17 @@ const CreateToolModal: React.FC<CreateToolModalProps> = ({ appType, onClose, onS
<label className="form-label">MCP客户端代码 <span className="required">*</span></label> <label className="form-label">MCP客户端代码 <span className="required">*</span></label>
<textarea <textarea
className="mcp-code-editor" className="mcp-code-editor"
placeholder={`粘贴MCP客户端代码,例如: placeholder={`粘贴 MCP 传输代码(标准 JSON 配置),例如:
const client = new MCPClient({ {
transport: { "mcpServers": {
type: "${mcpTransport}", "我的MCP服务": {
endpoint: "https://your-mcp-server.com/sse" "type": "streamable_http",
"url": "https://your-mcp-server.com/mcp",
"headers": { "X-API-KEY": "your-key" }
}
} }
});`} }
注意:请直接粘贴完整的传输代码,系统会自动解析 url / headers / 传输类型并建立连接`}
value={mcpCode} value={mcpCode}
onChange={e => { setMcpCode(e.target.value); setMcpCodeVerifyResult('idle'); }} onChange={e => { setMcpCode(e.target.value); setMcpCodeVerifyResult('idle'); }}
rows={10} rows={10}
@@ -1044,10 +1051,16 @@ const HubImportModal: React.FC<HubImportModalProps> = ({ appType, platforms, onC
<label className="form-label">MCP传输代码 <span className="required">*</span></label> <label className="form-label">MCP传输代码 <span className="required">*</span></label>
<textarea <textarea
className="mcp-code-editor" className="mcp-code-editor"
placeholder={`粘贴MCP客户端代码(需通过AI验证后才能导入),例如: placeholder={`粘贴 MCP 传输代码(标准 JSON 配置,需通过AI验证后才能导入),例如:
const mcpClient = new MCPClient({ {
transport: { type: "streamable-http", endpoint: "https://..." } "mcpServers": {
});`} "我的MCP服务": {
"type": "streamable_http",
"url": "https://your-mcp-server.com/mcp",
"headers": { "X-API-KEY": "your-key" }
}
}
}`}
value={hubCode} value={hubCode}
onChange={e => { setHubCode(e.target.value); setHubCodeVerifyResult('idle'); }} onChange={e => { setHubCode(e.target.value); setHubCodeVerifyResult('idle'); }}
rows={8} rows={8}
@@ -1178,10 +1191,16 @@ const mcpClient = new MCPClient({
<label className="form-label">Streamable HTTP 传输代码 <span className="required">*</span></label> <label className="form-label">Streamable HTTP 传输代码 <span className="required">*</span></label>
<textarea <textarea
className="mcp-code-editor" className="mcp-code-editor"
placeholder={`粘贴 ${p.name} 的 MCP 客户端代码(需通过AI验证后才能导入),例如: placeholder={`粘贴 ${p.name} 的 MCP 传输代码(标准 JSON 配置,需通过AI验证后才能导入),例如:
const mcpClient = new MCPClient({ {
transport: { type: "streamable-http", endpoint: "https://..." } "mcpServers": {
});`} "我的MCP服务": {
"type": "streamable_http",
"url": "https://your-mcp-server.com/mcp",
"headers": { "X-API-KEY": "your-key" }
}
}
}`}
value={hubCodeMap[p.id] || ''} value={hubCodeMap[p.id] || ''}
onChange={e => { onChange={e => {
setHubCodeMap(prev => ({ ...prev, [p.id]: e.target.value })); setHubCodeMap(prev => ({ ...prev, [p.id]: e.target.value }));
@@ -1471,7 +1490,7 @@ const MarketPage: React.FC = () => {
// Handle create tool - 调用后端 API 创建应用 // Handle create tool - 调用后端 API 创建应用
const handleCreateApp = async (data: Partial<MarketApp>) => { const handleCreateApp = async (data: Partial<MarketApp>) => {
try { try {
await marketAPI.createApp({ const payload: any = {
name: data.name, name: data.name,
type: data.type || 'skill', type: data.type || 'skill',
description: data.description || '', description: data.description || '',
@@ -1479,11 +1498,20 @@ const MarketPage: React.FC = () => {
is_member_free: data.isMemberFree ?? true, is_member_free: data.isMemberFree ?? true,
join_promotion: data.joinPromotion ?? false, join_promotion: data.joinPromotion ?? false,
source: 'user', source: 'user',
}); };
// 关键修复:把粘贴的 MCP 传输代码作为 download_url 传给后端,
// 后端会据此解析出 url / headers / transport 并自动注册到 mcp_servers 表做一次连通性测试
const mcpCode = (data as any).mcpCode as string | undefined;
if (data.type === 'mcp' && mcpCode) {
payload.download_url = mcpCode;
payload.mcp_transport = (data as any).mcpTransport || 'streamable_http';
}
await marketAPI.createApp(payload);
// 重新加载列表 // 重新加载列表
loadApps(); loadApps();
} catch (e: any) { } catch (e: any) {
console.error('创建应用失败:', e); console.error('创建应用失败:', e);
alert('创建应用失败:' + (e?.detail || e?.message || '未知错误'));
} }
setShowCreateModal(null); setShowCreateModal(null);
}; };