@obiwan90/edgedb-mcp-server
Version:
edgedb mcp server
220 lines (219 loc) • 9.41 kB
JavaScript
/**
* 查询相关MCP工具
* Query related MCP tools
*/
import { z } from "zod";
import { getClient } from "../services/edgedb.js";
import { handleError } from "../utils/errors.js";
/**
* 注册查询相关工具
* Register query related tools
* @param server MCP服务器实例 (MCP server instance)
*/
export function registerQueryTools(server) {
/**
* 执行EdgeQL查询工具
* Execute EdgeQL query tool
*/
server.tool("executeEdgeQL", { query: z.string().describe("EdgeQL query statement") }, async ({ query }, extra) => {
try {
const client = getClient();
// 执行EdgeQL查询
// Execute EdgeQL query
const result = await client.query(query);
return {
content: [{
type: "text",
text: JSON.stringify(result, null, 2)
}]
};
}
catch (error) {
return handleError(error, "执行EdgeQL查询", "请检查查询语法和类型是否正确");
}
});
/**
* 执行带参数的EdgeQL查询工具
* Execute EdgeQL query with parameters tool
*/
server.tool("executeEdgeQLWithParams", {
query: z.string().describe("EdgeQL parameterized query statement, using $parameters, e.g.: SELECT User FILTER .name = $name"),
params: z.string().describe("Parameter JSON object, e.g.: {\"name\":\"John\"}")
}, async ({ query, params }, extra) => {
try {
const client = getClient();
// 解析参数
// Parse parameters
let paramsObj;
try {
paramsObj = JSON.parse(params);
}
catch (e) {
throw new Error(`参数格式错误,必须是有效的JSON: ${e.message}`);
}
// 自动处理参数类型,检查查询中是否为每个参数添加了类型转换
// Automatically process parameter types, check if type conversion is added for each parameter in the query
let processedQuery = query;
for (const paramName in paramsObj) {
const paramPlaceholder = `$${paramName}`;
// 如果参数没有类型标注(<type>$param),自动添加
// If parameter has no type annotation (<type>$param), add it automatically
if (processedQuery.includes(paramPlaceholder) &&
!processedQuery.includes("<") &&
!new RegExp(`<[^>]+>${paramPlaceholder}`).test(processedQuery)) {
// 根据参数值类型推断EdgeDB类型
// Infer EdgeDB type based on parameter value type
let typeStr = "str";
const paramValue = paramsObj[paramName];
if (typeof paramValue === "number") {
if (Number.isInteger(paramValue)) {
typeStr = "int64";
}
else {
typeStr = "float64";
}
}
else if (typeof paramValue === "boolean") {
typeStr = "bool";
}
// 替换参数为带类型标注的形式
// Replace parameter with type-annotated form
processedQuery = processedQuery.replace(new RegExp(`\\${paramPlaceholder}\\b`, "g"), `<${typeStr}>${paramPlaceholder}`);
}
}
// 执行参数化查询
// Execute parameterized query
const result = await client.queryJSON(processedQuery, paramsObj);
// 解析JSON结果
// Parse JSON result
let parsedResult;
try {
parsedResult = JSON.parse(result);
}
catch (e) {
return {
content: [{
type: "text",
text: `查询结果无法解析为JSON: ${result}`
}]
};
}
return {
content: [{
type: "text",
text: JSON.stringify(parsedResult, null, 2)
}]
};
}
catch (error) {
return handleError(error, "执行参数化查询", "请检查查询语法和参数是否正确");
}
});
/**
* 查询单条记录工具
* Query single record tool
*/
server.tool("findOne", {
type: z.string().describe("Type name, e.g.: myapp::User"),
filter: z.string().describe("Filter condition, e.g.: .name = 'John'"),
fields: z.string().optional().describe("Fields to return, e.g.: {name, email}, default is all fields {*}")
}, async ({ type, filter, fields }, extra) => {
try {
const client = getClient();
// 使用executeEdgeQL工具实现,不再直接构建查询
// Implement using executeEdgeQL tool, no longer directly building the query
const { executeEdgeQL } = await import("./internal/query-helpers.js");
// 处理字段选择,确保格式正确
// Process field selection, ensure correct format
let fieldsStr = fields || '{*}';
// 确保字段选择有花括号
// Ensure field selection has curly braces
if (!fieldsStr.startsWith('{')) {
fieldsStr = `{${fieldsStr}}`;
}
if (!fieldsStr.endsWith('}')) {
fieldsStr = `${fieldsStr}}`;
}
// 构建正确格式的EdgeQL查询,确保字段选择紧跟类型名称
// Build correctly formatted EdgeQL query, ensure field selection follows type name
const queryStr = `SELECT ${type} ${fieldsStr} FILTER ${filter} LIMIT 1`;
console.log("执行查询:", queryStr);
const queryResults = await executeEdgeQL(client, queryStr);
if (!queryResults || queryResults.length === 0) {
return {
content: [{
type: "text",
text: "未找到匹配的记录"
}]
};
}
return {
content: [{
type: "text",
text: JSON.stringify(queryResults[0], null, 2)
}]
};
}
catch (error) {
console.error("查询单条记录错误:", error);
return handleError(error, "查询单条记录", "请检查类型名称和过滤条件。确保格式为: SELECT [类型] {[字段]} FILTER [条件]");
}
});
/**
* 查询多条记录工具
* Query multiple records tool
*/
server.tool("findMany", {
type: z.string().describe("Type name, e.g.: myapp::User"),
filter: z.string().optional().describe("Filter condition, e.g.: .name LIKE '%John%'"),
fields: z.string().optional().describe("Fields to return, e.g.: {name, email}, default is all fields {*}"),
orderBy: z.string().optional().describe("Order by condition, e.g.: .name ASC"),
limit: z.number().optional().describe("Maximum number of records to return"),
offset: z.number().optional().describe("Number of records to skip")
}, async ({ type, filter, fields, orderBy, limit, offset }, extra) => {
try {
const client = getClient();
// 使用executeEdgeQL工具实现,不再直接构建查询
const { executeEdgeQL } = await import("./internal/query-helpers.js");
// 处理字段选择,确保格式正确
let fieldsStr = fields || '{*}';
// 确保字段选择有花括号
if (!fieldsStr.startsWith('{')) {
fieldsStr = `{${fieldsStr}}`;
}
if (!fieldsStr.endsWith('}')) {
fieldsStr = `${fieldsStr}}`;
}
// 构建正确格式的EdgeQL查询,确保字段选择紧跟类型名称
let queryStr = `SELECT ${type} ${fieldsStr}`;
// 添加过滤条件
if (filter) {
queryStr += ` FILTER ${filter}`;
}
// 添加排序
if (orderBy) {
queryStr += ` ORDER BY ${orderBy}`;
}
// 添加限制
if (limit !== undefined) {
queryStr += ` LIMIT ${limit}`;
}
// 添加偏移
if (offset !== undefined) {
queryStr += ` OFFSET ${offset}`;
}
console.log("执行查询:", queryStr);
const queryResults = await executeEdgeQL(client, queryStr);
return {
content: [{
type: "text",
text: JSON.stringify(queryResults, null, 2)
}]
};
}
catch (error) {
console.error("查询多条记录错误:", error);
return handleError(error, "查询多条记录", "请检查类型名称和查询条件。确保格式为: SELECT [类型] {[字段]} FILTER [条件]");
}
});
}