alora-mcp 0.1.0 → 0.3.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.
- package/package.json +2 -2
- package/src/index.js +89 -2
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alora-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Servidor MCP de Alora — Claude Code, Codex, Cursor y cualquier cliente MCP",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"alora-mcp": "src/index.js"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"alora-sdk": "^0.
|
|
10
|
+
"alora-sdk": "^0.3.0",
|
|
11
11
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
12
12
|
"tar": "^7.4.3",
|
|
13
13
|
"zod": "^3.24.0"
|
package/src/index.js
CHANGED
|
@@ -80,12 +80,33 @@ server.registerTool('project_status', {
|
|
|
80
80
|
}, wrap(({ project }) => client().status(project)));
|
|
81
81
|
|
|
82
82
|
server.registerTool('logs', {
|
|
83
|
-
description: '
|
|
83
|
+
description: 'Líneas de log del proyecto (deploys, runtime y salida de la app). Usalo para debuggear tus propios deploys.',
|
|
84
84
|
inputSchema: {
|
|
85
85
|
project: z.string(),
|
|
86
86
|
lines: z.number().optional().describe('Cantidad de líneas, default 100'),
|
|
87
|
+
since: z.string().optional().describe('Solo líneas posteriores a este instante (ISO o ms epoch)'),
|
|
87
88
|
},
|
|
88
|
-
}, wrap(({ project, lines }) => client().logs(project, { lines })));
|
|
89
|
+
}, wrap(({ project, lines, since }) => client().logs(project, { lines, since })));
|
|
90
|
+
|
|
91
|
+
server.registerTool('exec', {
|
|
92
|
+
description: 'Ejecuta un comando dentro de la microVM del proyecto (despierta la máquina si duerme). Devuelve stdout, stderr y exit_code. Para inspeccionar el filesystem, ver archivos en /data, debuggear. Ej: "ls -la /data", "cat /data/bitacora/hoy.log".',
|
|
93
|
+
inputSchema: { project: z.string(), command: z.string() },
|
|
94
|
+
}, wrap(({ project, command }) => client().exec(project, command)));
|
|
95
|
+
|
|
96
|
+
server.registerTool('restart', {
|
|
97
|
+
description: 'Reinicia la app sin redesplegar (útil para aplicar un cambio de estado o salir de un cuelgue).',
|
|
98
|
+
inputSchema: { project: z.string() },
|
|
99
|
+
}, wrap(({ project }) => client().restart(project)));
|
|
100
|
+
|
|
101
|
+
server.registerTool('cron_run', {
|
|
102
|
+
description: 'Dispara un cron AHORA (sin esperar su horario). Devuelve el status y el body de la respuesta de la app — útil para probar y ver el traceback si falla.',
|
|
103
|
+
inputSchema: { project: z.string(), id: z.string() },
|
|
104
|
+
}, wrap(({ project, id }) => client().cronRun(project, id)));
|
|
105
|
+
|
|
106
|
+
server.registerTool('token_create', {
|
|
107
|
+
description: 'Crea un token de acceso por proyecto que BYPASSEA el login: un script/webhook/backup externo puede pegarle a la URL de la app con Authorization: Bearer <token> sin SSO. Scoped a este proyecto y revocable. La app lo ve con x-alora-user-role: service. El token se muestra una sola vez.',
|
|
108
|
+
inputSchema: { project: z.string(), name: z.string().optional() },
|
|
109
|
+
}, wrap(({ project, name }) => client().tokenCreate(project, name)));
|
|
89
110
|
|
|
90
111
|
server.registerTool('list_versions', {
|
|
91
112
|
description: 'Historial de versiones del proyecto, con autor y mensaje.',
|
|
@@ -164,6 +185,72 @@ server.registerTool('ai_disable', {
|
|
|
164
185
|
inputSchema: { project: z.string() },
|
|
165
186
|
}, wrap(({ project }) => client().aiSetProject(project, false)));
|
|
166
187
|
|
|
188
|
+
server.registerTool('set_always_on', {
|
|
189
|
+
description: 'Enciende o apaga el modo siempre-encendido de un proyecto. Por default las apps DUERMEN sin tráfico (escala a cero, casi gratis). Con always_on=true la VM no duerme: sirve para watchers 24/7, loops que tickean cada X segundos, cron propio de la app, y ciclos largos de `claude -p` (minutos) que corren de fondo sin depender de un request HTTP. Cuesta ~US$7-14/mes de cómputo activo.',
|
|
190
|
+
inputSchema: { project: z.string(), always_on: z.boolean() },
|
|
191
|
+
}, wrap(({ project, always_on }) => client().scale(project, { always_on })));
|
|
192
|
+
|
|
193
|
+
server.registerTool('set_worker_mode', {
|
|
194
|
+
description: 'Convierte un proyecto en worker headless 24/7 (sin HTTP): un proceso de fondo — watcher, cron, motor que llama `claude -p` en loop — que corre siempre y se reinicia solo si cae. Implica always-on. Para volver a app web: mode="web". Requiere runtime Node o Python. El estado persiste en DATA_DIR.',
|
|
195
|
+
inputSchema: { project: z.string(), mode: z.enum(['web', 'worker']) },
|
|
196
|
+
}, wrap(({ project, mode }) => client().scale(project, { mode })));
|
|
197
|
+
|
|
198
|
+
server.registerTool('cron_create', {
|
|
199
|
+
description: 'Programa una tarea recurrente: Alora hace GET a <path> de tu app en el horario dado (cron de 5 campos, UTC). Si la app duerme, el disparo la despierta, corre la tarea y se vuelve a dormir — la forma barata de "correr un rato cada tanto" sin always-on. Tu app reconoce el disparo por el header x-alora-cron: 1. Para procesos continuos (cada segundos) usá worker en su lugar.',
|
|
200
|
+
inputSchema: {
|
|
201
|
+
project: z.string(),
|
|
202
|
+
schedule: z.string().describe('cron UTC: "0 * * * *" cada hora, "*/5 * * * *" cada 5 min, "5 0,12 * * *" 00:05 y 12:05'),
|
|
203
|
+
path: z.string().describe('ruta que tu app maneja, ej: /cron/hourly'),
|
|
204
|
+
once: z.boolean().optional().describe('si true, se borra solo tras correr una vez'),
|
|
205
|
+
},
|
|
206
|
+
}, wrap(({ project, schedule, path, once }) => client().cronCreate(project, schedule, path, once)));
|
|
207
|
+
|
|
208
|
+
server.registerTool('cron_list', {
|
|
209
|
+
description: 'Lista las tareas programadas de un proyecto con su último disparo y estado.',
|
|
210
|
+
inputSchema: { project: z.string() },
|
|
211
|
+
}, wrap(({ project }) => client().cronList(project)));
|
|
212
|
+
|
|
213
|
+
server.registerTool('cron_delete', {
|
|
214
|
+
description: 'Elimina una tarea programada por su id.',
|
|
215
|
+
inputSchema: { project: z.string(), id: z.string() },
|
|
216
|
+
}, wrap(({ project, id }) => client().cronDelete(project, id)));
|
|
217
|
+
|
|
218
|
+
server.registerTool('send_feedback', {
|
|
219
|
+
description: 'Envía feedback a los que hacen Alora. Usalo cuando choques con un límite, necesites una capacidad que no existe, o se te ocurra una forma mejor de usar la plataforma para lo que el usuario quiere hacer. Le llega directo al equipo. No es para errores de tu app (eso es logs) — es para lo que Alora debería poder hacer y todavía no puede.',
|
|
220
|
+
inputSchema: {
|
|
221
|
+
message: z.string().describe('Qué necesitás o cómo querrías usar Alora'),
|
|
222
|
+
category: z.enum(['feature-request', 'limitation', 'idea', 'bug', 'general']).optional(),
|
|
223
|
+
},
|
|
224
|
+
}, wrap(({ message, category }) => client().feedback(message, { category })));
|
|
225
|
+
|
|
226
|
+
server.registerTool('domain_search', {
|
|
227
|
+
description: 'Chequea disponibilidad de un nombre en 10 TLDs con precio aproximado. La compra dentro de Alora llega pronto; hoy el dueño lo compra donde prefiera y se conecta con domain_connect.',
|
|
228
|
+
inputSchema: { name: z.string().describe('Nombre sin TLD, ej: "miempresa"') },
|
|
229
|
+
}, wrap(({ name }) => client().domainSearch(name)));
|
|
230
|
+
|
|
231
|
+
server.registerTool('domain_connect', {
|
|
232
|
+
description: 'Conecta un dominio propio del dueño a un proyecto. Devuelve los registros DNS a cargar; el TLS se emite solo al detectarlos. El login de Alora funciona igual en el dominio custom.',
|
|
233
|
+
inputSchema: { project: z.string(), domain: z.string().describe('ej: app.miempresa.com') },
|
|
234
|
+
}, wrap(({ project, domain }) => client().domainConnect(project, domain)));
|
|
235
|
+
|
|
236
|
+
server.registerTool('domain_list', {
|
|
237
|
+
description: 'Dominios conectados a un proyecto con su estado de DNS y certificado TLS.',
|
|
238
|
+
inputSchema: { project: z.string() },
|
|
239
|
+
}, wrap(({ project }) => client().domainList(project)));
|
|
240
|
+
|
|
241
|
+
server.registerTool('domain_buy', {
|
|
242
|
+
description: 'Inicia la COMPRA de un dominio con el saldo del workspace. Es plata real e irreversible, así que SIEMPRE requiere que el dueño humano apruebe por email (vence en 24h) — vos no podés completarla solo. Requiere saldo suficiente. Seguí el estado con approval_status. Con project, al aprobarse queda conectado y con TLS solo.',
|
|
243
|
+
inputSchema: {
|
|
244
|
+
domain: z.string().describe('ej: miempresa.com'),
|
|
245
|
+
project: z.string().optional().describe('Proyecto al que conectarlo al aprobarse'),
|
|
246
|
+
},
|
|
247
|
+
}, wrap(({ domain, project }) => client().domainBuy(domain, project)));
|
|
248
|
+
|
|
249
|
+
server.registerTool('approval_status', {
|
|
250
|
+
description: 'Estado de una aprobación pendiente (ej: compra de dominio): pending, approved, denied, failed o expired.',
|
|
251
|
+
inputSchema: { id: z.string() },
|
|
252
|
+
}, wrap(({ id }) => client().approvalStatus(id)));
|
|
253
|
+
|
|
167
254
|
server.registerTool('wallet_balance', {
|
|
168
255
|
description: 'Saldo prepago del workspace y últimos movimientos del ledger. El saldo se carga en https://alora.build/wallet (checkout de Paddle) — el agente no puede cargar plata, solo el humano.',
|
|
169
256
|
inputSchema: {},
|