@cgalaviz/vondi-mcp 0.0.0-stage → 0.5.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.
Files changed (147) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +279 -2
  3. package/dist/client.d.ts +53 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +372 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/main.d.ts +3 -0
  8. package/dist/main.d.ts.map +1 -0
  9. package/dist/main.js +49 -0
  10. package/dist/main.js.map +1 -0
  11. package/dist/registry/audit.d.ts +3 -0
  12. package/dist/registry/audit.d.ts.map +1 -0
  13. package/dist/registry/audit.js +23 -0
  14. package/dist/registry/audit.js.map +1 -0
  15. package/dist/registry/billing-core.d.ts +3 -0
  16. package/dist/registry/billing-core.d.ts.map +1 -0
  17. package/dist/registry/billing-core.js +612 -0
  18. package/dist/registry/billing-core.js.map +1 -0
  19. package/dist/registry/billing-documents.d.ts +3 -0
  20. package/dist/registry/billing-documents.d.ts.map +1 -0
  21. package/dist/registry/billing-documents.js +652 -0
  22. package/dist/registry/billing-documents.js.map +1 -0
  23. package/dist/registry/binary-downloads.d.ts +3 -0
  24. package/dist/registry/binary-downloads.d.ts.map +1 -0
  25. package/dist/registry/binary-downloads.js +80 -0
  26. package/dist/registry/binary-downloads.js.map +1 -0
  27. package/dist/registry/calendar.d.ts +3 -0
  28. package/dist/registry/calendar.d.ts.map +1 -0
  29. package/dist/registry/calendar.js +330 -0
  30. package/dist/registry/calendar.js.map +1 -0
  31. package/dist/registry/canned-responses.d.ts +11 -0
  32. package/dist/registry/canned-responses.d.ts.map +1 -0
  33. package/dist/registry/canned-responses.js +54 -0
  34. package/dist/registry/canned-responses.js.map +1 -0
  35. package/dist/registry/catalog-images.d.ts +3 -0
  36. package/dist/registry/catalog-images.d.ts.map +1 -0
  37. package/dist/registry/catalog-images.js +48 -0
  38. package/dist/registry/catalog-images.js.map +1 -0
  39. package/dist/registry/catalog.d.ts +3 -0
  40. package/dist/registry/catalog.d.ts.map +1 -0
  41. package/dist/registry/catalog.js +156 -0
  42. package/dist/registry/catalog.js.map +1 -0
  43. package/dist/registry/charges.d.ts +3 -0
  44. package/dist/registry/charges.d.ts.map +1 -0
  45. package/dist/registry/charges.js +63 -0
  46. package/dist/registry/charges.js.map +1 -0
  47. package/dist/registry/conversations.d.ts +9 -0
  48. package/dist/registry/conversations.d.ts.map +1 -0
  49. package/dist/registry/conversations.js +246 -0
  50. package/dist/registry/conversations.js.map +1 -0
  51. package/dist/registry/core-extras.d.ts +3 -0
  52. package/dist/registry/core-extras.d.ts.map +1 -0
  53. package/dist/registry/core-extras.js +532 -0
  54. package/dist/registry/core-extras.js.map +1 -0
  55. package/dist/registry/customers.d.ts +3 -0
  56. package/dist/registry/customers.d.ts.map +1 -0
  57. package/dist/registry/customers.js +244 -0
  58. package/dist/registry/customers.js.map +1 -0
  59. package/dist/registry/data-sources.d.ts +3 -0
  60. package/dist/registry/data-sources.d.ts.map +1 -0
  61. package/dist/registry/data-sources.js +144 -0
  62. package/dist/registry/data-sources.js.map +1 -0
  63. package/dist/registry/hooks.d.ts +3 -0
  64. package/dist/registry/hooks.d.ts.map +1 -0
  65. package/dist/registry/hooks.js +130 -0
  66. package/dist/registry/hooks.js.map +1 -0
  67. package/dist/registry/iam.d.ts +3 -0
  68. package/dist/registry/iam.d.ts.map +1 -0
  69. package/dist/registry/iam.js +116 -0
  70. package/dist/registry/iam.js.map +1 -0
  71. package/dist/registry/index.d.ts +6 -0
  72. package/dist/registry/index.d.ts.map +1 -0
  73. package/dist/registry/index.js +82 -0
  74. package/dist/registry/index.js.map +1 -0
  75. package/dist/registry/integrations.d.ts +3 -0
  76. package/dist/registry/integrations.d.ts.map +1 -0
  77. package/dist/registry/integrations.js +65 -0
  78. package/dist/registry/integrations.js.map +1 -0
  79. package/dist/registry/notifications.d.ts +3 -0
  80. package/dist/registry/notifications.d.ts.map +1 -0
  81. package/dist/registry/notifications.js +44 -0
  82. package/dist/registry/notifications.js.map +1 -0
  83. package/dist/registry/orders.d.ts +3 -0
  84. package/dist/registry/orders.d.ts.map +1 -0
  85. package/dist/registry/orders.js +134 -0
  86. package/dist/registry/orders.js.map +1 -0
  87. package/dist/registry/payments-gateways.d.ts +3 -0
  88. package/dist/registry/payments-gateways.d.ts.map +1 -0
  89. package/dist/registry/payments-gateways.js +222 -0
  90. package/dist/registry/payments-gateways.js.map +1 -0
  91. package/dist/registry/payments.d.ts +3 -0
  92. package/dist/registry/payments.d.ts.map +1 -0
  93. package/dist/registry/payments.js +39 -0
  94. package/dist/registry/payments.js.map +1 -0
  95. package/dist/registry/pricing.d.ts +3 -0
  96. package/dist/registry/pricing.d.ts.map +1 -0
  97. package/dist/registry/pricing.js +20 -0
  98. package/dist/registry/pricing.js.map +1 -0
  99. package/dist/registry/quotes.d.ts +19 -0
  100. package/dist/registry/quotes.d.ts.map +1 -0
  101. package/dist/registry/quotes.js +81 -0
  102. package/dist/registry/quotes.js.map +1 -0
  103. package/dist/registry/reports.d.ts +3 -0
  104. package/dist/registry/reports.d.ts.map +1 -0
  105. package/dist/registry/reports.js +33 -0
  106. package/dist/registry/reports.js.map +1 -0
  107. package/dist/registry/shipping.d.ts +3 -0
  108. package/dist/registry/shipping.d.ts.map +1 -0
  109. package/dist/registry/shipping.js +85 -0
  110. package/dist/registry/shipping.js.map +1 -0
  111. package/dist/registry/social-channels.d.ts +3 -0
  112. package/dist/registry/social-channels.d.ts.map +1 -0
  113. package/dist/registry/social-channels.js +64 -0
  114. package/dist/registry/social-channels.js.map +1 -0
  115. package/dist/registry/subscriptions.d.ts +4 -0
  116. package/dist/registry/subscriptions.d.ts.map +1 -0
  117. package/dist/registry/subscriptions.js +103 -0
  118. package/dist/registry/subscriptions.js.map +1 -0
  119. package/dist/registry/super-admin.d.ts +11 -0
  120. package/dist/registry/super-admin.d.ts.map +1 -0
  121. package/dist/registry/super-admin.js +222 -0
  122. package/dist/registry/super-admin.js.map +1 -0
  123. package/dist/registry/tenants.d.ts +13 -0
  124. package/dist/registry/tenants.d.ts.map +1 -0
  125. package/dist/registry/tenants.js +78 -0
  126. package/dist/registry/tenants.js.map +1 -0
  127. package/dist/registry/types.d.ts +67 -0
  128. package/dist/registry/types.d.ts.map +1 -0
  129. package/dist/registry/types.js +10 -0
  130. package/dist/registry/types.js.map +1 -0
  131. package/dist/registry/uploads.d.ts +3 -0
  132. package/dist/registry/uploads.d.ts.map +1 -0
  133. package/dist/registry/uploads.js +86 -0
  134. package/dist/registry/uploads.js.map +1 -0
  135. package/dist/registry/usage.d.ts +9 -0
  136. package/dist/registry/usage.d.ts.map +1 -0
  137. package/dist/registry/usage.js +33 -0
  138. package/dist/registry/usage.js.map +1 -0
  139. package/dist/registry/whatsapp-admin.d.ts +3 -0
  140. package/dist/registry/whatsapp-admin.d.ts.map +1 -0
  141. package/dist/registry/whatsapp-admin.js +222 -0
  142. package/dist/registry/whatsapp-admin.js.map +1 -0
  143. package/dist/tools.d.ts +8 -0
  144. package/dist/tools.d.ts.map +1 -0
  145. package/dist/tools.js +150 -0
  146. package/dist/tools.js.map +1 -0
  147. package/package.json +39 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Tupla (https://tupla.dev)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,280 @@
1
- # Temporary Holding Version
1
+ # @cgalaviz/vondi-mcp — MCP de Vondi
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Servidor [MCP](https://modelcontextprotocol.io) que expone la API de Vondi
4
+ (commerce-api: catálogo, clientes, cotizaciones, pedidos, pagos, envíos,
5
+ reportes, notificaciones, integraciones, uso, conversaciones de WhatsApp,
6
+ auditoría y, con una key global, administración de plataforma) como
7
+ herramientas para Claude o cualquier agente compatible con MCP.
8
+
9
+ Corre por **stdio** — el cliente (Claude Desktop, Claude Code, cualquier host
10
+ MCP) lo lanza como proceso local. No expone ningún puerto ni requiere
11
+ desplegarlo aparte. Publicado en npm como `@cgalaviz/vondi-mcp` (el bin se
12
+ llama `vondi-mcp`).
13
+
14
+ ## Instalar y correr
15
+
16
+ ```bash
17
+ npx @cgalaviz/vondi-mcp
18
+ ```
19
+
20
+ (o instalado globalmente: `npm install -g @cgalaviz/vondi-mcp` y luego
21
+ `vondi-mcp`). Necesita `COMMERCE_API_KEY` en el entorno — ver **Autenticación**
22
+ abajo. Sin ella, el proceso falla al arrancar con un mensaje explicando qué
23
+ falta, no con un error de red genérico en la primera tool que se intente usar.
24
+
25
+ ## Autenticación
26
+
27
+ Todo pasa por una **API key** (`Authorization: Bearer npk_...`), nunca una
28
+ sesión de usuario. Hay dos tipos:
29
+
30
+ - **Key de tenant** (la normal): se crea desde el panel en **Empresa → API
31
+ keys**, con los scopes que elijas. Solo puede operar la empresa que la
32
+ emitió.
33
+ - **Key global** (T-IAM-09b, solo super-admin): se crea en **Plataforma →
34
+ API keys globales**. Sin tenant fijo — cada llamada decide sobre cuál
35
+ operar con `COMMERCE_TENANT_ID` (ver abajo). Siempre lleva TODOS los
36
+ scopes; no es configurable. Al arrancar, el servidor detecta si la key es
37
+ global y lo avisa por stderr (`⚠️ ... esta API key es GLOBAL ...`), para
38
+ que nunca sea una sorpresa a media sesión.
39
+
40
+ En ambos casos, el MCP solo puede hacer lo que la key tenga permitido — todo
41
+ lo demás lo rechaza commerce-api con 403 (o 404 "Sin tenant" si falta
42
+ `X-Tenant-Id` con una key global). El servidor MCP no añade ni quita permisos
43
+ por su cuenta.
44
+
45
+ **Principio de menor privilegio:** usa una key de tenant con solo los scopes
46
+ que de verdad necesites, salvo que el caso de uso genuinamente cruce varias
47
+ empresas (soporte de plataforma, automatización cross-tenant) — ahí sí toca
48
+ key global, y con eso asumes que cualquier prompt que ese agente procese
49
+ puede, en teoría, terminar tocando cualquier empresa.
50
+
51
+ ## Variables de entorno
52
+
53
+ | Variable | Requerida | Default | Descripción |
54
+ |---|---|---|---|
55
+ | `COMMERCE_API_KEY` | Sí | — | La API key (`npk_...`). |
56
+ | `COMMERCE_API_BASE_URL` | No | `https://vondi.tupla.dev/api/v1` | Base de la API. Cambiar para apuntar a local/staging. |
57
+ | `COMMERCE_TENANT_ID` | No | — | Solo tiene efecto con una key global: manda `X-Tenant-Id` en cada request para acotarla a una empresa. Con una key de tenant normal se ignora. |
58
+ | `COMMERCE_TIMEOUT_MS` | No | `30000` | Tope por request antes de abortar. Una conexión colgada no debe dejar la sesión MCP entera esperando para siempre. |
59
+
60
+ ## Seguridad
61
+
62
+ - **`Authorization`/`X-Tenant-Id` nunca vienen del modelo**: cada tool los
63
+ arma el propio servidor desde variables de entorno fijas al arrancar
64
+ (`src/client.ts`); nada que el agente escriba en los argumentos de una
65
+ tool puede cambiar quién llama ni sobre qué tenant, más allá de lo que la
66
+ tool declara legítimamente (p. ej. un `id` de pedido).
67
+ - **Anotaciones de tool** (`readOnlyHint`/`destructiveHint`/`idempotentHint`/
68
+ `openWorldHint`, spec de MCP): cada tool las declara — `GET` es
69
+ `readOnlyHint`, `DELETE` y las mutaciones con efecto real difícil de
70
+ deshacer (reembolsos, cancelaciones, desactivar una integración/empresa,
71
+ mandar un mensaje de WhatsApp real) llevan `destructiveHint: true`. Un
72
+ cliente MCP que las respeta (Claude Desktop, Claude Code) puede pedir
73
+ confirmación antes de ejecutarlas. Son solo señales — commerce-api sigue
74
+ siendo el único candado real vía scopes.
75
+ - **Timeout por request**: ver `COMMERCE_TIMEOUT_MS` arriba.
76
+ - **Nunca guardes la key en texto plano compartido**: el secreto (`npk_...`)
77
+ se muestra una sola vez al crearlo. Si tu `.mcp.json` o
78
+ `claude_desktop_config.json` se sincroniza, se respalda o se comparte,
79
+ considera la key expuesta — revócala y crea una nueva si eso pasa. Preferir
80
+ un gestor de secretos del sistema operativo cuando el cliente MCP lo
81
+ soporte, en vez de dejar la key en el JSON de config.
82
+ - **Menor privilegio**: ver arriba. Una key con solo `catalog.read` no puede
83
+ hacer nada si el proceso o el prompt se ven comprometidos, más allá de leer
84
+ catálogo.
85
+ - El código es 100% código abierto en este repo (`apps/mcp-server/src`):
86
+ audítalo — no hay llamadas de red a nada más que
87
+ `COMMERCE_API_BASE_URL`, ni telemetría, ni logging del contenido de la key.
88
+
89
+ ## Build (para desarrollo local del propio servidor)
90
+
91
+ ```bash
92
+ pnpm --filter @cgalaviz/vondi-mcp build
93
+ ```
94
+
95
+ Genera `apps/mcp-server/dist/main.js`.
96
+
97
+ ## Configurar en Claude Code
98
+
99
+ ```bash
100
+ claude mcp add vondi \
101
+ --env COMMERCE_API_KEY=npk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
102
+ -- npx @cgalaviz/vondi-mcp
103
+ ```
104
+
105
+ O agregando a mano en `.mcp.json` (raíz del proyecto o `~/.claude.json`):
106
+
107
+ ```json
108
+ {
109
+ "mcpServers": {
110
+ "vondi": {
111
+ "command": "npx",
112
+ "args": ["@cgalaviz/vondi-mcp"],
113
+ "env": {
114
+ "COMMERCE_API_KEY": "npk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
115
+ }
116
+ }
117
+ }
118
+ }
119
+ ```
120
+
121
+ ## Configurar en Claude Desktop
122
+
123
+ En `claude_desktop_config.json` (menú Claude → Settings → Developer → Edit
124
+ Config):
125
+
126
+ ```json
127
+ {
128
+ "mcpServers": {
129
+ "vondi": {
130
+ "command": "npx",
131
+ "args": ["@cgalaviz/vondi-mcp"],
132
+ "env": {
133
+ "COMMERCE_API_KEY": "npk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
134
+ }
135
+ }
136
+ }
137
+ }
138
+ ```
139
+
140
+ ## Cualquier otro agente / cliente MCP
141
+
142
+ Cualquier host que hable el protocolo MCP por stdio sirve: lanzar
143
+ `npx @cgalaviz/vondi-mcp` (o `node apps/mcp-server/dist/main.js` desde el
144
+ repo) con `COMMERCE_API_KEY` en el entorno del proceso. No hay nada específico
145
+ de Claude en el servidor — es un `McpServer` estándar del SDK oficial
146
+ (`@modelcontextprotocol/sdk`).
147
+
148
+ ## Qué cubre
149
+
150
+ Dos superficies, según el tipo de key que recibe el proceso:
151
+
152
+ - **Key de negocio (tenant)** — la de cada empresa, 369 tools: catálogo
153
+ (productos, variantes, imágenes, categorías, importación), clientes, cotizaciones,
154
+ pedidos y cobros, suscripciones, pagos y transferencias, pasarelas (Backnest,
155
+ Conekta, Openpay), conversaciones y WhatsApp (conexiones, plantillas, horarios),
156
+ calendario y citas, canales sociales, hooks, fuentes de datos, cargos, envíos,
157
+ pricing, reportes, notificaciones, integraciones, uso, auditoría, IAM
158
+ (API keys, membresías, invitaciones) y facturación CFDI (catálogos, personas,
159
+ productos, facturas, solicitudes de factura, carta porte, descarga masiva,
160
+ configuración y credenciales).
161
+ - **Key global (super-admin de plataforma)** — todo lo anterior más 34
162
+ tools de plataforma (403 tools en total): `super_admin_*` (empresas,
163
+ membresías, invitaciones, keys de tenant y globales, uso, overview) y la compra
164
+ y uso de timbres (`billing_stamp_purchase`, `billing_stamp_summary`,
165
+ `billing_stamp_packages_list`, `billing_stamp_purchase_confirm`,
166
+ `billing_stamp_usage_history`).
167
+
168
+ El filtro vive en `src/registry/index.ts` (`routesForKeyKind`,
169
+ `isSuperAdminRoute`). Al arrancar, `src/main.ts` prueba la key contra
170
+ `/super-admin/overview`: 200 → global, 403/401 → tenant, otro error → tenant
171
+ (caso seguro). Una key de negocio nunca registra tools de plataforma.
172
+
173
+ Ver `src/registry/` — un archivo por dominio, cada uno una lista declarativa de
174
+ rutas (`RouteDef`, ver `src/registry/types.ts`) que `src/tools.ts` convierte en
175
+ tools MCP genéricamente. Las pocas rutas que no son JSON puro (fotos de
176
+ catálogo, PDF de cotización, XML/PDF de CFDI) están registradas a mano en
177
+ `src/registry/catalog-images.ts`, `src/registry/binary-downloads.ts` y
178
+ `src/registry/uploads.ts`.
179
+
180
+ Quedan fuera a propósito: endpoints `public/*` (usan token de link
181
+ compartido, no API key), flujos de login/MFA/recuperación de contraseña y
182
+ aceptación de invitación (no son API-key), webhooks entrantes (`webhook/*`,
183
+ los llama el proveedor, no un agente), redirecciones OAuth (`*/authorize`) y
184
+ callbacks, rutas de sesión de cliente final (`/me/*`, `customer-auth`),
185
+ impersonar (cookie de sesión de navegador; una key global + `COMMERCE_TENANT_ID`
186
+ logra lo mismo), y descargas CSV/ZIP/XML crudo y subidas multipart que el DSL
187
+ JSON no puede representar. Operativos de una sola vez (QR de Evolution, rotación
188
+ de webhook secret) se hacen mejor desde el panel.
189
+
190
+ ## Desarrollo
191
+
192
+ ```bash
193
+ pnpm --filter @cgalaviz/vondi-mcp dev # tsx, sin build previo
194
+ pnpm --filter @cgalaviz/vondi-mcp typecheck
195
+ pnpm --filter @cgalaviz/vondi-mcp lint
196
+ ```
197
+
198
+ Para probar interactivamente sin un cliente MCP completo, usa el
199
+ [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector):
200
+
201
+ ```bash
202
+ npx @modelcontextprotocol/inspector node apps/mcp-server/dist/main.js
203
+ ```
204
+
205
+ ## API keys — guía completa
206
+
207
+ Hay dos tipos y son cosas distintas.
208
+
209
+ ### Key de tenant (la que vas a usar el 99% del tiempo)
210
+
211
+ 1. **Panel** → **Empresa → API keys** → **"Crear API key"**.
212
+ 2. Nombre: algo descriptivo (ej. `"MCP Claude Code local"`, `"Agente chat producción"`).
213
+ 3. Scopes: **mínimo privilegio**. Para un agente de chat que cotiza, cobra y
214
+ lee catálogo: `catalog.read`, `customers.read`, `quotes.write`, `orders.write`,
215
+ `chat.read`, `chat.write`. Para reporting/auditoría sumá `payments.read`,
216
+ `audit.read`. **Nunca** pongas `tenant.admin` o `apikeys.manage` salvo que la
217
+ tool específica lo pida.
218
+ 4. Sin expiración, o 90/180 días si querés rotación automática. Una key eterna
219
+ es una fuga permanente si se filtra.
220
+ 5. **La key completa (`npk_...`) se muestra UNA sola vez** al crearla. Copiala
221
+ a un gestor de secretos del sistema (1Password CLI, macOS Keychain,
222
+ `gpg`-encrypted file) ANTES de cerrar el modal.
223
+ 6. La key queda asociada a UN tenant — si el agente debe operar varias
224
+ empresas, necesitás una key por tenant, o una key global.
225
+
226
+ ### Key global (T-IAM-09b — solo super-admin de plataforma)
227
+
228
+ Cubre TODOS los tenants sin que la API key quede atada a uno. Pensada para
229
+ soporte de plataforma y automatizaciones cross-tenant.
230
+
231
+ 1. **Panel** → **Plataforma → API keys globales** → **"Crear API key global"**.
232
+ 2. No hay scopes que elegir — siempre lleva todos.
233
+ 3. La key se crea en la cuenta de un humano (sesión de panel); una key global
234
+ **no puede emitir más keys globales** por sí sola (esto es por diseño).
235
+ 4. Para acotar a un tenant puntual sin perder los permisos, export
236
+ `COMMERCE_TENANT_ID=<uuid>` y el header `X-Tenant-Id` se manda solo. Sin
237
+ esa env, la key opera sobre cualquier empresa.
238
+
239
+ ### Convención operativa
240
+
241
+ - **Una key por cliente MCP / por despliegue**: Claude Desktop en la laptop
242
+ del dueño, Claude Code en CI, el agente de chat en el contenedor del
243
+ cliente — cada uno su propia key. Si una se filtra, revocas esa y las
244
+ demás siguen.
245
+ - **Rotación**: cuando un empleado del cliente que tenía acceso a la key se
246
+ va, o cada 90-180 días como política, revocá la key en el panel y emití
247
+ una nueva. El equipo de Tupla no necesita intervenir.
248
+ - **Logs**: si tu `.mcp.json` o `claude_desktop_config.json` se sincroniza
249
+ (iCloud, backup, dotfiles repo), se respalda o se comparte, considerá la
250
+ key expuesta — revocala y emití una nueva.
251
+ - **Menos es más**: si la tool que vas a usar no necesita `tenant.admin` para
252
+ funcionar (ver el README de cada tool), no le des ese scope a la key.
253
+
254
+ ## Publicar una versión nueva en npm
255
+
256
+ El paquete está bajo el scope personal `@cgalaviz/` (la cuenta npm del autor).
257
+ Como ya publicaste `atiendeya-mcp` antes, la cuenta tiene historial y no
258
+ requiere pasos previos.
259
+
260
+ ```bash
261
+ cd apps/mcp-server
262
+ npm login # user + 2FA OTP
263
+ pnpm --filter @cgalaviz/vondi-mcp build
264
+ npm version patch # o minor/major
265
+ npm publish # corre typecheck+lint+test+build (prepublishOnly)
266
+ ```
267
+
268
+ `npm publish` exige **2FA en el momento del publish** (no un token con
269
+ bypass-2FA — npm los está restringiendo para publish directo).
270
+
271
+ ### Verificar después de publicar
272
+
273
+ ```bash
274
+ npm view @cgalaviz/vondi-mcp version bin engines
275
+ npx @cgalaviz/vondi-mcp < /dev/null # arranca: "140 tools registradas"
276
+ ```
277
+
278
+ Si el publish falla con `404 Not Found - PUT`, lo más probable es que la
279
+ sesión de npm haya expirado o que el usuario autenticado no sea `cgalaviz` —
280
+ verificá con `npm whoami` y `npm login` de nuevo si hace falta.
@@ -0,0 +1,53 @@
1
+ export interface ApiResult {
2
+ ok: boolean;
3
+ status: number;
4
+ data: unknown;
5
+ }
6
+ /**
7
+ * Ejecuta la petición. Nunca lanza por un error HTTP del backend (4xx/5xx):
8
+ * ese error es información útil para el agente (falta un scope, un recurso
9
+ * no existe, una validación falló), así que se devuelve como dato normal
10
+ * con `ok:false`, no como excepción — el handler de la tool lo traduce a
11
+ * `isError` de MCP sin perder el detalle del body. Tampoco lanza por
12
+ * configuración inválida (URL malformada, scheme no permitido) — eso sería
13
+ * una falla de arranque, no de tool, y debe llegar al cliente como un
14
+ * mensaje accionable, no como un stack trace.
15
+ */
16
+ export declare function apiRequest(method: string, path: string, opts?: {
17
+ query?: Record<string, string | undefined>;
18
+ body?: unknown;
19
+ }): Promise<ApiResult>;
20
+ export interface DownloadResult {
21
+ ok: boolean;
22
+ status: number;
23
+ base64?: string;
24
+ mimeType?: string;
25
+ error?: unknown;
26
+ }
27
+ /** Descarga binaria (PDF de cotización, CSV de notificaciones): la respuesta no es JSON, se devuelve en base64 con tope. */
28
+ export declare function apiDownload(path: string): Promise<DownloadResult>;
29
+ /**
30
+ * Subida multipart (fotos de catálogo): las dos únicas rutas del registro
31
+ * que no son JSON puro, así que no encajan en `apiRequest` / el DSL
32
+ * declarativo de `registry/types.ts`. El agente manda la imagen en base64;
33
+ * aquí se valida el tamaño ANTES del decode y se arma el
34
+ * `multipart/form-data` que espera `ProductImageUploadInterceptor` (campo
35
+ * `file`).
36
+ */
37
+ export declare function apiUpload(path: string, file: {
38
+ base64: string;
39
+ filename: string;
40
+ mimeType: string;
41
+ }): Promise<ApiResult>;
42
+ /**
43
+ * Detecta, al arrancar, si la key configurada es GLOBAL (T-IAM-09b) —
44
+ * probando un endpoint que solo `SuperAdminGuard` deja pasar. Nunca lanza:
45
+ * "unknown" si no se pudo determinar (red caída, key inválida — eso ya lo
46
+ * va a reportar la primera tool que se use). Solo informativo, para el aviso
47
+ * de arranque en `main.ts`; ninguna tool depende de este resultado.
48
+ *
49
+ * El path del probe viene del registry (`SUPER_ADMIN_OVERVIEW_PATH`) para
50
+ * que un rename de la ruta no rompa silenciosamente el aviso de "key global".
51
+ */
52
+ export declare function probeKeyKind(): Promise<"global" | "tenant" | "unknown">;
53
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAmFA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACf;AA+DD;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GACxE,OAAO,CAAC,SAAS,CAAC,CA4BpB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAYD,4HAA4H;AAC5H,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAgFvE;AAqBD;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC3D,OAAO,CAAC,SAAS,CAAC,CAkDpB;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC,CAa7E"}