@comando.one/mcp-server 0.2.0 → 0.3.1

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.
package/README.md CHANGED
@@ -51,7 +51,7 @@ Ambos expõem o **mesmo conjunto de ferramentas** (50 curadas + `lookups` + `com
51
51
 
52
52
  ## Como funciona
53
53
 
54
- - **~70 tools curadas** (gerados a partir do OpenAPI canônico, zero drift) cobrindo as operações de maior valor — `customers_list`, `invoices_create`/`invoices_delete`, `charges_create`, `nfse_emit`, `payouts_create`, `contracts_pause`/`contracts_resume`, `service_categories_create`, `reports_aging_actions`/`reports_cashflow_forecast`, `audit_timeline`, `cost_centers_create`, etc.
54
+ - **126 tools curadas** (gerados a partir do OpenAPI canônico, zero drift) cobrindo as operações de maior valor — `customers_list`, `invoices_create`/`invoices_delete`, `charges_create`, `nfse_emit`, `payouts_create`, `contracts_pause`/`contracts_resume`, `service_categories_create`, `reports_aging_actions`/`reports_cashflow_forecast`, `audit_timeline`, `cost_centers_create`, etc.
55
55
  - **`comando_request`** — escape hatch genérico (`method`, `path`, `query`, `body`) que cobre 100% dos endpoints restantes.
56
56
  - **`lookups`** — catálogos read-only (centros de custo, condições/métodos de pagamento, naturezas, contas bancárias).
57
57
  - **`whoami`** — identidade, empresas acessíveis e scopes da chave.
package/dist/index.js CHANGED
@@ -223,7 +223,65 @@ var MANIFEST = [
223
223
  { operationId: "listReminders", tool: "reminders_list" },
224
224
  { operationId: "createReminder", tool: "reminders_create", write: true },
225
225
  { operationId: "updateReminder", tool: "reminders_update", write: true },
226
- { operationId: "deleteReminder", tool: "reminders_delete", write: true, destructive: true }
226
+ { operationId: "deleteReminder", tool: "reminders_delete", write: true, destructive: true },
227
+ // ── Cobertura completa da API (2026-08-14) ──────────────────────────────
228
+ // 43 operações que já existiam na API pública e não tinham tool: um agente
229
+ // conseguia criar cliente mas não editar endereço, listar fatura mas não
230
+ // apagar despesa. Deriva do MANIFEST curado, não decisão de projeto.
231
+ // Flags seguem a convenção: mutação = write; remoção = write + destructive.
232
+ // Identidade e empresa
233
+ { operationId: "getMe", tool: "me_get" },
234
+ { operationId: "getCompany", tool: "companies_get" },
235
+ // Clientes — sub-recursos e edição
236
+ { operationId: "listCustomerAddresses", tool: "customers_list_addresses" },
237
+ { operationId: "updateCustomerAddress", tool: "customers_update_address", write: true },
238
+ { operationId: "deleteCustomerAddress", tool: "customers_delete_address", write: true, destructive: true },
239
+ { operationId: "listCustomerContacts", tool: "customers_list_contacts" },
240
+ { operationId: "updateCustomerContact", tool: "customers_update_contact", write: true },
241
+ { operationId: "deleteCustomerContact", tool: "customers_delete_contact", write: true, destructive: true },
242
+ { operationId: "listCustomerContracts", tool: "customers_list_contracts" },
243
+ { operationId: "listCustomerProposals", tool: "customers_list_proposals" },
244
+ // Propostas e contratos — edição e exclusão
245
+ { operationId: "updateProposal", tool: "proposals_update", write: true },
246
+ { operationId: "deleteProposal", tool: "proposals_delete", write: true, destructive: true },
247
+ { operationId: "updateContract", tool: "contracts_update", write: true },
248
+ { operationId: "deleteContract", tool: "contracts_delete", write: true, destructive: true },
249
+ // Fornecedores — edição e formas de pagamento
250
+ { operationId: "updateSupplier", tool: "suppliers_update", write: true },
251
+ { operationId: "deleteSupplier", tool: "suppliers_delete", write: true, destructive: true },
252
+ { operationId: "listSupplierPaymentMethods", tool: "suppliers_list_payment_methods" },
253
+ { operationId: "createSupplierPaymentMethod", tool: "suppliers_add_payment_method", write: true },
254
+ { operationId: "updateSupplierPaymentMethod", tool: "suppliers_update_payment_method", write: true },
255
+ { operationId: "deleteSupplierPaymentMethod", tool: "suppliers_delete_payment_method", write: true, destructive: true },
256
+ // Serviços
257
+ { operationId: "getService", tool: "services_get" },
258
+ { operationId: "updateService", tool: "services_update", write: true },
259
+ { operationId: "deleteService", tool: "services_delete", write: true, destructive: true },
260
+ { operationId: "listServiceUnits", tool: "service_units_list" },
261
+ // Despesas
262
+ { operationId: "getExpense", tool: "expenses_get" },
263
+ { operationId: "updateExpense", tool: "expenses_update", write: true },
264
+ { operationId: "deleteExpense", tool: "expenses_delete", write: true, destructive: true },
265
+ // Financeiro e contas bancárias
266
+ { operationId: "listFinancialNatures", tool: "finance_list_natures" },
267
+ { operationId: "deleteFinancialMovement", tool: "finance_delete_movement", write: true, destructive: true },
268
+ { operationId: "listBankAccounts", tool: "bank_accounts_list" },
269
+ { operationId: "getBankAccount", tool: "bank_accounts_get" },
270
+ // Dados de referência de pagamento
271
+ { operationId: "listPaymentConditions", tool: "payment_conditions_list" },
272
+ { operationId: "listPaymentMethods", tool: "payment_methods_list" },
273
+ { operationId: "listPaymentMethodsAp", tool: "payment_methods_ap_list" },
274
+ // Repasses
275
+ { operationId: "syncPayout", tool: "payouts_sync", write: true },
276
+ // Webhooks — edição, teste e entregas
277
+ { operationId: "updateWebhook", tool: "webhooks_update", write: true },
278
+ { operationId: "deleteWebhook", tool: "webhooks_delete", write: true, destructive: true },
279
+ { operationId: "getWebhook", tool: "webhooks_get_config" },
280
+ { operationId: "upsertWebhook", tool: "webhooks_upsert_config", write: true },
281
+ { operationId: "testWebhook", tool: "webhooks_test", write: true },
282
+ { operationId: "listWebhookDeliveries", tool: "webhooks_list_deliveries" },
283
+ { operationId: "listWebhookEvents", tool: "webhooks_list_events" },
284
+ { operationId: "redeliverWebhook", tool: "webhooks_redeliver", write: true }
227
285
  ];
228
286
 
229
287
  // ../../src/lib/openApiSpec.ts
@@ -3048,7 +3106,7 @@ var API_MODULES = [
3048
3106
  permissions: [
3049
3107
  { key: "read", label: "Listar e visualizar", description: "Consultar propostas comerciais" },
3050
3108
  { key: "write", label: "Criar e editar", description: "Criar e editar propostas" },
3051
- { key: "send", label: "Enviar", description: "Enviar propostas por e-mail ou WhatsApp" },
3109
+ { key: "send", label: "Enviar", description: "Enviar propostas por e-mail" },
3052
3110
  { key: "delete", label: "Excluir", description: "Excluir propostas" }
3053
3111
  ]
3054
3112
  },
@@ -3357,6 +3415,22 @@ function augmentInputSchema(schema, opts) {
3357
3415
  }
3358
3416
  return { ...schema, properties };
3359
3417
  }
3418
+ function coerceObjectArg(value) {
3419
+ if (value && typeof value === "object" && !Array.isArray(value)) {
3420
+ return value;
3421
+ }
3422
+ if (typeof value === "string" && value.trim()) {
3423
+ try {
3424
+ const parsed = JSON.parse(value);
3425
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
3426
+ return parsed;
3427
+ }
3428
+ } catch {
3429
+ return void 0;
3430
+ }
3431
+ }
3432
+ return void 0;
3433
+ }
3360
3434
  function destructiveBlocked(args) {
3361
3435
  if (args.confirm === true) return null;
3362
3436
  return fail(
@@ -3405,7 +3479,7 @@ function buildCuratedTools(api, heldScopes) {
3405
3479
  if (blocked && args.dry_run !== true) return blocked;
3406
3480
  }
3407
3481
  const path = buildPath(desc, args);
3408
- const body = desc.hasBody ? args.body : void 0;
3482
+ const body = desc.hasBody ? coerceObjectArg(args.body) : void 0;
3409
3483
  if (args.dry_run === true) {
3410
3484
  return ok({
3411
3485
  dry_run: true,
@@ -3452,7 +3526,8 @@ function buildRequestTool(api) {
3452
3526
  body: { type: "object", description: "Corpo JSON (para POST/PATCH/PUT).", additionalProperties: true },
3453
3527
  company_id: { type: "string", description: "Opcional: UUID da empresa (header X-Company-Id)." },
3454
3528
  idempotency_key: { type: "string", description: "Opcional: chave de idempot\xEAncia (POST)." },
3455
- dry_run: { type: "boolean", description: "Se true, n\xE3o executa \u2014 s\xF3 mostra o que seria enviado." }
3529
+ dry_run: { type: "boolean", description: "Se true, n\xE3o executa \u2014 s\xF3 mostra o que seria enviado." },
3530
+ confirm: { type: "boolean", description: "Obrigat\xF3rio para DELETE: confirma a exclus\xE3o." }
3456
3531
  }
3457
3532
  },
3458
3533
  handler: async (args) => {
@@ -3461,17 +3536,23 @@ function buildRequestTool(api) {
3461
3536
  if (!METHODS.includes(method)) {
3462
3537
  return fail(`M\xE9todo inv\xE1lido: ${args.method}. Use um de: ${METHODS.join(", ")}.`);
3463
3538
  }
3539
+ if (method === "DELETE" && args.confirm !== true && args.dry_run !== true) {
3540
+ return fail(
3541
+ "A\xE7\xE3o destrutiva bloqueada. Passe confirm: true para executar, ou dry_run: true para pr\xE9-visualizar."
3542
+ );
3543
+ }
3464
3544
  let path = String(args.path ?? "");
3465
3545
  if (!path.startsWith("/")) return fail("path deve come\xE7ar com / (ex.: /customers).");
3466
- if (args.query && typeof args.query === "object") {
3546
+ const queryArg = coerceObjectArg(args.query);
3547
+ if (queryArg) {
3467
3548
  const u = new URLSearchParams();
3468
- for (const [k, v] of Object.entries(args.query)) {
3549
+ for (const [k, v] of Object.entries(queryArg)) {
3469
3550
  if (v !== void 0 && v !== null && v !== "") u.set(k, String(v));
3470
3551
  }
3471
3552
  const s = u.toString();
3472
3553
  if (s) path += (path.includes("?") ? "&" : "?") + s;
3473
3554
  }
3474
- const body = args.body && typeof args.body === "object" ? args.body : void 0;
3555
+ const body = coerceObjectArg(args.body);
3475
3556
  if (args.dry_run === true) {
3476
3557
  return ok({ dry_run: true, method, path, body: body ?? null });
3477
3558
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comando.one/mcp-server",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Servidor MCP (Model Context Protocol) para a API pública do Comando.One — opere seu ERP por linguagem natural.",
5
5
  "type": "module",
6
6
  "license": "MIT",