n8n
Version:
n8n Workflow Automation Tool
119 lines • 5.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createExploreNodeResourcesTool = void 0;
const zod_1 = __importDefault(require("zod"));
const constants_1 = require("./constants");
const mcp_constants_1 = require("../../mcp.constants");
const inputSchema = {
nodeType: zod_1.default
.string()
.describe('Fully-qualified node type ID from search_nodes / get_node_types, e.g. "n8n-nodes-base.slack".'),
version: zod_1.default
.number()
.describe('Node version, e.g. 4.7. Must match a version returned by search_nodes.'),
methodName: zod_1.default
.string()
.describe("The exact method name from the node's `@searchListMethod` or `@loadOptionsMethod` annotation in the type definition. " +
'Call get_node_types first to read the real method name. Do not invent or guess.'),
methodType: zod_1.default
.enum(['listSearch', 'loadOptions'])
.describe('"listSearch" for `@searchListMethod` annotations (supports filter/pagination); ' +
'"loadOptions" for `@loadOptionsMethod` annotations.'),
credentialType: zod_1.default
.string()
.describe('Credential type key for the node, e.g. "slackApi" or "googleSheetsOAuth2Api".'),
credentialId: zod_1.default
.string()
.describe('ID of a credential the user can access, obtained from list_credentials.'),
filter: zod_1.default.string().optional().describe('Optional search/filter text to narrow results.'),
paginationToken: zod_1.default
.string()
.optional()
.describe('Pagination token from a previous call to fetch the next page (listSearch only).'),
currentNodeParameters: zod_1.default
.record(zod_1.default.unknown())
.optional()
.describe('Current node parameters for dependent lookups. Some methods require prior selections — ' +
'e.g. listing sheets within a spreadsheet needs `{ documentId: { __rl: true, mode: "id", value: "<spreadsheetId>" } }`. ' +
"Check the type definition's displayOptions to know which parameters a method depends on."),
};
const outputSchema = {
results: zod_1.default
.array(zod_1.default.object({
name: zod_1.default.string(),
value: zod_1.default.union([zod_1.default.string(), zod_1.default.number(), zod_1.default.boolean()]),
url: zod_1.default.string().optional(),
description: zod_1.default.string().optional(),
}))
.describe('Resources returned by the node method. `value` is the id to use in workflow code.'),
paginationToken: zod_1.default
.string()
.optional()
.describe('Pass back as `paginationToken` to fetch the next page. Absent if no more results.'),
builderHint: zod_1.default
.string()
.optional()
.describe("Selection guidance from the node's @builderHint annotation, when present."),
};
const createExploreNodeResourcesTool = (user, nodeResourceExplorerService, telemetry) => ({
name: constants_1.MCP_EXPLORE_NODE_RESOURCES_TOOL.toolName,
config: {
description: "Resolve the real values behind a node's resource locator or load-options dropdown (e.g. Slack channels, Google Sheets tabs, OpenAI models). " +
'Use this after get_node_types so you ground RLC and load-options parameters in real IDs instead of inventing them. ' +
'Requires a credential ID from list_credentials — the call runs as the current user with that credential.',
inputSchema,
outputSchema,
annotations: {
title: constants_1.MCP_EXPLORE_NODE_RESOURCES_TOOL.displayTitle,
readOnlyHint: true,
destructiveHint: false,
idempotentHint: true,
openWorldHint: true,
},
},
handler: async (params) => {
const telemetryPayload = {
user_id: user.id,
tool_name: constants_1.MCP_EXPLORE_NODE_RESOURCES_TOOL.toolName,
parameters: {
nodeType: params.nodeType,
version: params.version,
methodName: params.methodName,
methodType: params.methodType,
credentialType: params.credentialType,
hasFilter: params.filter !== undefined,
hasPaginationToken: params.paginationToken !== undefined,
hasCurrentNodeParameters: params.currentNodeParameters !== undefined,
},
};
try {
const result = await nodeResourceExplorerService.exploreResources(user, params);
telemetryPayload.results = {
success: true,
data: {
resultCount: result.results.length,
hasPaginationToken: result.paginationToken !== undefined,
hasBuilderHint: result.builderHint !== undefined,
},
};
telemetry.track(mcp_constants_1.USER_CALLED_MCP_TOOL_EVENT, telemetryPayload);
return {
content: [{ type: 'text', text: JSON.stringify(result) }],
structuredContent: { ...result },
};
}
catch (error) {
telemetryPayload.results = {
success: false,
error: error instanceof Error ? error.name : 'UnknownError',
};
telemetry.track(mcp_constants_1.USER_CALLED_MCP_TOOL_EVENT, telemetryPayload);
throw error;
}
},
});
exports.createExploreNodeResourcesTool = createExploreNodeResourcesTool;
//# sourceMappingURL=explore-node-resources.tool.js.map