Files
MyGoNavi/frontend/src/utils/mcpServerGuidance.ts
2026-06-09 16:21:03 +08:00

153 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
export type MCPFieldState = 'required' | 'optional' | 'fixed';
export interface MCPFieldGuide {
key: string;
title: string;
summary: string;
detail: string;
fieldState: MCPFieldState;
example?: string;
}
export interface MCPFillStep {
step: string;
title: string;
detail: string;
}
export interface MCPTroubleshootingGuide {
key: string;
symptom: string;
likelyCause: string;
fix: string;
example?: string;
}
export const MCP_COMMAND_EXAMPLES = [
'uvx mcp-server-fetch',
'node server.js --stdio',
'python -m your_mcp_server',
];
export const MCP_COMMAND_PARSE_EXAMPLE = 'OPENAI_API_KEY=... uvx mcp-server-fetch --stdio';
export const MCP_SERVER_FILL_STEPS: MCPFillStep[] = [
{ step: '1', title: '模板 / 完整命令', detail: '优先选最接近的模板,或先粘一整行命令让 GoNavi 自动拆分。' },
{ step: '2', title: '服务名称', detail: '命名成 Browser、GitHub、Filesystem 这类一眼能认出的用途名。' },
{ step: '3', title: '启动命令', detail: '这里只填程序名或启动器本身,不要把整行命令塞进去。' },
{ step: '4', title: '命令参数', detail: '把脚本名、模块名和 --stdio 这类参数拆开逐项填写。' },
{ step: '5', title: '环境变量 / 超时', detail: '只有在服务确实需要额外配置时再补,不需要可以留空。' },
];
export const MCP_FIELD_GUIDES: MCPFieldGuide[] = [
{
key: 'name',
title: '服务名称',
summary: '保存后显示给你和 AI 看的名字。',
detail: '按用途命名,建议写成 Browser、GitHub、Filesystem 这类一眼能认出的名字。',
fieldState: 'required',
example: 'Filesystem / Browser / GitHub',
},
{
key: 'enabled',
title: '启用状态',
summary: '控制这条配置现在要不要参与工具发现和调用。',
detail: '禁用只是不使用,不会删除下面填好的配置。',
fieldState: 'optional',
example: '已启用 / 已禁用',
},
{
key: 'transport',
title: '传输方式',
summary: 'GoNavi 用什么方式和这个 MCP Server 通信。',
detail: '当前固定为 stdio表示本机直接启动进程并通过标准输入输出交互。',
fieldState: 'fixed',
example: 'stdio',
},
{
key: 'command',
title: '启动命令',
summary: '只填程序名或启动器本身。',
detail: '常见是 node、uvx、python脚本名和 --stdio 这类内容放到参数里。',
fieldState: 'required',
example: 'node / uvx / python',
},
{
key: 'args',
title: '命令参数',
summary: '把脚本名、模块名、开关参数拆开逐项填写。',
detail: '例如 node server.js --stdio要拆成 server.js 和 --stdio 两项。',
fieldState: 'optional',
example: 'server.js / --stdio / -m / your_mcp_server',
},
{
key: 'env',
title: '环境变量',
summary: '给 MCP Server 传入 KEY=VALUE 形式的配置。',
detail: '通常用来放 API Key、服务地址、工作目录等每行一条不要写 export。',
fieldState: 'optional',
example: 'OPENAI_API_KEY=... / GITHUB_TOKEN=...',
},
{
key: 'timeout',
title: '超时(秒)',
summary: '单次工具发现或调用最多等待多久。',
detail: '本机常规工具一般 20 秒就够,启动慢或远端链路再适当调大。',
fieldState: 'optional',
example: '20 / 45 / 60',
},
];
export const MCP_AUTHORING_NOTES = [
'启动命令只填程序本身,不要把脚本名、模块名和 --stdio 混进去。',
'如果 README 里只给了一整行命令,优先粘到完整命令框自动拆分。',
'环境变量每行一条 KEY=VALUE不要写 export也不要和启动命令混成一行保存。',
'密钥类环境变量会保存到本机配置,并只在启动 MCP 进程时作为进程环境传入;不要把密钥写进聊天内容。',
'测试工具发现只会临时启动一次做探测,不会自动保存配置。',
];
export const MCP_TROUBLESHOOTING_GUIDES: MCPTroubleshootingGuide[] = [
{
key: 'command-not-found',
symptom: '测试提示找不到命令',
likelyCause: '启动命令填了整串命令、命令没加入 PATH或 Windows 路径里有空格但没有用真实 exe 路径。',
fix: '启动命令只填可执行程序本身;脚本名和 --stdio 放到命令参数里。命令不在 PATH 时,直接填绝对路径。',
example: 'command=node, args=server.js / --stdio',
},
{
key: 'timeout-or-no-tools',
symptom: '测试超时或发现 0 个工具',
likelyCause: '服务启动慢、缺少 stdio 参数,或填成了只支持 HTTP/SSE 的 MCP 服务。',
fix: '先确认这个服务支持 stdio再补齐 --stdio 等参数;启动慢时把超时调到 45 或 60 秒。',
example: 'args=--stdio, timeout=45',
},
{
key: 'auth-failed',
symptom: '认证失败、401 或 403',
likelyCause: 'API Key、Token、服务地址等环境变量没有填或 KEY=VALUE 格式无效。',
fix: '在环境变量里每行写一条 KEY=VALUE不要写 export也不要把环境变量和启动命令混到同一行保存。',
example: 'GITHUB_TOKEN=...',
},
{
key: 'stdio-only',
symptom: 'README 只给了 URL 或 SSE 配置',
likelyCause: '这类配置通常不是本机 stdio 进程,当前 GoNavi 新增 MCP 服务暂不直接支持。',
fix: '优先找该服务的 stdio 启动方式;如果只有 HTTP/SSE请先用官方网关或本机包装器转成 stdio。',
example: '当前只支持 stdio',
},
];
const quoteCommandPart = (value: string): string => {
const text = String(value || '').trim();
if (!text) {
return '';
}
return /[\s"]/u.test(text) ? `"${text.replace(/"/g, '\\"')}"` : text;
};
export const buildMCPLaunchPreview = (command: string, args?: string[]): string =>
[command, ...(Array.isArray(args) ? args : [])]
.map((item) => quoteCommandPart(item))
.filter(Boolean)
.join(' ');