orquestra-mcp 1.47.0 → 1.49.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/README.md +17 -13
- package/package.json +1 -1
- package/src/server.mjs +37 -2
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# orquestra-mcp
|
|
2
2
|
|
|
3
|
-
Servidor MCP (Model Context Protocol) para Orquestra. Expone **
|
|
3
|
+
Servidor MCP (Model Context Protocol) para Orquestra. Expone **144 tools**
|
|
4
|
+
(conteo al 24 oct 2026, v1.49.0; la lista real está en `src/server.mjs`)
|
|
4
5
|
que llaman a la API de `orquestra-infra`: lectura de contexto/dashboard/
|
|
5
6
|
workspace/infra/paridad/listados, escritura de tareas/ideas/changelog/
|
|
6
7
|
notas/docs/módulos/flujo/categorías/infra/proyectos, y corridas de QA —
|
|
@@ -47,7 +48,7 @@ vez de contra producción).
|
|
|
47
48
|
|
|
48
49
|
## Setup manual (alternativa, sin el flujo de navegador)
|
|
49
50
|
|
|
50
|
-
Si
|
|
51
|
+
Si prefieres generar el token tú mismo en vez de usar `setup`:
|
|
51
52
|
|
|
52
53
|
1. **Cuenta + workspace en `orquestra-web`**: entra a la app, si no tienes
|
|
53
54
|
`workspaceId` te manda al wizard de onboarding.
|
|
@@ -75,7 +76,7 @@ Variables de entorno (todas opcionales si ya corriste `setup` — se leen de
|
|
|
75
76
|
| `ORQUESTRA_API_TOKEN` | sí | — |
|
|
76
77
|
| `ORQUESTRA_WORKSPACE_ID` | sí | — |
|
|
77
78
|
| `ORQUESTRA_DEFAULT_PROJECT_ID` | no | — |
|
|
78
|
-
| `ORQUESTRA_API_BASE` | no | `
|
|
79
|
+
| `ORQUESTRA_API_BASE` | no | `https://api.orquestra.me` |
|
|
79
80
|
| `ORQUESTRA_WEB_URL` (solo `setup`) | no | `https://app.orquestra.me` |
|
|
80
81
|
|
|
81
82
|
### Claude Code
|
|
@@ -152,23 +153,24 @@ Lectura de contexto:
|
|
|
152
153
|
| `get_platform_playbook` | `platform` | Guía de referencia + checklist de publicación en tienda (`ios`\|`android`) — sin red |
|
|
153
154
|
| `get_skills_catalog` | — | Catálogo de Claude Skills de terceros recomendadas — sin red |
|
|
154
155
|
| `preview_skill` | `key?` / `sourceRepo?`+`sourcePath?` | Trae el SKILL.md real de una skill de terceros, sin instalar nada |
|
|
155
|
-
| `install_skill` | `key?` / `sourceRepo?`+`sourcePath?`, `scope`, `confirmed` | Descarga e instala una skill en `.claude/skills/` — solo después de `preview_skill` + confirmación del usuario; además registra la instalación en Orquestra (best-effort) |
|
|
156
|
+
| `install_skill` | `key?` / `sourceRepo?`+`sourcePath?`, `scope`, `confirmed` | Descarga e instala una skill en `.claude/skills/{key}/` de la carpeta actual (`scope:'project'`) o en `~/.claude/skills/{key}/` (`scope:'global'`) — solo después de `preview_skill` + confirmación del usuario; además registra la instalación en Orquestra (best-effort) |
|
|
156
157
|
| `list_installed_skills` | `projectId?` | Registros reales de skills instaladas en el proyecto (colección `skills`, no el catálogo) |
|
|
157
158
|
| `create_skill_install` / `update_skill_install` | ver server.mjs | Self-report manual de una skill instalada a mano, fuera del flujo de `install_skill` |
|
|
158
159
|
| `get_setup_guide` | — | Orden recomendado (flujo→categorías→infra→módulos→tareas→ideas→notas→changelog→docs) para configurar/sincronizar sin duplicar — sin red |
|
|
159
160
|
| `list_modules` / `list_statuses` / `list_categories` / `list_services` / `list_environments` / `list_distributions` | `projectId?` | Lista completa de cada entidad — revísalos antes de `create_*` para no duplicar (patrón upsert) |
|
|
160
161
|
|
|
161
162
|
Creación (`create_*`) y edición (`update_*`) — mismo patrón en todos, solo
|
|
162
|
-
crear/editar,
|
|
163
|
+
crear/editar (los únicos borrados acotados están en "Estado", abajo). Tabla
|
|
164
|
+
parcial: la lista completa está en `src/server.mjs`:
|
|
163
165
|
|
|
164
166
|
| Entidad | Tools | Notas |
|
|
165
167
|
|---|---|---|
|
|
166
168
|
| Tareas | `create_task`, `update_task` | `update_task` incluye `scope` — úsalo para resolver desfases de paridad |
|
|
167
169
|
| Verificaciones por plataforma | `list_verifications`, `add_verification`, `update_verification`, `delete_verification`, `verify_with_agent` | Confirmaciones (humanas o de agente) de que la tarea quedó bien en web/iOS/Android/API — NO van en el checklist. La tarea no cierra con verificaciones abiertas y se cierra sola al aprobarse la última; `failed` (con `note`) la regresa a su estatus anterior. También: `verifications` en `create_task`, `waiveVerifications` en `update_task` (solo con confirmación del usuario) y `verificationId` en `create_agent_run` |
|
|
168
|
-
| Ideas | `create_idea` | |
|
|
169
|
-
| Changelog | `create_changelog_entry` | Estilo Keep a Changelog |
|
|
170
|
-
| Notas | `create_note` | |
|
|
171
|
-
| Docs | `create_doc` | |
|
|
170
|
+
| Ideas | `list_ideas`, `create_idea`, `update_idea` | |
|
|
171
|
+
| Changelog | `list_changelog`, `create_changelog_entry`, `update_changelog_entry` | Estilo Keep a Changelog |
|
|
172
|
+
| Notas | `list_notes`, `create_note`, `update_note` | |
|
|
173
|
+
| Docs | `create_doc`, `get_doc`, `update_doc` | |
|
|
172
174
|
| Módulos | `create_module`, `update_module` | `scope` también editable |
|
|
173
175
|
| Flujo (estatus) | `create_status`, `update_status` | `nextIds` define las transiciones válidas |
|
|
174
176
|
| Categorías | `create_category`, `update_category` | |
|
|
@@ -181,7 +183,7 @@ Compuestas:
|
|
|
181
183
|
| Tool | Args | Descripción |
|
|
182
184
|
|---|---|---|
|
|
183
185
|
| `init_project` | `name`, `description?`, `phase?`, `projectType?`, `distributions?`, `categories?` | Crea un proyecto nuevo en el workspace — categorías+distribuciones+flujo conectado en un paso |
|
|
184
|
-
| `apply_stage_playbook` | `stageId`, `moduleName
|
|
186
|
+
| `apply_stage_playbook` | `stageId`, `moduleName?` | Crea el módulo + todas las tareas de la plantilla de una etapa |
|
|
185
187
|
|
|
186
188
|
Los campos enum (`type`, `priority`, `status`, etc.) están fijos y
|
|
187
189
|
documentados en el `inputSchema` de cada tool — el modelo los ve sin
|
|
@@ -227,7 +229,7 @@ create/update sigue siendo criterio del agente y del humano.
|
|
|
227
229
|
|
|
228
230
|
## Estado
|
|
229
231
|
|
|
230
|
-
|
|
232
|
+
144 tools (ver arriba): lectura (contexto, dashboard, workspace, infra, paridad, standup,
|
|
231
233
|
sync report, setup guide, playbooks de etapa y de plataforma, catálogo de
|
|
232
234
|
skills, search) + `list_*` de cada colección + creación/edición de tareas
|
|
233
235
|
(con checklist, verificaciones por plataforma, tiempo, adjuntos, merge), ideas (con comentarios), notas,
|
|
@@ -236,6 +238,8 @@ infraestructura, proyecto, contenido (canales, campañas, contenido,
|
|
|
236
238
|
Postproxy), agentes, skills, sugerencias y vínculos entre ítems
|
|
237
239
|
(`link_items`/`unlink_items`/`list_relations`) + compuestas (init_project,
|
|
238
240
|
apply_stage_playbook, apply_platform_playbook, install_skill). Sin
|
|
239
|
-
`delete_*` salvo adjuntos, ítems de checklist, verificaciones
|
|
240
|
-
(`unlink_items`)
|
|
241
|
+
`delete_*` salvo adjuntos, ítems de checklist, verificaciones, vínculos
|
|
242
|
+
(`unlink_items`) y el link del portal del cliente (`revoke_client_portal_link`).
|
|
243
|
+
Comando extra de CLI (no tool): `npx orquestra-mcp vault sync <carpeta> [--apply]`
|
|
244
|
+
(base de conocimiento ↔ vault de Obsidian). Publicado en npm como
|
|
241
245
|
`orquestra-mcp` (unscoped) -- `npx orquestra-mcp setup`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orquestra-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.49.0",
|
|
4
4
|
"description": "Servidor MCP de Orquestra -- 135 tools para leer y escribir tareas, ideas, changelog, infraestructura, contenido, QA y más desde un agente de IA",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/server.mjs
CHANGED
|
@@ -89,7 +89,7 @@ const SETUP_GUIDE = {
|
|
|
89
89
|
{ step: 6, section: 'Ideas', check: 'list_ideas', createOrUpdate: 'create_idea / update_idea / convert_idea_to_task', matchBy: 'title' },
|
|
90
90
|
{ step: 7, section: 'Notas', check: 'list_notes', createOrUpdate: 'create_note / update_note', matchBy: 'title' },
|
|
91
91
|
{ step: 8, section: 'Changelog', check: 'list_changelog', createOrUpdate: 'create_changelog_entry / update_changelog_entry', matchBy: 'text' },
|
|
92
|
-
{ step: 9, section: 'Docs', check: 'search', createOrUpdate: 'create_doc
|
|
92
|
+
{ step: 9, section: 'Docs', check: 'search', createOrUpdate: 'create_doc / update_doc (get_doc para leer el texto completo)', matchBy: 'title' },
|
|
93
93
|
],
|
|
94
94
|
}
|
|
95
95
|
|
|
@@ -293,7 +293,7 @@ export function createServer() {
|
|
|
293
293
|
registerRead(
|
|
294
294
|
'search',
|
|
295
295
|
'/v1/search',
|
|
296
|
-
'Busca por texto en tareas, actividades (reuniones/llamadas), notas, ideas y docs de un proyecto de Orquestra. También por folio ("ORQ-123"
|
|
296
|
+
'Busca por texto en tareas, actividades (reuniones/llamadas), notas, ideas y docs de un proyecto de Orquestra. También por folio ("ORQ-123") o por clave de módulo ("AUTH-3") -- la exacta sale primero -- y sin importar acentos. Primero lo que coincide en el folio o el título, después en el cuerpo; tope de 30 resultados: si buscas ideas o docs en un proyecto con muchas tareas, pasa `types` para que no queden tapadas.',
|
|
297
297
|
{
|
|
298
298
|
q: z.string().describe('Texto a buscar'),
|
|
299
299
|
types: z.array(z.enum(['task', 'activity', 'note', 'idea', 'doc', 'knowledge'])).optional().describe('Limitar a estos tipos (opcional). Sin esto busca en todos. knowledge = solo la base vinculada a este proyecto.'),
|
|
@@ -768,6 +768,7 @@ export function createServer() {
|
|
|
768
768
|
skipParity: z.boolean().optional().describe('true = NO sumar las plataformas hermanas al scope aunque tengan el mismo productKey. Solo cuando el trabajo es genuinamente de UNA plataforma (ej. un ajuste de Gradle que no tiene contraparte en iOS) -- no lo mandes por default. Las tareas type="bug" nunca propagan, sin necesidad de esto.'),
|
|
769
769
|
parityExempt: z.boolean().optional().describe('true = este trabajo es de UNA sola plataforma y no cuenta en get_parity_summary (se pone solo cuando skipParity va con scope de una sola dist). false para volver a contarla.'),
|
|
770
770
|
parityOf: z.string().optional().describe('Folio: id de la tarea ORIGEN de la que esta es la hermana para otra plataforma (ej. la versión iOS de una tarea de Android). En paridad cuentan como UN item y al cerrar esta, su plataforma queda hecha en el origen. El origen no puede ser hermana de otra. "" lo quita.'),
|
|
771
|
+
moduleCode: z.string().max(40).optional().describe('Clave de la tarea dentro de su módulo (ej. "AUTH-3"), ADEMÁS del folio ORQ-N. NO la mandes normalmente: si el módulo tiene clave (key), el server la asigna sola. Solo para conservar la clave que ya traía de otro sistema al importar (ej. "PROJ-128" de Jira/Linear).'),
|
|
771
772
|
relatedTaskId: z.string().optional().describe('"Bloqueada por" -- id de otra tarea. LEGACY desde ORQ-248: si vas a bloquear por más de una tarea, usa blockedByIds en vez de esto (relatedTaskId se sigue llenando solo, como blockedByIds[0], para paridad con iOS/Android).'),
|
|
772
773
|
blockedByIds: z.array(z.string()).optional().describe('"Bloqueada por" -- ids de otras tareas (puede ser más de una). Esta tarea se muestra como bloqueada mientras ALGUNA de esas no llegue a un estatus final (isFinal). Reemplaza a relatedTaskId para bloqueos múltiples -- preferí este campo, no relatedTaskId, salvo que de verdad sea un solo bloqueador.'),
|
|
773
774
|
location: z.string().optional().describe('Solo relevante para type "meeting"/"call" (plataforma o lugar, ej. "Zoom", "Oficina") o "followup"/"business" (contexto libre) -- ignóralo para el resto de los tipos.'),
|
|
@@ -813,6 +814,7 @@ export function createServer() {
|
|
|
813
814
|
.describe('Alcance por distribución -- usa get_parity_summary para ver el scope actual antes de editarlo'),
|
|
814
815
|
parityExempt: z.boolean().optional().describe('true = este trabajo es de UNA sola plataforma y no cuenta en get_parity_summary; false para volver a contarla.'),
|
|
815
816
|
parityOf: z.string().optional().describe('Folio: id de la tarea ORIGEN de la que esta es la hermana para otra plataforma (ej. la versión iOS de una tarea de Android). En paridad cuentan como UN item y al cerrar esta, su plataforma queda hecha en el origen. El origen no puede ser hermana de otra. "" lo quita.'),
|
|
817
|
+
moduleCode: z.string().max(40).optional().describe('Clave de la tarea dentro de su módulo (ej. "AUTH-3"), texto libre editable a mano. "" la quita. Mover la tarea a otro módulo (moduleId) NO la cambia: la clave es estable.'),
|
|
816
818
|
relatedTaskId: z.string().optional().describe('"Bloqueada por" -- id de otra tarea, o "" para quitar el bloqueo. LEGACY, ver create_task -- preferí blockedByIds.'),
|
|
817
819
|
blockedByIds: z.array(z.string()).optional().describe('"Bloqueada por" -- reemplaza el array COMPLETO (no hace merge), [] quita todos los bloqueos. Ver create_task.'),
|
|
818
820
|
location: z.string().optional().describe('Solo relevante para type "meeting"/"call"/"followup"/"business". Ver create_task.'),
|
|
@@ -2333,10 +2335,41 @@ export function createServer() {
|
|
|
2333
2335
|
}
|
|
2334
2336
|
)
|
|
2335
2337
|
|
|
2338
|
+
// Editar docs (ORQ-409): get_doc trae el texto completo (search solo da fragmentos) para que
|
|
2339
|
+
// update_doc no pise el contenido con una versión recortada.
|
|
2340
|
+
server.registerTool(
|
|
2341
|
+
'get_doc',
|
|
2342
|
+
{
|
|
2343
|
+
description: 'Lee un documento completo del proyecto (contenido, tipo, carpeta, módulo, visibilidad). Úsala antes de update_doc: content se reemplaza entero, así que parte del texto actual. El id sale de search (types=["doc"]).',
|
|
2344
|
+
inputSchema: { projectId: z.string().optional().describe(PROJECT_ID_DESC), id: z.string() },
|
|
2345
|
+
},
|
|
2346
|
+
async ({ projectId, id }) => {
|
|
2347
|
+
try { return textResult(await apiGet(config, `/v1/docs/${id}`, { projectId: resolveProjectId(projectId) })) } catch (err) { return errorResult(err) }
|
|
2348
|
+
}
|
|
2349
|
+
)
|
|
2350
|
+
|
|
2351
|
+
registerUpdate('update_doc', '/v1/docs',
|
|
2352
|
+
'Edita un documento existente. Solo se cambian los campos que mandes; content REEMPLAZA el texto entero (lee primero con get_doc y manda el documento completo, no solo el cambio). La versión anterior queda en el historial del doc ("Versiones"). Si cambias el título, los [[Título viejo]] de todo el proyecto se reescriben solos.',
|
|
2353
|
+
{
|
|
2354
|
+
title: z.string().optional(),
|
|
2355
|
+
content: z.string().optional().describe('Markdown completo del doc. [[Título]] enlaza otra nota, doc, tarea o idea.'),
|
|
2356
|
+
type: z.enum(DOC_TYPES).optional(),
|
|
2357
|
+
adrStatus: z.enum(ADR_STATUSES).optional().describe('Solo para type=\'adr\'.'),
|
|
2358
|
+
adrContext: z.string().optional().describe('Solo para type=\'adr\'.'),
|
|
2359
|
+
adrConsequences: z.string().optional().describe('Solo para type=\'adr\'.'),
|
|
2360
|
+
moduleId: z.string().optional(),
|
|
2361
|
+
folder: z.enum(DOC_FOLDERS).optional(),
|
|
2362
|
+
visibility: z.enum(DOC_VISIBILITY).optional().describe('"team" | "workspace" | "public" (expone el doc sin sesión).'),
|
|
2363
|
+
reviewOwnerUid: z.string().optional(),
|
|
2364
|
+
reviewIntervalDays: z.number().optional(),
|
|
2365
|
+
}
|
|
2366
|
+
)
|
|
2367
|
+
|
|
2336
2368
|
// ═══ ESCRITURA (nivel B -- módulos, flujo, categorías, infra) ═══════════════
|
|
2337
2369
|
|
|
2338
2370
|
const SCOPE_SCHEMA = z.array(z.object({ distId: z.string(), layer: z.string().optional(), done: z.boolean().optional(), ...SCOPE_EVIDENCE })).optional()
|
|
2339
2371
|
|
|
2372
|
+
const MODULE_KEY = z.string().optional().describe('Clave del módulo (ej. "AUTH", "PAGOS"): 2-10 letras/números, empieza con letra, única en el proyecto. Numera sus tareas (AUTH-1, AUTH-2...) en moduleCode, además del folio ORQ-N. Solo si el usuario la pidió o el proyecto ya usa claves -- no la inventes.')
|
|
2340
2373
|
registerCreate('create_module', '/v1/modules', 'Crea un módulo en un proyecto de Orquestra.', {
|
|
2341
2374
|
name: z.string().describe('Nombre del módulo'),
|
|
2342
2375
|
description: z.string().optional(),
|
|
@@ -2349,6 +2382,7 @@ export function createServer() {
|
|
|
2349
2382
|
ownerUid: z.string().optional().describe('uid del miembro responsable del avance del módulo'),
|
|
2350
2383
|
dependsOnModuleIds: z.array(z.string()).optional().describe('IDs de módulos de los que este depende (dependencia planeada, manual)'),
|
|
2351
2384
|
closureCriteria: z.string().optional().describe('Texto libre: cuándo se considera verdaderamente cerrado'),
|
|
2385
|
+
key: MODULE_KEY,
|
|
2352
2386
|
})
|
|
2353
2387
|
registerUpdate('update_module', '/v1/modules', 'Edita un módulo existente (incluido su scope multiplataforma).', {
|
|
2354
2388
|
name: z.string().optional(),
|
|
@@ -2362,6 +2396,7 @@ export function createServer() {
|
|
|
2362
2396
|
ownerUid: z.string().optional().describe('uid del miembro responsable del avance del módulo'),
|
|
2363
2397
|
dependsOnModuleIds: z.array(z.string()).optional().describe('IDs de módulos de los que este depende (dependencia planeada, manual)'),
|
|
2364
2398
|
closureCriteria: z.string().optional().describe('Texto libre: cuándo se considera verdaderamente cerrado'),
|
|
2399
|
+
key: MODULE_KEY.describe(`${MODULE_KEY.description} Poner o cambiar la clave numera las tareas del módulo que todavía no tienen una (por orden de creación; la respuesta trae assignedCodes). "" la quita: las tareas conservan la suya.`),
|
|
2365
2400
|
})
|
|
2366
2401
|
|
|
2367
2402
|
registerCreate('create_status', '/v1/statuses', 'Crea un estatus (columna del flujo de tareas) en un proyecto.', {
|