mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-07 02:51:35 +08:00
✨ feat(ai): 完善工具目录与远程 MCP 接入指引
- 新增 inspect_ai_tool_catalog 工具,返回内置探针流程、参数提示和 MCP 工具摘要 - 拆分 AI 内置工具目录配置,降低 AIBuiltinToolsCatalog 体积 - 补充 OpenClaw/Hermans 远程 MCP Streamable HTTP 配置说明 - 增加 Linux CJK 字体缺失检测与 Ubuntu 安装提示
This commit is contained in:
@@ -111,6 +111,31 @@ export const BUILTIN_AI_INSPECTION_TOOL_INFO: AIBuiltinToolInfo[] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inspect_ai_tool_catalog",
|
||||
icon: "🧭",
|
||||
desc: "查看 AI 内置工具目录和参数提示",
|
||||
detail:
|
||||
"按关键词或工具名返回 GoNavi AI 内置工具、推荐探针流程、参数说明和当前 MCP 工具摘要。适合用户问“你该用哪个工具”“这个工具参数怎么填”“有哪些内置工具”或 AI 需要先选择探针路线时调用。",
|
||||
params: "keyword?, toolName?, includeMCPTools?(默认 true), limit?(默认 12)",
|
||||
tool: {
|
||||
type: "function",
|
||||
function: {
|
||||
name: "inspect_ai_tool_catalog",
|
||||
description:
|
||||
"读取 GoNavi AI 工具目录快照,可按关键词或工具名筛选,返回推荐工具调用流程、内置工具说明、参数提示和当前已发现 MCP 工具摘要。适用于用户询问当前有哪些内置工具、某类问题该先调用哪个探针、工具 arguments 怎么填、或 AI 在处理复杂问题前需要先选择工具路线时优先调用。",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
keyword: { type: "string", description: "可选,按问题关键词过滤工具和流程,例如 mcp、连接失败、事务、快捷键、schema、日志" },
|
||||
toolName: { type: "string", description: "可选,按内置工具名精确查询,例如 inspect_mcp_draft 或 inspect_sql_risk" },
|
||||
includeMCPTools: { type: "boolean", description: "可选,是否同时返回当前已发现的 MCP 工具摘要,默认 true" },
|
||||
limit: { type: "number", description: "可选,最多返回多少条流程、内置工具和 MCP 工具,默认 12,最大 40" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inspect_mcp_setup",
|
||||
icon: "🪛",
|
||||
|
||||
232
frontend/src/utils/aiBuiltinToolCatalog.ts
Normal file
232
frontend/src/utils/aiBuiltinToolCatalog.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
import type { AIBuiltinToolInfo } from './aiBuiltinToolInfo.types';
|
||||
|
||||
export interface AIBuiltinToolFlow {
|
||||
title: string;
|
||||
steps: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export interface AIBuiltinToolParameterHint {
|
||||
name: string;
|
||||
required: boolean;
|
||||
description: string;
|
||||
enumValues: string[];
|
||||
}
|
||||
|
||||
export const BUILTIN_TOOL_FLOWS: AIBuiltinToolFlow[] = [
|
||||
{
|
||||
title: '定位表与字段',
|
||||
steps: 'get_connections -> get_databases -> get_tables -> get_columns',
|
||||
description: '适合先找连接、找库、找表,再确认真实字段名后生成 SQL。',
|
||||
},
|
||||
{
|
||||
title: '字段反查表',
|
||||
steps: 'get_databases -> get_all_columns',
|
||||
description: '适合只知道字段名、业务含义或注释关键词,但还不确定具体落在哪张表。',
|
||||
},
|
||||
{
|
||||
title: '结构深挖',
|
||||
steps: 'get_columns -> get_indexes -> get_foreign_keys -> get_triggers -> get_table_ddl',
|
||||
description: '适合做索引优化、关系梳理、隐式副作用排查和 DDL 审查。',
|
||||
},
|
||||
{
|
||||
title: '一键结构快照',
|
||||
steps: 'inspect_table_bundle',
|
||||
description: '适合一次带回字段、索引、外键、触发器和 DDL;必要时还能附带样例行,减少来回调用。',
|
||||
},
|
||||
{
|
||||
title: '全库快速摸底',
|
||||
steps: 'inspect_database_bundle -> inspect_table_bundle',
|
||||
description: '适合先看整库有哪些表、每张表大概有哪些字段,再对目标表继续做深挖快照。',
|
||||
},
|
||||
{
|
||||
title: 'AI 应用健康总览',
|
||||
steps: 'inspect_app_health -> inspect_ai_setup_health / inspect_app_logs / inspect_recent_connection_failures / inspect_ai_last_render_error / inspect_ai_message_flow',
|
||||
description: '适合用户反馈 AI 不稳定、连接和 MCP 问题交织、回复气泡显示异常,或需要先看整体健康状态时,一次汇总配置、日志、连接失败、渲染异常、消息流和工作区现场。',
|
||||
},
|
||||
{
|
||||
title: '选择 AI 工具路线',
|
||||
steps: 'inspect_ai_tool_catalog -> inspect_ai_runtime / inspect_mcp_setup',
|
||||
description: '适合先按关键词确认该用哪些内置探针、每个工具 arguments 怎么填,以及当前有没有外部 MCP 工具可用。',
|
||||
},
|
||||
{
|
||||
title: '一键体检 AI 配置',
|
||||
steps: 'inspect_ai_setup_health -> inspect_ai_providers / inspect_mcp_setup / inspect_ai_guidance',
|
||||
description: '适合先拿到一份 AI 配置健康快照,看清当前是供应商没配好、聊天发送前置没满足、MCP 没接入,还是提示词 / Skills / 上下文还不完整,再决定往哪条探针继续下钻。',
|
||||
},
|
||||
{
|
||||
title: '查看 AI 当前能力',
|
||||
steps: 'inspect_ai_runtime -> inspect_ai_context / inspect_current_connection',
|
||||
description: '适合先确认当前模型、安全级别、上下文级别、Skills 和 MCP 工具,再决定让 AI 走哪条探针链路。',
|
||||
},
|
||||
{
|
||||
title: '核对写入安全边界',
|
||||
steps: 'inspect_ai_safety -> inspect_ai_runtime -> inspect_current_connection',
|
||||
description: '适合先确认当前是不是只读、DDL/DML 到底允不允许、MCP 写操作是否还需要 allowMutating,再决定后续该走查询、改数据还是改结构。',
|
||||
},
|
||||
{
|
||||
title: '排查供应商与模型',
|
||||
steps: 'inspect_ai_providers -> inspect_ai_runtime',
|
||||
description: '适合先确认当前到底配置了哪些供应商、哪个在生效、有没有缺密钥或没选模型,再解释为什么 AI 不能发送、为什么模型列表为空。',
|
||||
},
|
||||
{
|
||||
title: '排查聊天发送状态',
|
||||
steps: 'inspect_ai_chat_readiness -> inspect_ai_providers',
|
||||
description: '适合先确认当前聊天输入区到底缺什么前置条件,例如没选活动供应商、缺密钥、缺接口地址、没选模型,避免只凭界面现象猜测。',
|
||||
},
|
||||
{
|
||||
title: '排查 MCP 接入状态',
|
||||
steps: 'inspect_mcp_setup -> inspect_ai_runtime',
|
||||
description: '适合先确认当前配置了哪些 MCP 服务、哪些已启用、外部客户端有没有写入当前 GoNavi 路径,再结合运行时工具列表判断为什么某个工具没暴露出来。',
|
||||
},
|
||||
{
|
||||
title: '远程 Agent 接入 GoNavi MCP',
|
||||
steps: 'inspect_mcp_remote_access -> inspect_mcp_setup -> inspect_ai_safety',
|
||||
description: '适合 OpenClaw/Hermans 部署在云端 Linux,但数据库连接和密码只在 Windows GoNavi 本机时,先生成 HTTP MCP、Bearer Token、隧道和安全边界指引。',
|
||||
},
|
||||
{
|
||||
title: '新增 MCP 填写指引',
|
||||
steps: 'inspect_mcp_authoring_guide -> inspect_mcp_draft -> inspect_mcp_setup',
|
||||
description: '适合先读真实字段说明、模板样例和整行命令拆分规则,再把用户贴出的命令或草稿交给真实校验器试算,最后结合当前 MCP 配置现状判断应该新增哪种启动方式。',
|
||||
},
|
||||
{
|
||||
title: '查看 MCP 工具参数',
|
||||
steps: 'inspect_mcp_setup -> inspect_mcp_tool_schema',
|
||||
description: '适合先找到当前真实发现到的 MCP 工具 alias,再读取对应 inputSchema、必填字段、枚举和嵌套参数路径,避免调用外部 MCP 工具时乱填 arguments。',
|
||||
},
|
||||
{
|
||||
title: '查看当前提示与 Skills',
|
||||
steps: 'inspect_ai_guidance -> inspect_ai_runtime',
|
||||
description: '适合先确认当前自定义提示词、启用的 Skills、依赖工具和生效范围,再解释为什么 AI 当前会这样回答或为什么某个规则没有触发。',
|
||||
},
|
||||
{
|
||||
title: '查看当前 AI 上下文',
|
||||
steps: 'inspect_ai_context -> inspect_table_bundle / get_columns',
|
||||
description: '适合先确认这轮对话当前到底挂了哪些表结构,再继续做字段核对、表设计评审或 SQL 生成。',
|
||||
},
|
||||
{
|
||||
title: '查看当前连接',
|
||||
steps: 'inspect_current_connection -> get_databases / get_tables',
|
||||
description: '适合先确认当前活动数据源的类型、地址、当前库和 SSH/代理状态,再继续做库表探索或连接问题排查。',
|
||||
},
|
||||
{
|
||||
title: '核对数据源能力边界',
|
||||
steps: 'inspect_connection_capabilities -> inspect_current_connection',
|
||||
description: '适合先确认当前连接到底支不支持建库、删库、结果编辑、SQL 导出或近似计数,再解释为什么某些按钮没出现或某类操作只能只读。',
|
||||
},
|
||||
{
|
||||
title: '盘点本地连接资产',
|
||||
steps: 'inspect_saved_connections -> inspect_current_connection / get_databases',
|
||||
description: '适合先按关键词或类型筛出本地保存的数据源,再挑目标连接继续看当前状态或库表结构。',
|
||||
},
|
||||
{
|
||||
title: '盘点外部 SQL 目录',
|
||||
steps: 'inspect_external_sql_directories -> inspect_workspace_tabs / inspect_active_tab',
|
||||
description: '适合先确认本地配置了哪些外部 SQL 目录、目录绑定到哪个连接/库,以及当前打开的 SQL 文件来自哪里,再继续分析脚本内容。',
|
||||
},
|
||||
{
|
||||
title: '读取外部 SQL 文件',
|
||||
steps: 'inspect_external_sql_directories -> inspect_external_sql_file -> inspect_active_tab',
|
||||
description: '适合先定位具体脚本路径,再直接读取目录中的 SQL 文件内容;如果这个文件已经在编辑器里打开,再继续结合当前页签草稿一起分析。',
|
||||
},
|
||||
{
|
||||
title: '读取当前页签',
|
||||
steps: 'inspect_active_tab -> get_columns / get_indexes / execute_sql',
|
||||
description: '适合先读取当前编辑器里的 SQL 草稿或当前表页签,再继续做字段核对、索引分析和只读验证。',
|
||||
},
|
||||
{
|
||||
title: '盘点当前工作区',
|
||||
steps: 'inspect_workspace_tabs -> inspect_active_tab -> get_columns / execute_sql',
|
||||
description: '适合先看当前打开了哪些 SQL / 表 / 命令页签,再切到目标页签继续做字段核对、对比分析和只读验证。',
|
||||
},
|
||||
{
|
||||
title: '查看当前快捷键配置',
|
||||
steps: 'inspect_shortcuts -> inspect_active_tab / inspect_workspace_tabs',
|
||||
description: '适合先确认当前 Win / Mac 快捷键、是否改过默认值,以及结果区、AI 面板、查询执行等动作到底该怎么按,再结合当前页签解释具体使用场景。',
|
||||
},
|
||||
{
|
||||
title: '回看最近执行记录',
|
||||
steps: 'inspect_recent_sql_logs -> get_columns / get_indexes / execute_sql',
|
||||
description: '适合追查刚刚执行失败的 SQL、慢查询耗时,或基于真实执行历史继续让 AI 给解释和优化建议。',
|
||||
},
|
||||
{
|
||||
title: '总结最近 SQL 活动',
|
||||
steps: 'inspect_recent_sql_activity -> inspect_recent_sql_logs -> inspect_current_connection',
|
||||
description: '适合先看最近到底以读还是写为主、有没有 DDL 或删除、哪个库最近报错最多,再决定继续下钻哪条日志或哪个连接。',
|
||||
},
|
||||
{
|
||||
title: '核对 SQL 编辑器事务',
|
||||
steps: 'inspect_sql_editor_transaction -> inspect_recent_sql_activity -> inspect_sql_risk',
|
||||
description: '适合先确认 SQL 编辑器 DML 是否会进入托管事务、当前是手动还是自动提交、有没有待提交事务,再解释 update/insert/delete 执行后的提交语义。',
|
||||
},
|
||||
{
|
||||
title: 'SQL 风险预检',
|
||||
steps: 'inspect_sql_risk -> inspect_ai_safety -> execute_sql',
|
||||
description: '适合用户要求执行、删除、更新、DDL 或批量 SQL 前,先检查语句数量、写入/DDL 风险、WHERE 条件和当前安全策略,再决定是否需要用户确认。',
|
||||
},
|
||||
{
|
||||
title: '排查应用日志',
|
||||
steps: 'inspect_app_logs -> inspect_mcp_setup / inspect_saved_connections / inspect_current_connection',
|
||||
description: '适合先回看 gonavi.log 尾部的 ERROR/WARN,再结合 MCP、连接和当前数据源状态继续定位启动异常、连接失败或外部工具拉起问题。',
|
||||
},
|
||||
{
|
||||
title: '排查连接失败与冷却',
|
||||
steps: 'inspect_recent_connection_failures -> inspect_current_connection / inspect_saved_connections / inspect_app_logs',
|
||||
description: '适合用户直接问“为什么连接不上”或已经看到冷却/验证失败提示时,先拿到结构化根因、最新地址和下一步建议,再决定回到连接配置还是看更长日志。',
|
||||
},
|
||||
{
|
||||
title: '排查 AI 气泡渲染异常',
|
||||
steps: 'inspect_ai_last_render_error -> inspect_active_tab / inspect_ai_runtime',
|
||||
description: '适合用户反馈 AI 某条消息空白、气泡局部报错但整个面板没挂时,先拿到最近一次被隔离的渲染异常快照,再回到具体会话和运行时上下文继续缩小范围。',
|
||||
},
|
||||
{
|
||||
title: '诊断 AI 消息流',
|
||||
steps: 'inspect_ai_message_flow -> inspect_ai_last_render_error / inspect_app_logs',
|
||||
description: '适合用户反馈回复被拆成多个气泡、工具调用后没继续回答、消息流状态不对时,先读取当前会话的真实消息结构和异常信号。',
|
||||
},
|
||||
{
|
||||
title: '复用历史 SQL',
|
||||
steps: 'inspect_saved_queries -> get_columns / execute_sql',
|
||||
description: '适合先找本地保存过的查询脚本,再核对字段和只读验证,避免把之前写过的 SQL 重新手打一遍。',
|
||||
},
|
||||
{
|
||||
title: '回看 AI 历史对话',
|
||||
steps: 'inspect_ai_sessions -> inspect_active_tab / inspect_saved_queries',
|
||||
description: '适合先定位之前聊过的 AI 会话、首条问题和最近回复,再继续复用当前页签或历史 SQL 上下文。',
|
||||
},
|
||||
{
|
||||
title: '查找模板片段',
|
||||
steps: 'inspect_sql_snippets',
|
||||
description: '适合先找团队已有的 SQL 片段模板、补全前缀和常用骨架,再决定是否继续改写。',
|
||||
},
|
||||
{
|
||||
title: '理解样例数据',
|
||||
steps: 'get_columns -> preview_table_rows',
|
||||
description: '适合先确认字段,再直接查看前几行真实样例数据和空值形态。',
|
||||
},
|
||||
{
|
||||
title: '只读验证',
|
||||
steps: 'get_columns -> preview_table_rows -> execute_sql',
|
||||
description: '适合生成 SQL 后做小范围结果核对,仍会受 AI 安全级别控制。',
|
||||
},
|
||||
];
|
||||
|
||||
export const describeBuiltinToolParameters = (tool: AIBuiltinToolInfo): AIBuiltinToolParameterHint[] => {
|
||||
const schema = tool.tool.function.parameters;
|
||||
const properties = schema && typeof schema === 'object' && typeof schema.properties === 'object'
|
||||
? schema.properties
|
||||
: {};
|
||||
const required = new Set(
|
||||
Array.isArray(schema?.required) ? schema.required.map((item) => String(item)) : [],
|
||||
);
|
||||
|
||||
return Object.entries(properties).map(([name, config]) => {
|
||||
const normalized = config && typeof config === 'object' ? config as Record<string, any> : {};
|
||||
return {
|
||||
name,
|
||||
required: required.has(name),
|
||||
description: typeof normalized.description === 'string' ? normalized.description : '',
|
||||
enumValues: Array.isArray(normalized.enum) ? normalized.enum.map((item) => String(item)) : [],
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -76,6 +76,15 @@ describe('aiToolRegistry', () => {
|
||||
expect(info?.tool.function.description).toContain('当前 AI 聊天输入区');
|
||||
});
|
||||
|
||||
it('registers the ai-tool-catalog inspector as a builtin tool', () => {
|
||||
const info = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_ai_tool_catalog');
|
||||
expect(info).toBeTruthy();
|
||||
expect(info?.desc).toContain('内置工具目录');
|
||||
expect(info?.tool.function.description).toContain('推荐工具调用流程');
|
||||
expect(info?.tool.function.parameters?.properties?.keyword?.description).toContain('连接失败');
|
||||
expect(info?.tool.function.parameters?.properties?.includeMCPTools?.description).toContain('MCP 工具摘要');
|
||||
});
|
||||
|
||||
it('registers the ai-guidance inspector as a builtin tool', () => {
|
||||
const info = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_ai_guidance');
|
||||
expect(info).toBeTruthy();
|
||||
@@ -208,6 +217,7 @@ describe('aiToolRegistry', () => {
|
||||
expect(tools.some((item) => item.function.name === 'inspect_ai_safety')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_ai_providers')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_ai_chat_readiness')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_ai_tool_catalog')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_mcp_setup')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_mcp_remote_access')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_mcp_authoring_guide')).toBe(true);
|
||||
|
||||
33
frontend/src/utils/fontFamilies.test.ts
Normal file
33
frontend/src/utils/fontFamilies.test.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import {
|
||||
getLinuxCJKFontInstallHint,
|
||||
hasInstalledCJKFontFamily,
|
||||
} from './fontFamilies';
|
||||
|
||||
describe('fontFamilies helpers', () => {
|
||||
it('detects installed CJK font families on Linux', () => {
|
||||
expect(hasInstalledCJKFontFamily([
|
||||
{ family: 'Ubuntu' },
|
||||
{ family: 'Noto Sans CJK SC' },
|
||||
])).toBe(true);
|
||||
expect(hasInstalledCJKFontFamily([
|
||||
{ family: 'DejaVu Sans' },
|
||||
{ family: 'Liberation Sans' },
|
||||
])).toBe(false);
|
||||
});
|
||||
|
||||
it('returns an Ubuntu CJK font install hint only when Linux lacks CJK fonts', () => {
|
||||
expect(getLinuxCJKFontInstallHint('linux', [
|
||||
{ family: 'DejaVu Sans' },
|
||||
])).toBe('sudo apt install fonts-noto-cjk fonts-wqy-microhei && fc-cache -fv');
|
||||
|
||||
expect(getLinuxCJKFontInstallHint('linux', [
|
||||
{ family: 'Source Han Sans SC' },
|
||||
])).toBeNull();
|
||||
|
||||
expect(getLinuxCJKFontInstallHint('windows', [
|
||||
{ family: 'DejaVu Sans' },
|
||||
])).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,33 @@ export const DEFAULT_MONO_FONT_FAMILY =
|
||||
'"JetBrains Mono", "Noto Sans Mono CJK SC", "Noto Sans Mono", ui-monospace, "SF Mono", Menlo, Consolas, "DejaVu Sans Mono", monospace';
|
||||
|
||||
const MAX_FONT_FAMILY_LENGTH = 512;
|
||||
const LINUX_CJK_FONT_INSTALL_COMMAND = 'sudo apt install fonts-noto-cjk fonts-wqy-microhei && fc-cache -fv';
|
||||
|
||||
const CJK_FONT_KEYWORDS = [
|
||||
'noto sans cjk',
|
||||
'noto sans sc',
|
||||
'noto serif cjk',
|
||||
'noto serif sc',
|
||||
'source han sans',
|
||||
'source han serif',
|
||||
'思源',
|
||||
'wenquanyi',
|
||||
'文泉驿',
|
||||
'sarasa',
|
||||
'更纱',
|
||||
'lxgw',
|
||||
'霞鹜',
|
||||
'microsoft yahei',
|
||||
'微软雅黑',
|
||||
'simsun',
|
||||
'宋体',
|
||||
'simhei',
|
||||
'黑体',
|
||||
'pingfang',
|
||||
'苹方',
|
||||
'hiragino',
|
||||
'冬青',
|
||||
];
|
||||
|
||||
export type FontFamilyOption = {
|
||||
value: string;
|
||||
@@ -46,6 +73,11 @@ const normalizeFontSearchToken = (value: string): string => String(value || '')
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9\u4e00-\u9fff]+/gi, '');
|
||||
|
||||
const normalizeInstalledFontNameForCJK = (entry: string | InstalledFontFamily): string => {
|
||||
const raw = typeof entry === 'string' ? entry : entry.family;
|
||||
return String(raw || '').trim().toLowerCase();
|
||||
};
|
||||
|
||||
const insertFontNameWordBreaks = (value: string): string => value
|
||||
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
|
||||
.replace(/([a-z\d])([A-Z])/g, '$1 $2');
|
||||
@@ -267,6 +299,32 @@ export const resolveMonoFontFamily = (customValue: unknown): string => {
|
||||
return sanitizeFontFamilyInput(customValue) ?? DEFAULT_MONO_FONT_FAMILY;
|
||||
};
|
||||
|
||||
export const hasInstalledCJKFontFamily = (
|
||||
installedFamilies: Array<string | InstalledFontFamily>,
|
||||
): boolean => {
|
||||
return installedFamilies.some((entry) => {
|
||||
const family = normalizeInstalledFontNameForCJK(entry);
|
||||
if (!family) {
|
||||
return false;
|
||||
}
|
||||
const compactFamily = normalizeFontSearchToken(family);
|
||||
return CJK_FONT_KEYWORDS.some((keyword) => {
|
||||
const normalizedKeyword = keyword.toLowerCase();
|
||||
return family.includes(normalizedKeyword) || compactFamily.includes(normalizeFontSearchToken(normalizedKeyword));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const getLinuxCJKFontInstallHint = (
|
||||
platform: string,
|
||||
installedFamilies: Array<string | InstalledFontFamily>,
|
||||
): string | null => {
|
||||
if (String(platform || '').toLowerCase() !== 'linux') {
|
||||
return null;
|
||||
}
|
||||
return hasInstalledCJKFontFamily(installedFamilies) ? null : LINUX_CJK_FONT_INSTALL_COMMAND;
|
||||
};
|
||||
|
||||
export const getPlatformFontFamilyOptions = (
|
||||
platform: string,
|
||||
kind: "ui" | "mono",
|
||||
|
||||
@@ -134,5 +134,8 @@ describe('mcpClientInstallStatus helpers', () => {
|
||||
expect(guide).toContain('云端 Agent 不需要保存数据库密码');
|
||||
expect(guide).toContain('不能直接使用 Windows 本地 stdio 命令');
|
||||
expect(guide).toContain('allowMutating=true');
|
||||
expect(guide).toContain('"type": "streamable-http"');
|
||||
expect(guide).toContain('"Authorization": "Bearer <随机token>"');
|
||||
expect(guide).toContain('GoNavi.exe mcp-server http --addr 127.0.0.1:8765 --path /mcp --token <随机token>');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -161,6 +161,19 @@ export const buildRemoteMCPClientGuide = (
|
||||
status?: Pick<AIMCPClientInstallStatus, 'displayName' | 'message'> | null,
|
||||
): string => {
|
||||
const displayName = String(status?.displayName || '远程 Agent').trim();
|
||||
const streamableHTTPConfig = [
|
||||
'{',
|
||||
' "mcpServers": {',
|
||||
' "gonavi": {',
|
||||
' "type": "streamable-http",',
|
||||
' "url": "https://<你的域名或隧道地址>/mcp",',
|
||||
' "headers": {',
|
||||
' "Authorization": "Bearer <随机token>"',
|
||||
' }',
|
||||
' }',
|
||||
' }',
|
||||
'}',
|
||||
];
|
||||
return [
|
||||
`GoNavi MCP 远程接入说明 - ${displayName}`,
|
||||
'',
|
||||
@@ -179,6 +192,13 @@ export const buildRemoteMCPClientGuide = (
|
||||
`3. 在 ${displayName} 中添加远程 MCP Server,transport 选择 Streamable HTTP,URL 填隧道/反向代理后的 /mcp 地址,并设置 Authorization: Bearer <随机token>。`,
|
||||
'4. 先调用 get_connections 获取 connectionId,再调用表结构工具;不要把数据库 host/user/password 写进云端 Agent 配置。',
|
||||
'',
|
||||
'可复制配置片段(适用于支持 mcpServers JSON 的 Agent):',
|
||||
...streamableHTTPConfig,
|
||||
'',
|
||||
'CLI / 服务启动命令:',
|
||||
'GoNavi.exe mcp-server http --addr 127.0.0.1:8765 --path /mcp --token <随机token>',
|
||||
'或设置环境变量:GONAVI_MCP_HTTP_TOKEN=<随机token> 后运行 gonavi-mcp-server http --addr 127.0.0.1:8765 --path /mcp',
|
||||
'',
|
||||
status?.message ? `当前提示:${status.message}` : '',
|
||||
].filter((line, index, lines) => line || index < lines.length - 1).join('\n');
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user