mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-07 11:01:33 +08:00
✨ feat(ai): 增强 MCP 配置诊断能力
- 复用新增 MCP 表单校验逻辑,向 inspect_mcp_setup 输出服务配置问题 - 将 MCP 配置问题汇总到 AI 设置体检,补充后续处理建议 - 补充 MCP 快照、AI 体检和本地工具执行器测试
This commit is contained in:
@@ -404,6 +404,16 @@ describe('aiLocalToolExecutor', () => {
|
||||
enabled: true,
|
||||
timeoutSeconds: 20,
|
||||
},
|
||||
{
|
||||
id: 'server-2',
|
||||
name: 'Broken',
|
||||
transport: 'stdio',
|
||||
command: '',
|
||||
args: [],
|
||||
env: {},
|
||||
enabled: true,
|
||||
timeoutSeconds: 1,
|
||||
},
|
||||
]),
|
||||
getMCPClientInstallStatuses: vi.fn().mockResolvedValue([
|
||||
{
|
||||
@@ -424,9 +434,12 @@ describe('aiLocalToolExecutor', () => {
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.content).toContain('"serverCount":1');
|
||||
expect(result.content).toContain('"serverCount":2');
|
||||
expect(result.content).toContain('"name":"Browser"');
|
||||
expect(result.content).toContain('"launchCommandPreview":"uvx mcp-server-browser"');
|
||||
expect(result.content).toContain('"serverConfigurationIssueCount":2');
|
||||
expect(result.content).toContain('"serversWithConfigurationErrors":1');
|
||||
expect(result.content).toContain('"key":"command-missing"');
|
||||
expect(result.content).toContain('"displayName":"Codex"');
|
||||
expect(result.content).toContain('"launchCommandPreview":"gonavi-mcp-server stdio"');
|
||||
});
|
||||
|
||||
@@ -49,11 +49,46 @@ describe('aiMCPInsights', () => {
|
||||
expect(snapshot.serverCount).toBe(1);
|
||||
expect(snapshot.enabledServerCount).toBe(1);
|
||||
expect(snapshot.discoveredMCPToolCount).toBe(1);
|
||||
expect(snapshot.serverConfigurationIssueCount).toBe(0);
|
||||
expect(snapshot.servers[0].launchCommandPreview).toBe('uvx mcp-server-browser');
|
||||
expect(snapshot.servers[0].configurationIssueCount).toBe(0);
|
||||
expect(snapshot.servers[0].envVarCount).toBe(2);
|
||||
expect(snapshot.servers[0].discoveredToolCount).toBe(1);
|
||||
expect(snapshot.clients[0].displayName).toBe('Claude Code');
|
||||
expect(snapshot.clients[0].launchCommandPreview).toBe('gonavi-mcp-server stdio');
|
||||
expect(snapshot.currentClientCount).toBe(1);
|
||||
});
|
||||
|
||||
it('surfaces saved mcp server launch validation issues for ai diagnostics', () => {
|
||||
const snapshot = buildMCPSetupSnapshot({
|
||||
mcpServers: [
|
||||
{
|
||||
id: 'server-1',
|
||||
name: 'Broken',
|
||||
transport: 'stdio',
|
||||
command: '',
|
||||
args: [],
|
||||
env: {},
|
||||
enabled: true,
|
||||
timeoutSeconds: 1,
|
||||
},
|
||||
],
|
||||
mcpClientStatuses: [],
|
||||
mcpTools: [],
|
||||
});
|
||||
|
||||
expect(snapshot.serverConfigurationIssueCount).toBe(2);
|
||||
expect(snapshot.serversWithConfigurationErrors).toBe(1);
|
||||
expect(snapshot.enabledServersWithConfigurationIssues).toBe(1);
|
||||
expect(snapshot.servers[0].configurationErrorCount).toBe(1);
|
||||
expect(snapshot.servers[0].configurationWarningCount).toBe(1);
|
||||
expect(snapshot.servers[0].configurationCanTest).toBe(false);
|
||||
expect(snapshot.servers[0].configurationIssues.map((issue) => issue.key)).toEqual([
|
||||
'command-missing',
|
||||
'timeout-out-of-range',
|
||||
]);
|
||||
expect(snapshot.warnings).toContain('有 1 个 MCP 服务存在启动配置错误,测试和工具发现可能失败');
|
||||
expect(snapshot.nextActions).toContain('先修复 MCP 服务配置检查里的错误项,再重新测试服务');
|
||||
expect(snapshot.message).toContain('2 个配置检查项需要确认');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { AIMCPClientInstallStatus, AIMCPServerConfig, AIMCPToolDescriptor } from '../../types';
|
||||
import { validateMCPServerDraft } from '../../utils/mcpServerValidation';
|
||||
|
||||
const SERVER_TOOL_PREVIEW_LIMIT = 20;
|
||||
|
||||
@@ -38,6 +39,7 @@ export const buildMCPSetupSnapshot = (params: {
|
||||
alias: tool.alias,
|
||||
title: tool.title || tool.originalName || tool.alias,
|
||||
}));
|
||||
const validation = validateMCPServerDraft(server);
|
||||
return {
|
||||
id: server.id,
|
||||
name: server.name,
|
||||
@@ -52,6 +54,11 @@ export const buildMCPSetupSnapshot = (params: {
|
||||
discoveredToolCount: serverTools.length,
|
||||
discoveredTools: serverTools.slice(0, SERVER_TOOL_PREVIEW_LIMIT),
|
||||
discoveredToolsTruncated: serverTools.length > SERVER_TOOL_PREVIEW_LIMIT,
|
||||
configurationIssueCount: validation.issues.length,
|
||||
configurationErrorCount: validation.errorCount,
|
||||
configurationWarningCount: validation.warningCount,
|
||||
configurationCanTest: validation.canTest,
|
||||
configurationIssues: validation.issues,
|
||||
};
|
||||
}),
|
||||
);
|
||||
@@ -74,20 +81,45 @@ export const buildMCPSetupSnapshot = (params: {
|
||||
const enabledServerCount = normalizedServers.filter((server) => server.enabled).length;
|
||||
const installedClientCount = normalizedClientStatuses.filter((item) => item.installed).length;
|
||||
const currentClientCount = normalizedClientStatuses.filter((item) => item.matchesCurrent).length;
|
||||
const serversWithConfigurationErrors = normalizedServers.filter((server) => server.configurationErrorCount > 0).length;
|
||||
const serversWithConfigurationWarnings = normalizedServers.filter((server) => server.configurationWarningCount > 0).length;
|
||||
const serverConfigurationIssueCount = normalizedServers
|
||||
.reduce((total, server) => total + server.configurationIssueCount, 0);
|
||||
const enabledServersWithConfigurationIssues = normalizedServers
|
||||
.filter((server) => server.enabled && server.configurationIssueCount > 0)
|
||||
.length;
|
||||
const warnings: string[] = [];
|
||||
const nextActions: string[] = [];
|
||||
|
||||
if (serversWithConfigurationErrors > 0) {
|
||||
warnings.push(`有 ${serversWithConfigurationErrors} 个 MCP 服务存在启动配置错误,测试和工具发现可能失败`);
|
||||
nextActions.push('先修复 MCP 服务配置检查里的错误项,再重新测试服务');
|
||||
} else if (serversWithConfigurationWarnings > 0) {
|
||||
warnings.push(`有 ${serversWithConfigurationWarnings} 个 MCP 服务存在启动配置告警,建议在排查工具发现失败前先确认`);
|
||||
nextActions.push('打开对应 MCP 服务,按配置检查提示拆分启动命令、参数和超时时间');
|
||||
}
|
||||
|
||||
return {
|
||||
serverCount: normalizedServers.length,
|
||||
enabledServerCount,
|
||||
disabledServerCount: normalizedServers.length - enabledServerCount,
|
||||
discoveredMCPToolCount: Array.isArray(mcpTools) ? mcpTools.length : 0,
|
||||
serverConfigurationIssueCount,
|
||||
serversWithConfigurationErrors,
|
||||
serversWithConfigurationWarnings,
|
||||
enabledServersWithConfigurationIssues,
|
||||
servers: normalizedServers,
|
||||
clientInstallCount: normalizedClientStatuses.length,
|
||||
installedClientCount,
|
||||
currentClientCount,
|
||||
detectedClientCount: normalizedClientStatuses.filter((item) => item.clientDetected).length,
|
||||
clients: normalizedClientStatuses,
|
||||
warnings,
|
||||
nextActions,
|
||||
message: normalizedServers.length > 0
|
||||
? `当前共配置 ${normalizedServers.length} 个 MCP 服务,其中 ${enabledServerCount} 个已启用`
|
||||
? serverConfigurationIssueCount > 0
|
||||
? `当前共配置 ${normalizedServers.length} 个 MCP 服务,其中 ${enabledServerCount} 个已启用,${serverConfigurationIssueCount} 个配置检查项需要确认`
|
||||
: `当前共配置 ${normalizedServers.length} 个 MCP 服务,其中 ${enabledServerCount} 个已启用`
|
||||
: '当前还没有配置任何 MCP 服务',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -131,4 +131,80 @@ describe('buildAISetupHealthSnapshot', () => {
|
||||
expect(snapshot.mcp.message).toContain('当前共配置 1 个 MCP 服务');
|
||||
expect(snapshot.guidance.enabledSkillPreview).toContain('结构审查');
|
||||
});
|
||||
|
||||
it('includes mcp server configuration validation issues in setup health warnings', () => {
|
||||
const snapshot = buildAISetupHealthSnapshot({
|
||||
providers: [{
|
||||
id: 'provider-1',
|
||||
type: 'openai',
|
||||
name: 'OpenAI 主账号',
|
||||
apiKey: '',
|
||||
hasSecret: true,
|
||||
baseUrl: 'https://api.openai.com/v1',
|
||||
model: 'gpt-5.4',
|
||||
models: ['gpt-5.4'],
|
||||
maxTokens: 32000,
|
||||
temperature: 0.2,
|
||||
}],
|
||||
activeProviderId: 'provider-1',
|
||||
safetyLevel: 'readonly',
|
||||
contextLevel: 'schema_only',
|
||||
builtinToolNames: ['inspect_ai_setup_health', 'inspect_mcp_setup'],
|
||||
mcpServers: [{
|
||||
id: 'server-1',
|
||||
name: 'Broken',
|
||||
transport: 'stdio',
|
||||
command: '',
|
||||
args: [],
|
||||
env: {},
|
||||
enabled: true,
|
||||
timeoutSeconds: 1,
|
||||
}],
|
||||
mcpClientStatuses: [{
|
||||
client: 'codex',
|
||||
displayName: 'Codex',
|
||||
installed: true,
|
||||
matchesCurrent: true,
|
||||
clientDetected: true,
|
||||
clientCommand: 'codex',
|
||||
clientPath: 'C:/Tools/codex.exe',
|
||||
configPath: 'C:/Users/demo/.codex/config.toml',
|
||||
command: 'gonavi-mcp-server',
|
||||
args: ['stdio'],
|
||||
message: '已接入当前 GoNavi MCP',
|
||||
}],
|
||||
mcpTools: [],
|
||||
skills: [{
|
||||
id: 'skill-1',
|
||||
name: '结构审查',
|
||||
description: '优先核对字段',
|
||||
systemPrompt: '先看字段和索引,再给结论。',
|
||||
enabled: true,
|
||||
scopes: ['database'],
|
||||
requiredTools: ['get_columns'],
|
||||
}],
|
||||
userPromptSettings: {
|
||||
global: '回答前先核对上下文。',
|
||||
database: '',
|
||||
jvm: '',
|
||||
jvmDiagnostic: '',
|
||||
},
|
||||
activeContext: {
|
||||
connectionId: 'conn-1',
|
||||
dbName: 'crm',
|
||||
},
|
||||
activeContextItems: [{
|
||||
dbName: 'crm',
|
||||
tableName: 'orders',
|
||||
ddl: 'CREATE TABLE orders (...)',
|
||||
}],
|
||||
});
|
||||
|
||||
expect(snapshot.status).toBe('needs_attention');
|
||||
expect(snapshot.summary.mcpServerConfigurationIssueCount).toBe(2);
|
||||
expect(snapshot.summary.mcpServersWithConfigurationErrors).toBe(1);
|
||||
expect(snapshot.warnings).toContain('有 1 个 MCP 服务存在启动配置错误,测试和工具发现可能失败');
|
||||
expect(snapshot.nextActions).toContain('先修复 MCP 服务配置检查里的错误项,再重新测试服务');
|
||||
expect(snapshot.mcp.servers[0].configurationIssues.map((issue) => issue.key)).toContain('command-missing');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -109,6 +109,8 @@ export const buildAISetupHealthSnapshot = (params: {
|
||||
appendUnique(warnings, '当前还没有配置任何 MCP 服务');
|
||||
appendUnique(nextActions, '如需扩展 AI 工具能力,可新增并测试至少 1 个 MCP 服务');
|
||||
}
|
||||
mcpSnapshot.warnings.forEach((warning) => appendUnique(warnings, warning));
|
||||
mcpSnapshot.nextActions.forEach((action) => appendUnique(nextActions, action));
|
||||
if (mcpSnapshot.currentClientCount === 0) {
|
||||
appendUnique(warnings, 'Claude Code / Codex 还没有任何客户端接入当前 GoNavi MCP');
|
||||
appendUnique(nextActions, '如需让外部 CLI 使用 GoNavi MCP,先把当前 GoNavi 接入 Claude Code 或 Codex');
|
||||
@@ -160,6 +162,8 @@ export const buildAISetupHealthSnapshot = (params: {
|
||||
customPromptCount: guidanceSnapshot.customPromptCount,
|
||||
mcpServerCount: mcpSnapshot.serverCount,
|
||||
enabledMCPServerCount: mcpSnapshot.enabledServerCount,
|
||||
mcpServerConfigurationIssueCount: mcpSnapshot.serverConfigurationIssueCount,
|
||||
mcpServersWithConfigurationErrors: mcpSnapshot.serversWithConfigurationErrors,
|
||||
installedExternalClientCount: mcpSnapshot.installedClientCount,
|
||||
currentExternalClientCount: mcpSnapshot.currentClientCount,
|
||||
discoveredMCPToolCount: mcpSnapshot.discoveredMCPToolCount,
|
||||
|
||||
Reference in New Issue
Block a user