n8n-nodes-confirm8 0.17.0 → 0.18.0

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.
@@ -1,5 +1,10 @@
1
- import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription, IDataObject } from 'n8n-workflow';
2
2
  export declare class Confirm8AgentTool implements INodeType {
3
3
  description: INodeTypeDescription;
4
+ /**
5
+ * MCP-style tool description with explicit schema
6
+ */
7
+ supportsMultipleCalls(): Promise<boolean>;
8
+ getToolDescription(this: IExecuteFunctions): Promise<IDataObject>;
4
9
  execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
10
  }
@@ -10,7 +10,7 @@ class Confirm8AgentTool {
10
10
  icon: 'file:tool.svg',
11
11
  group: ['transform'],
12
12
  version: 1,
13
- description: 'Autonomous AI Agent tool for Confirm8 API',
13
+ description: 'MCP-style AI Agent tool for Confirm8 API with schema discovery',
14
14
  defaults: {
15
15
  name: 'Confirm8 AI Tool',
16
16
  },
@@ -51,51 +51,313 @@ class Confirm8AgentTool {
51
51
  default: '',
52
52
  required: true,
53
53
  },
54
- // Tool parameters (provided by AI)
54
+ // Tool parameters (AI provides)
55
55
  {
56
56
  displayName: 'Resource',
57
57
  name: 'resource',
58
58
  type: 'string',
59
59
  default: '',
60
- description: 'Resource type',
61
60
  },
62
61
  {
63
62
  displayName: 'Operation',
64
63
  name: 'operation',
65
64
  type: 'string',
66
65
  default: '',
67
- description: 'Operation to perform',
68
66
  },
69
67
  {
70
68
  displayName: 'Record ID',
71
69
  name: 'recordId',
72
70
  type: 'string',
73
71
  default: '',
74
- description: 'Record ID',
75
72
  },
76
73
  {
77
74
  displayName: 'Data',
78
75
  name: 'data',
79
76
  type: 'string',
80
77
  default: '',
81
- description: 'JSON data',
82
78
  },
83
79
  ],
84
80
  };
85
81
  }
82
+ /**
83
+ * MCP-style tool description with explicit schema
84
+ */
85
+ async supportsMultipleCalls() {
86
+ return true;
87
+ }
88
+ // This is what the AI sees - make it VERY explicit
89
+ async getToolDescription() {
90
+ return {
91
+ name: 'confirm8_api',
92
+ description: 'Access Confirm8 business management system. Use EXACT values from schema below.',
93
+ // Define schema with ENUMS
94
+ schema: {
95
+ type: 'object',
96
+ properties: {
97
+ resource: {
98
+ type: 'string',
99
+ description: 'Resource to access. MUST be one of the exact values below.',
100
+ enum: [
101
+ 'user',
102
+ 'client',
103
+ 'item',
104
+ 'itemType',
105
+ 'task',
106
+ 'service',
107
+ 'product',
108
+ 'order',
109
+ 'modality',
110
+ 'ticket',
111
+ 'property'
112
+ ],
113
+ examples: ['user', 'client', 'task']
114
+ },
115
+ operation: {
116
+ type: 'string',
117
+ description: 'Operation to perform. MUST be one of the exact values below.',
118
+ enum: [
119
+ 'getAll',
120
+ 'get',
121
+ 'create',
122
+ 'update',
123
+ 'activate',
124
+ 'deactivate',
125
+ 'getByUsername',
126
+ 'getTickets',
127
+ 'getTasks',
128
+ 'getPermissions',
129
+ 'linkTasks',
130
+ 'deleteLinkedTasks',
131
+ 'deleteLinkedTasksByUser',
132
+ 'uploadPhoto',
133
+ 'uploadSignature'
134
+ ],
135
+ examples: ['getAll', 'get', 'create', 'update']
136
+ },
137
+ recordId: {
138
+ type: 'string',
139
+ description: 'ID of record (required for: get, update, activate, deactivate, getTickets, getTasks, getPermissions, uploadPhoto, uploadSignature)',
140
+ examples: ['123', '456', 'abc-def-ghi']
141
+ },
142
+ data: {
143
+ type: 'string',
144
+ description: 'JSON string with data (required for: create, update, linkTasks, uploadPhoto, uploadSignature)',
145
+ examples: [
146
+ '{"name":"John Doe","email":"john@example.com"}',
147
+ '{"status":"completed"}',
148
+ '{"userId":"123","taskIds":["1","2","3"]}'
149
+ ]
150
+ }
151
+ },
152
+ required: ['resource', 'operation']
153
+ },
154
+ // Detailed mapping
155
+ resources: {
156
+ user: {
157
+ description: 'Users and employees',
158
+ operations: {
159
+ getAll: { description: 'List all users', requires: [] },
160
+ get: { description: 'Get user by ID', requires: ['recordId'] },
161
+ create: { description: 'Create new user', requires: ['data'] },
162
+ update: { description: 'Update user', requires: ['recordId', 'data'] },
163
+ activate: { description: 'Activate user', requires: ['recordId'] },
164
+ deactivate: { description: 'Deactivate user', requires: ['recordId'] },
165
+ getByUsername: { description: 'Get user by username', requires: ['data.username'] },
166
+ getTickets: { description: 'Get user tickets', requires: ['recordId'] },
167
+ getTasks: { description: 'Get user tasks', requires: ['recordId'] },
168
+ getPermissions: { description: 'Get user permissions', requires: ['recordId'] },
169
+ linkTasks: { description: 'Link tasks to user', requires: ['data'] },
170
+ uploadPhoto: { description: 'Upload user photo', requires: ['recordId', 'data'] },
171
+ uploadSignature: { description: 'Upload signature', requires: ['recordId', 'data'] }
172
+ }
173
+ },
174
+ client: {
175
+ description: 'Clients and customers',
176
+ operations: {
177
+ getAll: { description: 'List all clients', requires: [] },
178
+ get: { description: 'Get client by ID', requires: ['recordId'] },
179
+ create: { description: 'Create new client', requires: ['data'] },
180
+ update: { description: 'Update client', requires: ['recordId', 'data'] },
181
+ activate: { description: 'Activate client', requires: ['recordId'] },
182
+ deactivate: { description: 'Deactivate client', requires: ['recordId'] }
183
+ }
184
+ },
185
+ item: {
186
+ description: 'Items and inventory',
187
+ operations: {
188
+ getAll: { description: 'List all items', requires: [] },
189
+ get: { description: 'Get item by ID', requires: ['recordId'] },
190
+ create: { description: 'Create new item', requires: ['data'] },
191
+ update: { description: 'Update item', requires: ['recordId', 'data'] },
192
+ activate: { description: 'Activate item', requires: ['recordId'] },
193
+ deactivate: { description: 'Deactivate item', requires: ['recordId'] }
194
+ }
195
+ },
196
+ itemType: {
197
+ description: 'Item type categories',
198
+ operations: {
199
+ getAll: { description: 'List all item types', requires: [] },
200
+ get: { description: 'Get item type by ID', requires: ['recordId'] },
201
+ create: { description: 'Create new item type', requires: ['data'] },
202
+ update: { description: 'Update item type', requires: ['recordId', 'data'] },
203
+ activate: { description: 'Activate item type', requires: ['recordId'] },
204
+ deactivate: { description: 'Deactivate item type', requires: ['recordId'] }
205
+ }
206
+ },
207
+ task: {
208
+ description: 'Tasks and checklists',
209
+ operations: {
210
+ getAll: { description: 'List all tasks', requires: [] },
211
+ get: { description: 'Get task by ID', requires: ['recordId'] },
212
+ create: { description: 'Create new task', requires: ['data'] },
213
+ update: { description: 'Update task', requires: ['recordId', 'data'] },
214
+ activate: { description: 'Activate task', requires: ['recordId'] },
215
+ deactivate: { description: 'Deactivate task', requires: ['recordId'] }
216
+ }
217
+ },
218
+ service: {
219
+ description: 'Services',
220
+ operations: {
221
+ getAll: { description: 'List all services', requires: [] },
222
+ get: { description: 'Get service by ID', requires: ['recordId'] },
223
+ create: { description: 'Create new service', requires: ['data'] },
224
+ update: { description: 'Update service', requires: ['recordId', 'data'] },
225
+ activate: { description: 'Activate service', requires: ['recordId'] },
226
+ deactivate: { description: 'Deactivate service', requires: ['recordId'] }
227
+ }
228
+ },
229
+ product: {
230
+ description: 'Products',
231
+ operations: {
232
+ getAll: { description: 'List all products', requires: [] },
233
+ get: { description: 'Get product by ID', requires: ['recordId'] },
234
+ create: { description: 'Create new product', requires: ['data'] },
235
+ update: { description: 'Update product', requires: ['recordId', 'data'] },
236
+ activate: { description: 'Activate product', requires: ['recordId'] },
237
+ deactivate: { description: 'Deactivate product', requires: ['recordId'] }
238
+ }
239
+ },
240
+ order: {
241
+ description: 'Work orders (WOS)',
242
+ operations: {
243
+ getAll: { description: 'List all orders', requires: [] },
244
+ get: { description: 'Get order by ID', requires: ['recordId'] },
245
+ create: { description: 'Create new order', requires: ['data'] },
246
+ update: { description: 'Update order', requires: ['recordId', 'data'] },
247
+ activate: { description: 'Activate order', requires: ['recordId'] },
248
+ deactivate: { description: 'Deactivate order', requires: ['recordId'] }
249
+ }
250
+ },
251
+ modality: {
252
+ description: 'Order modalities',
253
+ operations: {
254
+ getAll: { description: 'List all modalities', requires: [] },
255
+ get: { description: 'Get modality by ID', requires: ['recordId'] },
256
+ create: { description: 'Create new modality', requires: ['data'] },
257
+ update: { description: 'Update modality', requires: ['recordId', 'data'] },
258
+ activate: { description: 'Activate modality', requires: ['recordId'] },
259
+ deactivate: { description: 'Deactivate modality', requires: ['recordId'] }
260
+ }
261
+ },
262
+ ticket: {
263
+ description: 'Tickets and occurrences',
264
+ operations: {
265
+ getAll: { description: 'List all tickets', requires: [] },
266
+ get: { description: 'Get ticket by ID', requires: ['recordId'] },
267
+ create: { description: 'Create new ticket', requires: ['data'] },
268
+ update: { description: 'Update ticket', requires: ['recordId', 'data'] },
269
+ activate: { description: 'Activate ticket', requires: ['recordId'] },
270
+ deactivate: { description: 'Deactivate ticket', requires: ['recordId'] }
271
+ }
272
+ },
273
+ property: {
274
+ description: 'Properties',
275
+ operations: {
276
+ getAll: { description: 'List all properties', requires: [] },
277
+ get: { description: 'Get property by ID', requires: ['recordId'] },
278
+ create: { description: 'Create new property', requires: ['data'] },
279
+ update: { description: 'Update property', requires: ['recordId', 'data'] },
280
+ activate: { description: 'Activate property', requires: ['recordId'] },
281
+ deactivate: { description: 'Deactivate property', requires: ['recordId'] }
282
+ }
283
+ }
284
+ },
285
+ // Common operation patterns
286
+ operationPatterns: {
287
+ 'list all X / show all X / get all X': 'operation=getAll',
288
+ 'show X / get X [id]': 'operation=get, recordId=[id]',
289
+ 'create X / add X / new X': 'operation=create, data={...}',
290
+ 'update X / modify X / change X': 'operation=update, recordId=[id], data={...}',
291
+ 'activate X / enable X': 'operation=activate, recordId=[id]',
292
+ 'deactivate X / disable X': 'operation=deactivate, recordId=[id]'
293
+ },
294
+ // Explicit examples
295
+ examples: [
296
+ {
297
+ input: 'list all users',
298
+ params: { resource: 'user', operation: 'getAll' }
299
+ },
300
+ {
301
+ input: 'show user 123',
302
+ params: { resource: 'user', operation: 'get', recordId: '123' }
303
+ },
304
+ {
305
+ input: 'create client ABC Corp',
306
+ params: {
307
+ resource: 'client',
308
+ operation: 'create',
309
+ data: '{"name":"ABC Corp"}'
310
+ }
311
+ },
312
+ {
313
+ input: 'update task 456 to completed',
314
+ params: {
315
+ resource: 'task',
316
+ operation: 'update',
317
+ recordId: '456',
318
+ data: '{"status":"completed"}'
319
+ }
320
+ },
321
+ {
322
+ input: 'list todos usuarios',
323
+ params: { resource: 'user', operation: 'getAll' }
324
+ },
325
+ {
326
+ input: 'mostrar clientes',
327
+ params: { resource: 'client', operation: 'getAll' }
328
+ }
329
+ ],
330
+ // CRITICAL: Exact value mapping
331
+ valueMapping: {
332
+ 'users/usuarios/usuários/employees/funcionários': 'user',
333
+ 'clients/clientes/customers': 'client',
334
+ 'items/itens': 'item',
335
+ 'tasks/tarefas': 'task',
336
+ 'services/serviços/servicos': 'service',
337
+ 'products/produtos': 'product',
338
+ 'orders/ordens/pedidos': 'order',
339
+ 'tickets/chamados': 'ticket',
340
+ 'properties/propriedades': 'property',
341
+ 'list/listar/mostrar/show/get all/buscar todos': 'getAll',
342
+ 'get/buscar/obter/show one': 'get',
343
+ 'create/criar/adicionar/add/new/novo': 'create',
344
+ 'update/atualizar/modificar/modify/change': 'update',
345
+ 'activate/ativar/enable/habilitar': 'activate',
346
+ 'deactivate/desativar/disable/desabilitar': 'deactivate'
347
+ }
348
+ };
349
+ }
86
350
  async execute() {
87
351
  const items = this.getInputData();
88
352
  const returnData = [];
89
353
  for (let i = 0; i < items.length; i++) {
90
354
  try {
91
- // Get API credentials
92
355
  const baseUrl = this.getNodeParameter('baseUrl', i);
93
356
  const bearerToken = this.getNodeParameter('bearerToken', i);
94
357
  const apiDomain = this.getNodeParameter('apiDomain', i);
95
358
  const apiKeyToken = this.getNodeParameter('apiKeyToken', i);
96
- // Get operation parameters (from AI or manual)
97
- const resource = this.getNodeParameter('resource', i, '');
98
- const operation = this.getNodeParameter('operation', i, '');
359
+ let resource = this.getNodeParameter('resource', i, '');
360
+ let operation = this.getNodeParameter('operation', i, '');
99
361
  const recordId = this.getNodeParameter('recordId', i, '');
100
362
  // Parse data
101
363
  let data = {};
@@ -105,14 +367,38 @@ class Confirm8AgentTool {
105
367
  data = JSON.parse(dataParam);
106
368
  }
107
369
  catch (e) {
108
- // If not JSON, treat as empty
370
+ // Ignore
109
371
  }
110
372
  }
373
+ // Normalize resource and operation (handle common variations)
374
+ const resourceMap = {
375
+ 'users': 'user', 'usuarios': 'user', 'usuários': 'user', 'employees': 'user',
376
+ 'clients': 'client', 'clientes': 'client', 'customers': 'client',
377
+ 'items': 'item', 'itens': 'item',
378
+ 'tasks': 'task', 'tarefas': 'task',
379
+ 'services': 'service', 'serviços': 'service', 'servicos': 'service',
380
+ 'products': 'product', 'produtos': 'product',
381
+ 'orders': 'order', 'ordens': 'order', 'pedidos': 'order',
382
+ 'tickets': 'ticket', 'chamados': 'ticket',
383
+ 'properties': 'property', 'propriedades': 'property',
384
+ 'modalities': 'modality', 'modalidades': 'modality'
385
+ };
386
+ const operationMap = {
387
+ 'list': 'getAll', 'listar': 'getAll', 'mostrar': 'getAll', 'show': 'getAll',
388
+ 'buscar': 'get', 'obter': 'get',
389
+ 'criar': 'create', 'adicionar': 'create', 'add': 'create', 'novo': 'create', 'new': 'create',
390
+ 'atualizar': 'update', 'modificar': 'update', 'modify': 'update',
391
+ 'ativar': 'activate', 'enable': 'activate', 'habilitar': 'activate',
392
+ 'desativar': 'deactivate', 'disable': 'deactivate', 'desabilitar': 'deactivate'
393
+ };
394
+ // Normalize
395
+ resource = resourceMap[resource.toLowerCase()] || resource;
396
+ operation = operationMap[operation.toLowerCase()] || operation;
111
397
  if (!resource || !operation) {
112
398
  throw new Error('Resource and operation are required');
113
399
  }
114
- // Map resources to endpoints
115
- const resourceMap = {
400
+ // Map to API endpoints
401
+ const endpointMap = {
116
402
  user: 'users',
117
403
  client: 'clients',
118
404
  item: 'items',
@@ -125,7 +411,7 @@ class Confirm8AgentTool {
125
411
  ticket: 'tickets',
126
412
  property: 'properties',
127
413
  };
128
- const baseEndpoint = resourceMap[resource] || resource;
414
+ const baseEndpoint = endpointMap[resource] || resource;
129
415
  let endpoint = '';
130
416
  let method = 'GET';
131
417
  let body = {};
@@ -136,7 +422,7 @@ class Confirm8AgentTool {
136
422
  break;
137
423
  case 'get':
138
424
  if (!recordId)
139
- throw new Error('recordId required for get');
425
+ throw new Error('recordId required');
140
426
  endpoint = `/${baseEndpoint}/${recordId}`;
141
427
  break;
142
428
  case 'create':
@@ -146,26 +432,25 @@ class Confirm8AgentTool {
146
432
  break;
147
433
  case 'update':
148
434
  if (!recordId)
149
- throw new Error('recordId required for update');
435
+ throw new Error('recordId required');
150
436
  endpoint = `/${baseEndpoint}/${recordId}`;
151
437
  method = 'PUT';
152
438
  body = data;
153
439
  break;
154
440
  case 'activate':
155
441
  if (!recordId)
156
- throw new Error('recordId required for activate');
442
+ throw new Error('recordId required');
157
443
  endpoint = `/${baseEndpoint}/${recordId}/active`;
158
444
  method = ['client', 'item', 'itemType', 'task', 'service', 'product', 'order', 'modality'].includes(resource)
159
445
  ? 'PUT' : 'PATCH';
160
446
  break;
161
447
  case 'deactivate':
162
448
  if (!recordId)
163
- throw new Error('recordId required for deactivate');
449
+ throw new Error('recordId required');
164
450
  endpoint = `/${baseEndpoint}/${recordId}/inactive`;
165
451
  method = ['client', 'item', 'itemType', 'task', 'service', 'product', 'order', 'modality'].includes(resource)
166
452
  ? 'PUT' : 'PATCH';
167
453
  break;
168
- // Special user operations
169
454
  case 'getByUsername':
170
455
  if (!data.username)
171
456
  throw new Error('username required in data');
@@ -197,7 +482,7 @@ class Confirm8AgentTool {
197
482
  break;
198
483
  case 'deleteLinkedTasksByUser':
199
484
  if (!data.employeeId)
200
- throw new Error('employeeId required in data');
485
+ throw new Error('employeeId required');
201
486
  endpoint = `/users/tasks/${data.employeeId}`;
202
487
  method = 'DELETE';
203
488
  break;
@@ -252,8 +537,6 @@ class Confirm8AgentTool {
252
537
  json: {
253
538
  success: false,
254
539
  error: error.message || 'Unknown error',
255
- resource: this.getNodeParameter('resource', i, ''),
256
- operation: this.getNodeParameter('operation', i, ''),
257
540
  },
258
541
  pairedItem: { item: i },
259
542
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-confirm8",
3
- "version": "0.17.0",
3
+ "version": "0.18.0",
4
4
  "description": "Simple n8n node for Confirm8 API - no credentials needed",
5
5
  "license": "MIT",
6
6
  "author": "Bill Hebert",