UNPKG

@obiwan90/edgedb-mcp-server

Version:
291 lines (285 loc) 10.9 kB
/** * 模式管理相关MCP工具 * Schema management related MCP tools */ import { z } from "zod"; import { getClient } from "../services/edgedb.js"; import { handleError } from "../utils/errors.js"; /** * 注册模式管理相关工具 * Register schema management related tools * @param server MCP服务器实例 (MCP server instance) */ export function registerSchemaTools(server) { /** * 列出类型工具 * List types tool */ server.tool("listTypes", { includeSystem: z.boolean().optional().describe("Whether to include system types") }, async ({ includeSystem }, extra) => { try { const client = getClient(); // 根据EdgeDB版本构建查询 // Build query based on EdgeDB version let query; if (includeSystem) { query = ` SELECT schema::ObjectType { name, is_abstract, bases: { name } } ORDER BY .name; `; } else { query = ` SELECT schema::ObjectType { name, is_abstract, bases: { name } } FILTER NOT .name LIKE 'schema::%' AND NOT .name LIKE 'sys::%' AND NOT .name LIKE 'std::%' AND NOT .name LIKE 'cfg::%' ORDER BY .name; `; } const result = await client.query(query); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } catch (error) { return handleError(error, "获取类型列表", "请检查数据库连接和权限"); } }); /** * 描述类型工具 * Describe type tool */ server.tool("describeType", { name: z.string().describe("Type name, e.g.: myapp::User") }, async ({ name }, extra) => { try { const client = getClient(); // 查询类型信息 // Query type information const result = await client.query(` SELECT schema::ObjectType { name, is_abstract, bases: { name }, annotations: { name, @value }, properties: { name, required, readonly, cardinality, target: { name, __type__: {name} }, annotations: { name, @value } } ORDER BY .name, links: { name, required, readonly, cardinality, target: { name }, annotations: { name, @value } } ORDER BY .name, indexes: { expr }, constraints: { name, expr, annotations: { name, @value } } } FILTER .name = <str>$name; `, { name }); if (result.length === 0) { return { content: [{ type: "text", text: `类型 '${name}' 不存在` }], isError: true }; } return { content: [{ type: "text", text: JSON.stringify(result[0], null, 2) }] }; } catch (error) { return handleError(error, "获取类型详情", "请检查类型名称是否正确"); } }); /** * 比较两个类型的模式结构 * Compare schema structure of two types */ server.tool("compareSchemas", { sourceType: z.string().describe("Source type name, e.g.: myapp::User"), targetType: z.string().describe("Target type name, e.g.: myapp::Profile") }, async ({ sourceType, targetType }, extra) => { try { const client = getClient(); // 获取两个类型的属性 const sourcePropertiesResult = await client.query(` SELECT schema::ObjectType { name, properties: { name, required, target: { name } } ORDER BY .name, links: { name, required, target: { name } } ORDER BY .name } FILTER .name = <str>$name; `, { name: sourceType }); const targetPropertiesResult = await client.query(` SELECT schema::ObjectType { name, properties: { name, required, target: { name } } ORDER BY .name, links: { name, required, target: { name } } ORDER BY .name } FILTER .name = <str>$name; `, { name: targetType }); if (sourcePropertiesResult.length === 0) { return { content: [{ type: "text", text: `源类型 '${sourceType}' 不存在` }], isError: true }; } if (targetPropertiesResult.length === 0) { return { content: [{ type: "text", text: `目标类型 '${targetType}' 不存在` }], isError: true }; } // 使用类型断言明确数据类型 const sourceProperties = sourcePropertiesResult[0]; const targetProperties = targetPropertiesResult[0]; // 分析差异 const comparison = { source: sourceType, target: targetType, propertyDifferences: [], linkDifferences: [], sourceOnlyProperties: [], targetOnlyProperties: [], sourceOnlyLinks: [], targetOnlyLinks: [] }; // 比较属性 const sourceProps = sourceProperties.properties; const targetProps = targetProperties.properties; const sourcePropsMap = new Map(sourceProps.map((p) => [p.name, p])); const targetPropsMap = new Map(targetProps.map((p) => [p.name, p])); // 查找源中有但目标中没有的属性 sourceProps.forEach((prop) => { if (!targetPropsMap.has(prop.name)) { comparison.sourceOnlyProperties.push(prop); } else { const targetProp = targetPropsMap.get(prop.name); if (prop.required !== targetProp.required || prop.target.name !== targetProp.target.name) { comparison.propertyDifferences.push({ name: prop.name, source: prop, target: targetProp }); } } }); // 查找目标中有但源中没有的属性 targetProps.forEach((prop) => { if (!sourcePropsMap.has(prop.name)) { comparison.targetOnlyProperties.push(prop); } }); // 比较链接 const sourceLinks = sourceProperties.links; const targetLinks = targetProperties.links; const sourceLinksMap = new Map(sourceLinks.map((l) => [l.name, l])); const targetLinksMap = new Map(targetLinks.map((l) => [l.name, l])); // 查找源中有但目标中没有的链接 sourceLinks.forEach((link) => { if (!targetLinksMap.has(link.name)) { comparison.sourceOnlyLinks.push(link); } else { const targetLink = targetLinksMap.get(link.name); if (link.required !== targetLink.required || link.target.name !== targetLink.target.name) { comparison.linkDifferences.push({ name: link.name, source: link, target: targetLink }); } } }); // 查找目标中有但源中没有的链接 targetLinks.forEach((link) => { if (!sourceLinksMap.has(link.name)) { comparison.targetOnlyLinks.push(link); } }); return { content: [{ type: "text", text: JSON.stringify(comparison, null, 2) }] }; } catch (error) { return handleError(error, "比较模式", "请检查类型名称是否正确"); } }); }