n8n-nodes-agnicwallet 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,368 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgnicMCPTool = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
6
+ const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
7
+ const tools_1 = require("@langchain/core/tools");
8
+ const agents_1 = require("langchain/agents");
9
+ const zod_1 = require("zod");
10
+ const json_schema_to_zod_1 = require("@n8n/json-schema-to-zod");
11
+ /**
12
+ * Toolkit class that wraps MCP tools for n8n AI Agent
13
+ * Extends Toolkit from langchain/agents for proper serialization
14
+ */
15
+ class AgnicMcpToolkit extends agents_1.Toolkit {
16
+ constructor(tools) {
17
+ super();
18
+ this.tools = tools;
19
+ }
20
+ }
21
+ // Pre-configured AgnicPay MCP endpoint (uses HTTP Streamable transport)
22
+ const AGNIC_MCP_ENDPOINT = "https://mcp.agnicpay.xyz/sse";
23
+ /**
24
+ * Convert JSON Schema to Zod schema using n8n's library
25
+ * Returns actual Zod schema objects (not strings)
26
+ */
27
+ function convertJsonSchemaToZod(schema) {
28
+ if (!schema || typeof schema !== "object") {
29
+ return zod_1.z.object({});
30
+ }
31
+ try {
32
+ // @n8n/json-schema-to-zod returns actual Zod objects, not strings
33
+ const zodSchema = (0, json_schema_to_zod_1.jsonSchemaToZod)(schema);
34
+ // Ensure we return an object schema for structured tools
35
+ if (zodSchema instanceof zod_1.z.ZodObject) {
36
+ return zodSchema;
37
+ }
38
+ // Wrap non-object schemas in an object
39
+ return zod_1.z.object({ value: zodSchema });
40
+ }
41
+ catch {
42
+ // Fallback to empty object schema if conversion fails
43
+ return zod_1.z.object({});
44
+ }
45
+ }
46
+ /**
47
+ * Convert an MCP tool to a LangChain DynamicStructuredTool
48
+ */
49
+ function mcpToolToDynamicTool(tool, callTool) {
50
+ // Convert JSON Schema to Zod schema using proper library
51
+ const zodSchema = convertJsonSchemaToZod(tool.inputSchema);
52
+ // Use type assertion to avoid deep type instantiation issues with DynamicStructuredTool
53
+ const toolConfig = {
54
+ name: tool.name,
55
+ description: tool.description || `MCP tool: ${tool.name}`,
56
+ schema: zodSchema,
57
+ func: async (input) => {
58
+ try {
59
+ const result = await callTool(tool.name, input);
60
+ if (typeof result === "string") {
61
+ return result;
62
+ }
63
+ return JSON.stringify(result);
64
+ }
65
+ catch (error) {
66
+ const errorMessage = error instanceof Error ? error.message : String(error);
67
+ return `Error calling ${tool.name}: ${errorMessage}`;
68
+ }
69
+ },
70
+ // Required metadata for proper tool serialization in n8n
71
+ metadata: { isFromToolkit: true },
72
+ };
73
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
+ return new tools_1.DynamicStructuredTool(toolConfig);
75
+ }
76
+ /**
77
+ * AgnicMCPTool - MCP Client for AgnicPay
78
+ *
79
+ * This is a supply-only AI tool node that connects to the AgnicPay MCP server
80
+ * and provides X402 payment tools to AI Agents via the MCP protocol.
81
+ *
82
+ * This node cannot be executed directly - it only supplies tools to AI Agents.
83
+ */
84
+ class AgnicMCPTool {
85
+ constructor() {
86
+ this.description = {
87
+ displayName: "Agnic MCP Tool",
88
+ name: "agnicMcpTool",
89
+ icon: "file:AgnicMCPTool.png",
90
+ group: ["output"],
91
+ version: 1,
92
+ description: "MCP client for AgnicPay - X402 payment tools for AI Agents",
93
+ defaults: {
94
+ name: "Agnic MCP Tool",
95
+ },
96
+ // Supply-only AI tool configuration
97
+ inputs: [],
98
+ outputs: [{ type: n8n_workflow_1.NodeConnectionTypes.AiTool, displayName: "Tools" }],
99
+ codex: {
100
+ categories: ["AI"],
101
+ subcategories: {
102
+ AI: ["Tools"],
103
+ },
104
+ resources: {
105
+ primaryDocumentation: [
106
+ {
107
+ url: "https://www.agnicpay.xyz/mcp",
108
+ },
109
+ ],
110
+ },
111
+ },
112
+ credentials: [
113
+ {
114
+ name: "agnicWalletOAuth2Api",
115
+ required: false,
116
+ displayOptions: {
117
+ show: {
118
+ authentication: ["oAuth2"],
119
+ },
120
+ },
121
+ },
122
+ {
123
+ name: "agnicWalletApi",
124
+ required: false,
125
+ displayOptions: {
126
+ show: {
127
+ authentication: ["apiKey"],
128
+ },
129
+ },
130
+ },
131
+ ],
132
+ properties: [
133
+ {
134
+ displayName: "Authentication",
135
+ name: "authentication",
136
+ type: "options",
137
+ default: "apiKey",
138
+ options: [
139
+ {
140
+ name: "OAuth2",
141
+ value: "oAuth2",
142
+ description: "Recommended: Connect your account",
143
+ },
144
+ {
145
+ name: "API Key",
146
+ value: "apiKey",
147
+ description: "For CI/CD or programmatic access",
148
+ },
149
+ ],
150
+ description: "How to authenticate with AgnicWallet",
151
+ },
152
+ {
153
+ displayName: "Connects to AgnicPay MCP server. Tools are discovered automatically and include: make X402 API requests, check balance, view payment history, and discover APIs.",
154
+ name: "notice",
155
+ type: "notice",
156
+ default: "",
157
+ },
158
+ ],
159
+ };
160
+ }
161
+ /**
162
+ * Execute method for direct tool invocation.
163
+ * This is called when input data is passed directly to this node.
164
+ */
165
+ async execute() {
166
+ var _a;
167
+ const node = this.getNode();
168
+ const items = this.getInputData();
169
+ const returnData = [];
170
+ // Get authentication
171
+ const authentication = this.getNodeParameter("authentication", 0);
172
+ let accessToken;
173
+ try {
174
+ if (authentication === "oAuth2") {
175
+ const creds = (await this.getCredentials("agnicWalletOAuth2Api"));
176
+ accessToken = (_a = creds === null || creds === void 0 ? void 0 : creds.oauthTokenData) === null || _a === void 0 ? void 0 : _a.access_token;
177
+ }
178
+ else {
179
+ const creds = (await this.getCredentials("agnicWalletApi"));
180
+ accessToken = creds === null || creds === void 0 ? void 0 : creds.apiToken;
181
+ }
182
+ }
183
+ catch {
184
+ throw new n8n_workflow_1.NodeOperationError(node, "Failed to load AgnicWallet credentials.");
185
+ }
186
+ if (!accessToken) {
187
+ throw new n8n_workflow_1.NodeOperationError(node, "Missing AgnicWallet authentication token.");
188
+ }
189
+ // Connect to MCP server
190
+ const transport = new streamableHttp_js_1.StreamableHTTPClientTransport(new URL(AGNIC_MCP_ENDPOINT), {
191
+ requestInit: { headers: { Authorization: `Bearer ${accessToken}` } },
192
+ });
193
+ const client = new index_js_1.Client({ name: "agnic-mcp-client", version: "1.0.0" }, { capabilities: {} });
194
+ try {
195
+ await client.connect(transport);
196
+ const toolsResult = await client.listTools();
197
+ const mcpTools = toolsResult.tools || [];
198
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
199
+ const item = items[itemIndex];
200
+ // Expect input to have a 'tool' property with the tool name
201
+ if (!item.json.tool || typeof item.json.tool !== "string") {
202
+ throw new n8n_workflow_1.NodeOperationError(node, "Tool name not found in item.json.tool", { itemIndex });
203
+ }
204
+ const toolName = item.json.tool;
205
+ const matchingTool = mcpTools.find((t) => t.name === toolName);
206
+ if (!matchingTool) {
207
+ throw new n8n_workflow_1.NodeOperationError(node, `Tool "${toolName}" not found`, {
208
+ itemIndex,
209
+ });
210
+ }
211
+ // Extract tool arguments (everything except 'tool' property)
212
+ const { tool: _, ...toolArguments } = item.json;
213
+ const result = await client.callTool({
214
+ name: toolName,
215
+ arguments: toolArguments,
216
+ });
217
+ // Extract text content from result
218
+ let responseContent = result;
219
+ if (result.content && Array.isArray(result.content)) {
220
+ const textContent = result.content.find((c) => c.type === "text");
221
+ if (textContent && "text" in textContent) {
222
+ responseContent = textContent.text;
223
+ }
224
+ }
225
+ returnData.push({
226
+ json: { response: responseContent },
227
+ pairedItem: { item: itemIndex },
228
+ });
229
+ }
230
+ }
231
+ finally {
232
+ try {
233
+ await client.close();
234
+ }
235
+ catch {
236
+ // Ignore cleanup errors
237
+ }
238
+ try {
239
+ await transport.close();
240
+ }
241
+ catch {
242
+ // Ignore cleanup errors
243
+ }
244
+ }
245
+ return [returnData];
246
+ }
247
+ /**
248
+ * Supply MCP tools to AI Agent.
249
+ * This is the main method that provides tools to the AI Agent.
250
+ */
251
+ async supplyData(itemIndex) {
252
+ var _a;
253
+ // ─────────────────────────────────────────────
254
+ // Authentication
255
+ // ─────────────────────────────────────────────
256
+ const authentication = this.getNodeParameter("authentication", itemIndex);
257
+ let accessToken;
258
+ try {
259
+ if (authentication === "oAuth2") {
260
+ const creds = (await this.getCredentials("agnicWalletOAuth2Api", itemIndex));
261
+ accessToken = (_a = creds === null || creds === void 0 ? void 0 : creds.oauthTokenData) === null || _a === void 0 ? void 0 : _a.access_token;
262
+ }
263
+ else {
264
+ const creds = (await this.getCredentials("agnicWalletApi", itemIndex));
265
+ accessToken = creds === null || creds === void 0 ? void 0 : creds.apiToken;
266
+ }
267
+ }
268
+ catch (err) {
269
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), "Failed to load AgnicWallet credentials. Please configure your credentials.", { itemIndex });
270
+ }
271
+ if (!accessToken) {
272
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), "Missing AgnicWallet authentication token. Please check your credentials configuration.", { itemIndex });
273
+ }
274
+ // ─────────────────────────────────────────────
275
+ // MCP Client Setup
276
+ // ─────────────────────────────────────────────
277
+ let client;
278
+ let transport;
279
+ try {
280
+ // Create HTTP Streamable transport with authentication
281
+ // This transport uses POST requests and accepts both JSON and SSE responses
282
+ transport = new streamableHttp_js_1.StreamableHTTPClientTransport(new URL(AGNIC_MCP_ENDPOINT), {
283
+ requestInit: {
284
+ headers: {
285
+ Authorization: `Bearer ${accessToken}`,
286
+ },
287
+ },
288
+ });
289
+ // Create MCP client
290
+ client = new index_js_1.Client({ name: "agnic-mcp-client", version: "1.0.0" }, { capabilities: {} });
291
+ // Connect to MCP server
292
+ await client.connect(transport);
293
+ // ─────────────────────────────────────────────
294
+ // Discover and wrap MCP tools
295
+ // ─────────────────────────────────────────────
296
+ const toolsResult = await client.listTools();
297
+ const mcpTools = toolsResult.tools || [];
298
+ if (mcpTools.length === 0) {
299
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), "No tools available from AgnicPay MCP server. Please check your authentication and try again.", { itemIndex });
300
+ }
301
+ // Create a tool caller function
302
+ const callTool = async (name, args) => {
303
+ if (!client) {
304
+ throw new Error("MCP client is not connected");
305
+ }
306
+ const result = await client.callTool({
307
+ name,
308
+ arguments: args,
309
+ });
310
+ // Extract content from the result
311
+ if (result.content && Array.isArray(result.content)) {
312
+ const textContent = result.content.find((c) => c.type === "text");
313
+ if (textContent && "text" in textContent) {
314
+ return textContent.text;
315
+ }
316
+ }
317
+ return result;
318
+ };
319
+ // Convert MCP tools to LangChain DynamicStructuredTools
320
+ const langchainTools = mcpTools.map((tool) => mcpToolToDynamicTool(tool, callTool));
321
+ // Wrap tools in a Toolkit for n8n AI Agent compatibility
322
+ const toolkit = new AgnicMcpToolkit(langchainTools);
323
+ // Store references for cleanup
324
+ const clientRef = client;
325
+ const transportRef = transport;
326
+ // Return toolkit with cleanup function
327
+ return {
328
+ response: toolkit,
329
+ closeFunction: async () => {
330
+ try {
331
+ await clientRef.close();
332
+ }
333
+ catch {
334
+ // Ignore cleanup errors
335
+ }
336
+ try {
337
+ await transportRef.close();
338
+ }
339
+ catch {
340
+ // Ignore cleanup errors
341
+ }
342
+ },
343
+ };
344
+ }
345
+ catch (error) {
346
+ // Clean up on error
347
+ if (client) {
348
+ try {
349
+ await client.close();
350
+ }
351
+ catch {
352
+ // Ignore cleanup errors
353
+ }
354
+ }
355
+ if (transport) {
356
+ try {
357
+ await transport.close();
358
+ }
359
+ catch {
360
+ // Ignore cleanup errors
361
+ }
362
+ }
363
+ const errorMessage = error instanceof Error ? error.message : String(error);
364
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to connect to AgnicPay MCP server: ${errorMessage}`, { itemIndex });
365
+ }
366
+ }
367
+ }
368
+ exports.AgnicMCPTool = AgnicMCPTool;
@@ -1,4 +1,4 @@
1
- import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
2
2
  export declare class X402HttpRequest implements INodeType {
3
3
  description: INodeTypeDescription;
4
4
  execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;