* 知识图谱 MCP 工具
*
* harmonyos_graph_search — 搜索图谱节点
* harmonyos_graph_neighbors — 获取节点邻居
* harmonyos_graph_path — 查找两节点间路径
* harmonyos_graph_stats — 图谱统计
*/
import { z } from 'zod';
import { graphSearch, graphNeighbors, graphPath, graphStats, getAllNodeIds, } from '../lib/graph.js';
import { guardKnowledge } from './setup.js';
const TYPE_EMOJI = {
kit: '📦',
module: '📡',
component: '🧩',
guide: '📖',
error_code: '⚠️',
};
const RELATION_LABEL = {
belongs_to: '属于 →',
contains: '包含 →',
references: '引用 →',
related: '关联 →',
};
function formatNode(n) {
const emoji = TYPE_EMOJI[n.type] || '•';
return `${emoji} **${n.name}** \`${n.id}\``;
}
function formatEdge(e) {
const label = RELATION_LABEL[e.relation] || e.relation;
return `\`${e.from}\` ${label} \`${e.to}\``;
}
const GraphSearchSchema = z.object({
query: z.string()
.min(1, '查询不能为空')
.describe('搜索关键词,匹配节点名称或 ID。如 "Canvas"、"@ohos.app.ability"、"ArkUI"'),
type: z.enum(['kit', 'module', 'component', 'guide', 'error_code'])
.optional()
.describe('限定节点类型'),
maxResults: z.number().int().min(1).max(100).default(30)
.describe('最大结果数'),
}).strict();
export function registerGraphSearchTool(server) {
server.registerTool('harmonyos_graph_search', {
title: 'Search Knowledge Graph',
description: `在 HarmonyOS 知识图谱中搜索节点。
知识图谱包含 Kit、API 模块、UI 组件、开发指南等节点及其关系。
**节点类型:**
- kit: HarmonyOS Kit(AbilityKit, ArkUI, ArkTS...)
- module: @ohos.* API 模块
- component: ArkUI 组件(Button, List, Canvas...)
- guide: 开发指南章节
**使用场景:**
- 查找某个 API 模块属于哪个 Kit
- 发现与某个组件相关的所有模块
- 了解 Kit 的组成结构`,
inputSchema: GraphSearchSchema,
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: true,
},
}, async (params) => {
const guard = guardKnowledge();
if (guard)
return { content: [{ type: 'text', text: guard }] };
const results = graphSearch(params.query, {
type: params.type,
maxResults: params.maxResults,
});
if (results.length === 0) {
return {
content: [{ type: 'text', text: `未找到匹配 "${params.query}" 的图谱节点。` }],
};
}
const lines = [
`# 图谱搜索: "${params.query}"`,
'',
`找到 ${results.length} 个节点:`,
'',
];
for (const n of results) {
lines.push(formatNode(n));
if (n.path)
lines.push(` 📁 \`${n.path}\``);
if (n.kit)
lines.push(` 📦 Kit: ${n.kit}`);
lines.push(` 💡 使用 \`harmonyos_graph_neighbors\` 查看关联节点,nodeId: \`${n.id}\``);
lines.push('');
}
return {
content: [{ type: 'text', text: lines.join('\n') }],
};
});
}
const GraphNeighborsSchema = z.object({
nodeId: z.string()
.min(1, '节点 ID 不能为空')
.describe('节点 ID,从 harmonyos_graph_search 结果中获取。如 "module:ohos_app_ability_Ability"'),
direction: z.enum(['in', 'out', 'both']).default('both')
.describe('边的方向:in(入边)、out(出边)、both(两者)'),
relation: z.enum(['belongs_to', 'contains', 'references', 'related'])
.optional()
.describe('限定关系类型'),
maxResults: z.number().int().min(1).max(100).default(30)
.describe('最大结果数'),
}).strict();
export function registerGraphNeighborsTool(server) {
server.registerTool('harmonyos_graph_neighbors', {
title: 'Get Graph Neighbors',
description: `获取知识图谱中某个节点的邻居节点和关系。
**使用场景:**
- 了解某个 Kit 包含哪些模块和组件
- 查找某个模块属于哪个 Kit
- 发现与某文档交叉引用的其他文档
**方向:**
- out: 从该节点出发的边(如 Kit → 包含的模块)
- in: 指向该节点的边(如 模块 → 所属的 Kit)
- both: 所有相关边`,
inputSchema: GraphNeighborsSchema,
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: true,
},
}, async (params) => {
const guard = guardKnowledge();
if (guard)
return { content: [{ type: 'text', text: guard }] };
const result = graphNeighbors(params.nodeId, {
direction: params.direction,
relation: params.relation,
maxResults: params.maxResults,
});
if (!result) {
const allIds = getAllNodeIds();
const lower = params.nodeId.toLowerCase();
const suggestions = allIds
.filter(id => id.toLowerCase().includes(lower))
.slice(0, 5);
let text = `未找到节点 "${params.nodeId}"。`;
if (suggestions.length > 0) {
text += `\n\n你可能想搜索:\n${suggestions.map(s => `- \`${s}\``).join('\n')}`;
}
text += '\n\n使用 harmonyos_graph_search 搜索节点。';
return { content: [{ type: 'text', text }] };
}
const lines = [
`# 节点: ${formatNode(result.node)}`,
'',
`${result.edges.length} 个关联:`,
'',
];
const byRelation = new Map();
for (const e of result.edges) {
const key = e.relation;
if (!byRelation.has(key))
byRelation.set(key, []);
byRelation.get(key).push(e);
}
for (const [rel, relEdges] of byRelation) {
lines.push(`## ${RELATION_LABEL[rel] || rel} (${relEdges.length})`);
for (const e of relEdges.slice(0, 15)) {
const neighborId = e.from === result.node.id ? e.to : e.from;
lines.push(`- \`${neighborId}\``);
}
if (relEdges.length > 15) {
lines.push(`- ... 还有 ${relEdges.length - 15} 个`);
}
lines.push('');
}
return {
content: [{ type: 'text', text: lines.join('\n') }],
};
});
}
const GraphPathSchema = z.object({
from: z.string()
.describe('起始节点 ID'),
to: z.string()
.describe('目标节点 ID'),
maxDepth: z.number().int().min(2).max(6).default(4)
.describe('最大搜索深度'),
}).strict();
export function registerGraphPathTool(server) {
server.registerTool('harmonyos_graph_path', {
title: 'Find Graph Path',
description: `在知识图谱中查找两个节点之间的关联路径。
使用 BFS 算法查找从起始节点到目标节点的最短路径。
**使用场景:**
- 理解 API 模块和 Kit 之间的依赖关系
- 发现两个组件之间通过哪些文档关联
- 追踪某个功能的上下游依赖
**返回:** 路径上的节点序列和边序列。`,
inputSchema: GraphPathSchema,
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: true,
},
}, async (params) => {
const guard = guardKnowledge();
if (guard)
return { content: [{ type: 'text', text: guard }] };
const result = graphPath(params.from, params.to, params.maxDepth);
if (!result) {
return {
content: [{
type: 'text',
text: `在深度 ${params.maxDepth} 内未找到从 "${params.from}" 到 "${params.to}" 的路径。\n\n可能原因:\n- 两个节点之间距离太远\n- 节点 ID 不正确\n- 增大 maxDepth 参数重试`,
}],
};
}
const lines = [
`# 图谱路径: "${params.from}" → "${params.to}"`,
'',
`路径长度: ${result.nodes.length} 个节点, ${result.edges.length} 条边`,
'',
'## 节点序列',
];
for (let i = 0; i < result.nodes.length; i++) {
const arrow = i < result.nodes.length - 1 ? ' ↓' : '';
lines.push(`${i + 1}. ${formatNode(result.nodes[i])}${arrow}`);
}
lines.push('');
lines.push('## 边序列');
for (const e of result.edges) {
lines.push(`- ${formatEdge(e)}`);
}
return {
content: [{ type: 'text', text: lines.join('\n') }],
};
});
}
const GraphStatsSchema = z.object({}).strict();
export function registerGraphStatsTool(server) {
server.registerTool('harmonyos_graph_stats', {
title: 'Graph Statistics',
description: `获取 HarmonyOS 知识图谱的统计信息。
返回节点总数、边总数、各类型分布,以及 Top Kit(按模块和组件数量排序)。
**使用场景:**
- 了解知识图谱的覆盖范围
- 查看哪些 Kit 的文档最丰富
- 快速评估 HarmonyOS 的能力分布`,
inputSchema: GraphStatsSchema,
annotations: {
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: true,
},
}, async () => {
const guard = guardKnowledge();
if (guard)
return { content: [{ type: 'text', text: guard }] };
const stats = graphStats();
const lines = [
'# 知识图谱统计',
'',
`| 指标 | 值 |`,
`|------|-----|`,
`| 节点总数 | ${stats.nodeCount.toLocaleString()} |`,
`| 边总数 | ${stats.edgeCount.toLocaleString()} |`,
'',
'## 节点类型分布',
'',
'| 类型 | 数量 |',
'|------|------|',
];
for (const [type, count] of Object.entries(stats.nodeTypes).sort((a, b) => b[1] - a[1])) {
const emoji = TYPE_EMOJI[type] || '';
lines.push(`| ${emoji} ${type} | ${count.toLocaleString()} |`);
}
lines.push('');
lines.push('## 边类型分布');
lines.push('');
lines.push('| 关系 | 数量 |');
lines.push('|------|------|');
for (const [rel, count] of Object.entries(stats.edgeTypes).sort((a, b) => b[1] - a[1])) {
const label = RELATION_LABEL[rel] || rel;
lines.push(`| ${label} | ${count.toLocaleString()} |`);
}
lines.push('');
lines.push('## Top Kit(按模块+组件数量)');
lines.push('');
for (let i = 0; i < stats.topKits.length; i++) {
const k = stats.topKits[i];
lines.push(`${i + 1}. **${k.name}** — ${k.moduleCount} 模块, ${k.componentCount} 组件`);
}
return {
content: [{ type: 'text', text: lines.join('\n') }],
};
});
}