@quantyapp/quanty-mcp-server 1.0.2 → 1.0.5

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.
@@ -42,4 +42,8 @@ export declare function prepareImportItem(budgetId: string, bankItem: BankItem):
42
42
  preview: string;
43
43
  data: any;
44
44
  };
45
+ /**
46
+ * Gets a specific item from a bank by ID
47
+ */
48
+ export declare function getBankItemById(bankId: string, itemId: string): Promise<BankItem | null>;
45
49
  //# sourceMappingURL=bankService.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bankService.d.ts","sourceRoot":"","sources":["../../src/core/bankService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,QAAQ,GAAG,SAAS,GAAG,cAAc,CAAC;IAClD,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAmBzE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAgB/E;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CA0C5G;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,GACnB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,CAchD"}
1
+ {"version":3,"file":"bankService.d.ts","sourceRoot":"","sources":["../../src/core/bankService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,QAAQ,GAAG,SAAS,GAAG,cAAc,CAAC;IAClD,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAmBzE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAgB/E;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CA0C5G;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC7B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,GACnB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,GAAG,CAAA;CAAE,CAchD;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAsC9F"}
@@ -103,3 +103,45 @@ export function prepareImportItem(budgetId, bankItem) {
103
103
  }
104
104
  };
105
105
  }
106
+ /**
107
+ * Gets a specific item from a bank by ID
108
+ */
109
+ export async function getBankItemById(bankId, itemId) {
110
+ const { data, error } = await supabase
111
+ .from('composition_banks')
112
+ .select('categories')
113
+ .eq('id', bankId)
114
+ .single();
115
+ if (error)
116
+ return null;
117
+ let foundItem = null;
118
+ function search(items) {
119
+ for (const item of items) {
120
+ if (item.id === itemId) {
121
+ foundItem = {
122
+ id: item.id,
123
+ code: item.code,
124
+ description: item.description,
125
+ unit: item.unit,
126
+ unitCost: item.unitCost || 0,
127
+ itemType: item.itemType
128
+ };
129
+ return;
130
+ }
131
+ if (item.children)
132
+ search(item.children);
133
+ }
134
+ }
135
+ function searchCats(categories) {
136
+ for (const cat of categories) {
137
+ if (foundItem)
138
+ return;
139
+ if (cat.items)
140
+ search(cat.items);
141
+ if (cat.children)
142
+ searchCats(cat.children);
143
+ }
144
+ }
145
+ searchCats(data?.categories || []);
146
+ return foundItem;
147
+ }
package/dist/mcp/index.js CHANGED
@@ -124,7 +124,8 @@ Use quanty_ver_composicao para ver os insumos de uma composição específica.`,
124
124
  {
125
125
  name: 'quanty_ver_composicao',
126
126
  description: `Mostra os INSUMOS que compõem um item do tipo COMPOSIÇÃO.
127
- Uso obrigatório quando um item tiver 'is_composicao: true' para entender seus custos internos.`,
127
+ Uso obrigatório quando um item tiver 'is_composicao: true' para entender seus custos internos.
128
+ Se um insumo retornado também for uma composição, você pode chamar esta função novamente com o ID dele (recursividade).`,
128
129
  inputSchema: {
129
130
  type: 'object',
130
131
  properties: {
@@ -153,7 +154,22 @@ Para importar uma composição para um orçamento, o sistema traz toda a estrutu
153
154
  banco_id: { type: 'string', description: 'ID do banco (obtido via quanty_listar_bancos)' },
154
155
  busca: { type: 'string', description: 'Texto para buscar (ex: "concreto fck 30", "forma metálica")' }
155
156
  },
156
- required: ['banco_id', 'busca']
157
+ }
158
+ },
159
+ {
160
+ name: 'quanty_importar_item',
161
+ description: `Importa um item (insumo ou composição) de um banco de referência para o orçamento.
162
+ Use esta função quando encontrar um item via quanty_buscar_insumo e quiser adicioná-lo ao orçamento.
163
+ A importação traz automaticamente a unidade e custo do banco.`,
164
+ inputSchema: {
165
+ type: 'object',
166
+ properties: {
167
+ orcamento_id: { type: 'string', description: 'ID do orçamento destino' },
168
+ banco_item_id: { type: 'string', description: 'ID do item no banco (retornado por quanty_buscar_insumo)' },
169
+ banco_id: { type: 'string', description: 'ID do banco de origem' },
170
+ quantidade: { type: 'number', description: 'Quantidade a ser orçada' }
171
+ },
172
+ required: ['orcamento_id', 'banco_item_id', 'banco_id', 'quantidade']
157
173
  }
158
174
  },
159
175
  // === WRITE TOOLS (with confirmation) ===
@@ -308,11 +324,14 @@ async function handleToolCall(auth, name, args) {
308
324
  qtd_insumos: insumos.length,
309
325
  custo_total_calculado: `R$ ${totalComposicao.toFixed(2)}`,
310
326
  insumos: insumos.map(i => ({
327
+ id: i.id, // ID necessário para recursão
311
328
  descricao: i.description,
312
329
  unidade: i.unit,
313
- coeficiente: i.quantity, // Na composição, quantidade é o coeficiente
330
+ coeficiente: i.quantity,
314
331
  custo_unitario_insumo: i.unitCost,
315
- custo_total_insumo: i.total
332
+ custo_total_insumo: i.total,
333
+ is_composicao: i.is_composicao, // Indica se pode descer mais um nível
334
+ tipo: i.type
316
335
  }))
317
336
  };
318
337
  }
@@ -348,6 +367,38 @@ async function handleToolCall(auth, name, args) {
348
367
  };
349
368
  }
350
369
  // === WRITE (with confirmation) ===
370
+ case 'quanty_importar_item': {
371
+ // Primeiro buscamos os detalhes do item no banco para preparar a importação
372
+ // Como prepareImportItem precisa do objeto BankItem completo, vamos simular ou buscar
373
+ // Para simplificar, vamos usar uma busca direta pelo ID no banco via searchBankItems (ajustando a query seria ideal, mas aqui vamos assumir que o ID é suficiente ou implementaremos um getBankItem)
374
+ // Melhor abordagem: vamos buscar o item específico.
375
+ // O bankService não tem getBankItem exposto, então vamos adicionar uma busca rápida ou usar search
376
+ const items = await bankService.searchBankItems(args.banco_id, ''); // Busca ampla é ruim.
377
+ // Vamos adicionar uma função getBankItem no bankService ou buscar na lista filtrada.
378
+ // WORKAROUND: Vamos criar a pendência com os dados mínimos e deixar o execute resolver ou
379
+ // implementar getBankItem no bankService agora.
380
+ // Vamos assumir que o usuário passou dados válidos e deixar a validação para o execute se possível.
381
+ // Mas prepareImportItem pede um BankItem.
382
+ // Vamos adicionar getBankItemById no bankService agora.
383
+ const item = await bankService.getBankItemById(args.banco_id, args.banco_item_id);
384
+ if (!item)
385
+ return { erro: 'Item não encontrado no banco de dados.' };
386
+ const prepared = bankService.prepareImportItem(args.orcamento_id, item);
387
+ // Injetamos a quantidade que o usuário pediu, pois o prepareImportItem define como 0
388
+ prepared.data.item.quantity = args.quantidade;
389
+ prepared.preview = prepared.preview.replace('quantidade: 0', `quantidade: ${args.quantidade}`); // Ajuste cosmético se houver
390
+ const pendingId = generatePendingId();
391
+ pendingOperations.set(pendingId, {
392
+ action: prepared.action,
393
+ data: prepared.data,
394
+ expiresAt: Date.now() + 5 * 60 * 1000
395
+ });
396
+ return {
397
+ pending_id: pendingId,
398
+ preview: `Importar "${item.description}" (${args.quantidade} ${item.unit}) - Pressione executar para confirmar.`,
399
+ mensagem: 'Use quanty_executar com este pending_id para confirmar a importação.'
400
+ };
401
+ }
351
402
  case 'quanty_preparar_orcamento': {
352
403
  const prepared = budgetService.prepareCreateBudget(auth, args.titulo);
353
404
  const pendingId = generatePendingId();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantyapp/quanty-mcp-server",
3
- "version": "1.0.2",
3
+ "version": "1.0.5",
4
4
  "description": "MCP Server para conectar Claude Desktop ao Quanty - Sistema de Orçamentos de Engenharia",
5
5
  "type": "module",
6
6
  "main": "dist/mcp/index.js",