foundry-boards-mcp 0.1.0__tar.gz
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.
- foundry_boards_mcp-0.1.0/.env.example +18 -0
- foundry_boards_mcp-0.1.0/.gitignore +4 -0
- foundry_boards_mcp-0.1.0/LICENSE +21 -0
- foundry_boards_mcp-0.1.0/PKG-INFO +378 -0
- foundry_boards_mcp-0.1.0/README.md +350 -0
- foundry_boards_mcp-0.1.0/foundry_mcp/__init__.py +9 -0
- foundry_boards_mcp-0.1.0/foundry_mcp/__main__.py +6 -0
- foundry_boards_mcp-0.1.0/foundry_mcp/config.py +73 -0
- foundry_boards_mcp-0.1.0/foundry_mcp/foundry.py +685 -0
- foundry_boards_mcp-0.1.0/foundry_mcp/server.py +2234 -0
- foundry_boards_mcp-0.1.0/mcp.json.example +12 -0
- foundry_boards_mcp-0.1.0/pyproject.toml +62 -0
- foundry_boards_mcp-0.1.0/requirements.txt +5 -0
- foundry_boards_mcp-0.1.0/run.ps1 +12 -0
- foundry_boards_mcp-0.1.0/run_server.py +16 -0
- foundry_boards_mcp-0.1.0/tests/test_agent_identity.py +157 -0
- foundry_boards_mcp-0.1.0/tests/test_columns_and_attachments.py +380 -0
- foundry_boards_mcp-0.1.0/tests/test_config.py +26 -0
- foundry_boards_mcp-0.1.0/uv.lock +1164 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# ── MCP de tableros de Foundry — SOLO configuración (sin credenciales) ────────────
|
|
2
|
+
# La autenticación NO va aquí: te la pide Claude Code (diálogo interactivo) la primera vez.
|
|
3
|
+
# Este archivo es opcional; sin él se usan los valores por defecto de abajo.
|
|
4
|
+
|
|
5
|
+
# API de Foundry (el MISMO backend que consume el frontend). Incluye el prefijo /api/v1.
|
|
6
|
+
# Sin esta variable se habla con el Foundry público: https://foundry.collie.digital/api/v1
|
|
7
|
+
# Descoméntala solo para apuntar a otro backend — el tuyo en local, o uno propio.
|
|
8
|
+
# FOUNDRY_API_BASE=http://localhost:8000/api/v1
|
|
9
|
+
|
|
10
|
+
# Segundos de espera a la API.
|
|
11
|
+
FOUNDRY_TIMEOUT=30
|
|
12
|
+
|
|
13
|
+
# ── Override opcional (solo automatización/CI, SIN diálogo) ────────────────────────
|
|
14
|
+
# Si defines esto, el MCP se autentica sin pedir nada. Para uso normal, déjalo comentado
|
|
15
|
+
# y deja que Claude Code te pida las credenciales.
|
|
16
|
+
# FOUNDRY_TOKEN=
|
|
17
|
+
# FOUNDRY_EMAIL=
|
|
18
|
+
# FOUNDRY_PASSWORD=
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Collie Valley
|
|
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.
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: foundry-boards-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP para administrar los tableros Kanban de Foundry desde agentes de IA.
|
|
5
|
+
Project-URL: Homepage, https://foundry.collie.digital
|
|
6
|
+
Author: Collie Valley
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: agents,agile,claude,foundry,kanban,mcp,model-context-protocol
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Framework :: AsyncIO
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Natural Language :: Spanish
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Bug Tracking
|
|
21
|
+
Classifier: Topic :: Utilities
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: httpx>=0.27
|
|
24
|
+
Requires-Dist: keyring>=25
|
|
25
|
+
Requires-Dist: mcp<2,>=1.12
|
|
26
|
+
Requires-Dist: python-dotenv>=1.0
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# Foundry Boards — MCP para agentes de IA
|
|
30
|
+
|
|
31
|
+
Servidor **MCP** (Model Context Protocol) que le da a **Claude Code, Codex, OpenCode, Gemini**
|
|
32
|
+
y otros clientes compatibles herramientas para
|
|
33
|
+
**administrar los tableros de Foundry** con un **modelo de gestión de trabajo ágil** (ADR-0014):
|
|
34
|
+
listar/crear tableros, crear/mover/editar tarjetas (work items), **transicionar por estados**,
|
|
35
|
+
gestionar **jerarquía** (épicas/historias/subtareas), **etiquetas**, **vínculos**, **sprints**
|
|
36
|
+
(Scrum), leer el **historial estructurado** y **gestionar adjuntos** (leer imágenes, subir y
|
|
37
|
+
borrar) — además de mover un tablero personal a un Área.
|
|
38
|
+
|
|
39
|
+
No forma parte del backend ni lo modifica: habla el **mismo contrato REST público** que el
|
|
40
|
+
frontend, autenticándose como una **cuenta de usuario** (JWT). Corre en **tu máquina**, igual que
|
|
41
|
+
`integrations/discord-porrin` y `integrations/porrin-meet`.
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
Agente IA ──stdio──► foundry-boards (este MCP) ──HTTP + JWT──► Foundry API (/api/v1)
|
|
45
|
+
tools de tablero (permisos por rol)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Por qué un MCP (y no llamar al backend a mano)
|
|
49
|
+
Con el MCP conectado, le pides al agente cosas en lenguaje natural y opera el tablero:
|
|
50
|
+
- *"Lista mis tableros y muéstrame las tarjetas del de Marketing."*
|
|
51
|
+
- *"Crea la tarea 'Migrar auth a OAuth' en En progreso, prioridad alta, asígnala a Ana."*
|
|
52
|
+
- *"Mueve todas las tarjetas de En revisión que ya estén aprobadas a Hecho."*
|
|
53
|
+
|
|
54
|
+
Los **permisos los valida el backend por rol**: dueño/colaborador pueden mutar; **observador solo
|
|
55
|
+
lee** (una mutación devuelve 403 y Claude te lo dice).
|
|
56
|
+
|
|
57
|
+
## Requisitos
|
|
58
|
+
- **Python 3.10+** (lo gestiona `uv`; no necesitas python/pip en el PATH).
|
|
59
|
+
- **Un backend con el que hablar.** Por omisión, el Foundry público
|
|
60
|
+
(`https://foundry.collie.digital`): no hace falta levantar nada. Para apuntar a otro —el tuyo en
|
|
61
|
+
local, o uno propio— se dice con `FOUNDRY_API_BASE` (ver *Configuración*).
|
|
62
|
+
- Una **cuenta de Foundry**; para administrar tableros de un Área, esa cuenta debe ser
|
|
63
|
+
**miembro colaborador/dueño** de ese Área. Puede ser tu propia cuenta o una dedicada.
|
|
64
|
+
|
|
65
|
+
## Instalación (con `uv`)
|
|
66
|
+
```powershell
|
|
67
|
+
cd integrations/foundry-mcp
|
|
68
|
+
.\run.ps1 # crea .venv, instala deps y hace un chequeo de humo (no pide credenciales)
|
|
69
|
+
```
|
|
70
|
+
Manual (o en Linux/Mac):
|
|
71
|
+
```bash
|
|
72
|
+
cd integrations/foundry-mcp
|
|
73
|
+
uv sync # crea .venv e instala deps desde pyproject.toml/uv.lock (portable)
|
|
74
|
+
uv run python -m foundry_mcp # (opcional) arranque manual por stdio; normalmente lo lanza Claude Code
|
|
75
|
+
```
|
|
76
|
+
No necesitas `.env`: **no se configuran credenciales**. Como mucho, un `.env` con
|
|
77
|
+
`FOUNDRY_API_BASE` para apuntar a otro backend, `FOUNDRY_AGENT_SOURCE` para corregir la identidad
|
|
78
|
+
de un cliente que no se anuncie bien o `FOUNDRY_AGENT_MODEL` para declarar el modelo usado (tu
|
|
79
|
+
`.env` local **gana** sobre el default del `.mcp.json`).
|
|
80
|
+
|
|
81
|
+
## Identidad del agente en tareas, comentarios e historial
|
|
82
|
+
|
|
83
|
+
Cada descripción, comentario, avance, bloqueo, verificación o cambio de historial creado por el
|
|
84
|
+
MCP conserva la procedencia `ia` y guarda dos datos separados:
|
|
85
|
+
|
|
86
|
+
- `agent_source`: `claude_code`, `codex`, `opencode`, `gemini`, `other` o `unknown`.
|
|
87
|
+
- `agent_model`: nombre abierto del modelo concreto, por ejemplo `gpt-5`, `claude-sonnet-*` o
|
|
88
|
+
`gemini-2.5-pro`.
|
|
89
|
+
|
|
90
|
+
Foundry los muestra como `IA · Codex · gpt-*` junto a la descripción, en cada aporte y en cada
|
|
91
|
+
evento del historial; no hace falta firmar el texto. El MCP adjunta la identidad como cabeceras a
|
|
92
|
+
sus peticiones, de modo que también cubre movimientos, etiquetas, vínculos, sprints y otras
|
|
93
|
+
mutaciones que dejan `ChangeLog`.
|
|
94
|
+
|
|
95
|
+
- `FOUNDRY_AGENT_SOURCE=auto` (recomendado) usa `clientInfo` de la sesión MCP.
|
|
96
|
+
- Si el cliente se identifica con un nombre genérico, fija un override, por ejemplo
|
|
97
|
+
`FOUNDRY_AGENT_SOURCE=codex`.
|
|
98
|
+
- MCP no estandariza el modelo en `clientInfo`: fija `FOUNDRY_AGENT_MODEL` si el proceso usa uno
|
|
99
|
+
estable, o pasa `agent_model` en la herramienta si cambia dentro de la misma sesión. El servidor
|
|
100
|
+
también reconoce, si existen, `CODEX_MODEL`, `CLAUDE_MODEL`, `ANTHROPIC_MODEL`,
|
|
101
|
+
`OPENCODE_MODEL` y `GEMINI_MODEL`.
|
|
102
|
+
- Los clientes antiguos siguen funcionando: sus descripciones y eventos de agente aparecen como
|
|
103
|
+
`IA · Desconocido · Modelo desconocido`.
|
|
104
|
+
- La identidad es **declarada por el cliente o por la configuración local**, no una certificación
|
|
105
|
+
criptográfica. No debe usarse como control de autorización; los permisos siguen dependiendo del
|
|
106
|
+
JWT y del rol de la cuenta.
|
|
107
|
+
|
|
108
|
+
## Autenticación (interactiva — te la pide Claude Code)
|
|
109
|
+
No hay credenciales en archivos ni en variables de entorno. La **primera acción** sobre un tablero
|
|
110
|
+
(o la tool `login`) abre un **diálogo de Claude Code** que te pide **email + contraseña** (o pegar un
|
|
111
|
+
**token**). Con eso el MCP obtiene un JWT y lo usa durante la sesión.
|
|
112
|
+
|
|
113
|
+
- El **token** se cachea en **memoria** para la sesión. Si marcas **"recordar"** en el diálogo, se
|
|
114
|
+
guarda en el **gestor de credenciales del sistema operativo** (Windows Credential Manager / macOS
|
|
115
|
+
Keychain / Secret Service) — **nunca** en `.env`, en un archivo ni en el repo. La **contraseña no
|
|
116
|
+
se guarda en ningún lado**: solo se usa para obtener el token.
|
|
117
|
+
- El token de Foundry dura **24 h** y no hay renovación automática (la contraseña no se guarda).
|
|
118
|
+
Al caducar, el MCP **relee primero el gestor de credenciales**: si otra sesión ya renovó (y
|
|
119
|
+
guardó con "recordar"), lo reutiliza **sin preguntar** — con varias ventanas de Claude Code
|
|
120
|
+
abiertas, solo la primera pide login. Si el guardado también caducó, vuelve el diálogo (una vez
|
|
121
|
+
al día como mucho).
|
|
122
|
+
- `login` inicia sesión por adelantado o cambia de cuenta; `logout` olvida el token (memoria + SO).
|
|
123
|
+
- **Automatización/CI (sin diálogo):** define `FOUNDRY_TOKEN`, o `FOUNDRY_EMAIL` + `FOUNDRY_PASSWORD`
|
|
124
|
+
en el entorno y el MCP se autentica sin preguntar. Es opcional; para uso normal, no lo definas.
|
|
125
|
+
|
|
126
|
+
> Se usa *elicitation* en **modo formulario**. Para un backend local que tú controlas es lo práctico;
|
|
127
|
+
> como solo se persiste el JWT (nunca la contraseña), el riesgo es acotado.
|
|
128
|
+
|
|
129
|
+
## Registrar en Claude Code
|
|
130
|
+
El registro solo necesita **cómo lanzar** el server (sin secretos: la sesión se pide en runtime).
|
|
131
|
+
El repo ya trae un **`.mcp.json` en la raíz** (scope de **proyecto**, compartido con el equipo) que
|
|
132
|
+
lanza el server con `uv run` — **portable** (Windows/Linux/Mac, sin rutas de `.venv`) — y fija el
|
|
133
|
+
backend de prod:
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"mcpServers": {
|
|
138
|
+
"foundry-boards": {
|
|
139
|
+
"type": "stdio",
|
|
140
|
+
"command": "uv",
|
|
141
|
+
"args": ["run", "--directory", "${CLAUDE_PROJECT_DIR:-.}/integrations/foundry-mcp", "python", "run_server.py"],
|
|
142
|
+
"env": {
|
|
143
|
+
"FOUNDRY_API_BASE": "https://foundry.collie.digital/api/v1",
|
|
144
|
+
"FOUNDRY_AGENT_SOURCE": "auto"
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
Si ese proceso usa un modelo fijo, añade
|
|
151
|
+
`"FOUNDRY_AGENT_MODEL": "<modelo-actual>"` dentro de `env`. Si permite cambiar de modelo durante
|
|
152
|
+
la sesión, deja la configuración sin ese valor y usa el argumento `agent_model` de cada aporte,
|
|
153
|
+
creación o edición de tarea.
|
|
154
|
+
Claude Code **pide aprobarlo** la primera vez (`claude mcp reset-project-choices` para reelegir).
|
|
155
|
+
Requiere `uv` en el PATH (el mismo que usa el backend).
|
|
156
|
+
|
|
157
|
+
**Alternativa personal** (sin `.mcp.json`, solo para ti): `claude mcp add-json foundry-boards '<json>'`
|
|
158
|
+
con la misma estructura pero **ruta absoluta** en `--directory` (en `~/.claude.json` no se expande
|
|
159
|
+
`${CLAUDE_PROJECT_DIR}`). Si no vas a tocar el código del MCP, es más simple instalarlo: el
|
|
160
|
+
[`mcp.json.example`](./mcp.json.example) trae esa forma, la de *[Instalarlo sin el
|
|
161
|
+
repo](#instalarlo-sin-el-repo-desde-pypi)*, que no depende de dónde tengas el proyecto.
|
|
162
|
+
|
|
163
|
+
Verifica: `/mcp` debe mostrar `foundry-boards` con sus tools. Prueba *"usa whoami de foundry-boards"*.
|
|
164
|
+
|
|
165
|
+
## Compartir con el equipo (onboarding)
|
|
166
|
+
Todo lo necesario ya vive en el repo (el `.mcp.json` y el código); **no hay secretos que repartir** —
|
|
167
|
+
cada quien entra con **su** cuenta. Cada compañero, **una vez**:
|
|
168
|
+
1. Tener **`uv`** en el PATH y el repo al día (`git pull`).
|
|
169
|
+
2. **Preparar el entorno** para que el primer arranque no expire:
|
|
170
|
+
`cd integrations/foundry-mcp && uv sync` (o `.\run.ps1` en Windows).
|
|
171
|
+
3. Abrir **Claude Code** en la carpeta del repo → **aprobar** el `.mcp.json` cuando lo pregunte.
|
|
172
|
+
4. `/mcp` → `foundry-boards` (74 tools: tablero + notas). La primera acción abre el **diálogo de login**: entra con
|
|
173
|
+
**tu** cuenta (debes ser miembro colaborador/dueño de los espacios que quieras editar).
|
|
174
|
+
|
|
175
|
+
- **Backend:** por defecto prod (fijado en el `.mcp.json`). Para apuntar a otro (p. ej. local), crea
|
|
176
|
+
un `.env` en `integrations/foundry-mcp/` con `FOUNDRY_API_BASE=...` — tu `.env` local **gana** sobre
|
|
177
|
+
el default del `.mcp.json`.
|
|
178
|
+
- **Si ya lo tenías registrado a mano** (scope local/usuario), quítalo para que mande el de proyecto:
|
|
179
|
+
`claude mcp remove foundry-boards -s local`.
|
|
180
|
+
|
|
181
|
+
## Instalarlo sin el repo (desde PyPI)
|
|
182
|
+
Quien **no** tiene el monorepo —ni tiene por qué tenerlo— instala el paquete publicado. Basta con
|
|
183
|
+
`uv` en el PATH: `uvx` lo baja, lo cachea y lo ejecuta sin dejar nada en tu carpeta de trabajo.
|
|
184
|
+
|
|
185
|
+
```powershell
|
|
186
|
+
claude mcp add-json foundry-boards '{ "type":"stdio", "command":"uvx", "args":["foundry-boards-mcp"] }'
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Y ya está: **no hay que configurar ningún backend**, porque por omisión habla con el Foundry
|
|
190
|
+
público (`https://foundry.collie.digital`). Lo demás es igual que para el equipo — la primera
|
|
191
|
+
herramienta abre el **diálogo de login** y entras con **tu** cuenta.
|
|
192
|
+
|
|
193
|
+
> **Aún no publicado.** La primera versión todavía no está en PyPI; hasta entonces, usa la vía
|
|
194
|
+
> desde git de aquí abajo. El nombre ya está decidido: `foundry-mcp` está cogido por un proyecto
|
|
195
|
+
> ajeno, así que el paquete se llama **`foundry-boards-mcp`** y el comando, igual.
|
|
196
|
+
|
|
197
|
+
- Para clavar una versión concreta: `"args": ["foundry-boards-mcp@0.1.0"]`.
|
|
198
|
+
- Para apuntar a otro backend —el tuyo en local, o uno propio—, añade
|
|
199
|
+
`"env": {"FOUNDRY_API_BASE": "http://localhost:8000/api/v1"}`.
|
|
200
|
+
- Necesitas una **cuenta de Foundry**; para editar los tableros de un Área, ser miembro
|
|
201
|
+
colaborador o dueño de ella. No hay nada más que repartir: ni claves, ni tokens.
|
|
202
|
+
|
|
203
|
+
**Desde git, sin esperar a una publicación** (requiere acceso al repositorio, que es privado):
|
|
204
|
+
|
|
205
|
+
```powershell
|
|
206
|
+
claude mcp add-json foundry-boards '{ "type":"stdio", "command":"uvx", "args":["--from","git+https://github.com/gepres/foundry.git#subdirectory=integrations/foundry-mcp","foundry-boards-mcp"] }'
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
- Se registra en tu scope **local/usuario** (ruta git absoluta; `${CLAUDE_PROJECT_DIR}` no aplica
|
|
210
|
+
sin repo).
|
|
211
|
+
- Para fijar rama o etiqueta: `...foundry.git@<tag-o-rama>#subdirectory=integrations/foundry-mcp`
|
|
212
|
+
(sin `@`, usa la rama por defecto = último `main`).
|
|
213
|
+
- La primera vez uv **clona el repo una vez** (en su caché, no en tu workspace) para construir el
|
|
214
|
+
paquete; los arranques siguientes son rápidos.
|
|
215
|
+
|
|
216
|
+
## Herramientas
|
|
217
|
+
**Sesión**
|
|
218
|
+
- `login` — inicia sesión (abre el diálogo de credenciales) o cambia de cuenta.
|
|
219
|
+
- `logout` — olvida el token (memoria + gestor de credenciales del SO).
|
|
220
|
+
|
|
221
|
+
**Lectura**
|
|
222
|
+
- `whoami` — la cuenta con la que actúa el MCP (verifica la sesión).
|
|
223
|
+
- `list_spaces` — Áreas de trabajo visibles.
|
|
224
|
+
- `list_boards(space_id?)` — tableros personales (sin `space_id`) o los de un Área.
|
|
225
|
+
- `list_all_boards` — panorama: personales + los de cada Área.
|
|
226
|
+
- `get_board(initiative_id)` — tablero completo: columnas con sus tarjetas.
|
|
227
|
+
|
|
228
|
+
**Tableros**
|
|
229
|
+
- `list_board_presets()` — las **plantillas de columnas** para el alta: `key`, `label`, `template`
|
|
230
|
+
(`kanban`/`scrum`), `is_default` y las columnas de cada una con su categoría. Léelas antes de
|
|
231
|
+
crear: las claves no se adivinan.
|
|
232
|
+
- `create_board(title, space_id?, preset?, columns?)` — tablero nuevo (personal o de un Área).
|
|
233
|
+
`preset` es la clave de una plantilla; `columns` monta las columnas **a medida**
|
|
234
|
+
(`[{"name": "Ideas", "category": "todo", "color": "#5b9bd5"}, …]`, entre 2 y 10, con al menos una
|
|
235
|
+
`todo` y una `done`). Con columnas a medida manda también el `preset` del que partes: es quien
|
|
236
|
+
fija la plantilla del tablero y, con ella, si hay sprints.
|
|
237
|
+
- `move_board_to_space(initiative_id, space_id)` — comparte un tablero personal con un Área.
|
|
238
|
+
|
|
239
|
+
**Columnas del tablero** (FNV-267; el servidor aplica el tope de 10, los nombres sin repetir y el
|
|
240
|
+
invariante de ≥1 de entrada y ≥1 de cierre)
|
|
241
|
+
- `add_column(initiative_id, name, category="in_progress", color?)` — al final del tablero.
|
|
242
|
+
- `rename_column(initiative_id, column, name)` — el id no cambia: **el historial no se toca**.
|
|
243
|
+
- `set_column_category(initiative_id, column, category)` — `todo` · `in_progress` · `done`; es lo
|
|
244
|
+
que decide dónde entra una tarjeta y qué la da por cerrada.
|
|
245
|
+
- `set_column_color(initiative_id, column, color?)` — `#rrggbb`, o vacío para heredar el de su tipo.
|
|
246
|
+
- `reorder_columns(initiative_id, columns)` — **todas** las columnas en el orden que quedan.
|
|
247
|
+
- `delete_column(initiative_id, column, reassign_to?)` — si tiene tarjetas, `reassign_to` dice a
|
|
248
|
+
dónde se mudan (se avisa antes con cuántas son). Marcada como **destructiva** para el cliente.
|
|
249
|
+
|
|
250
|
+
**Tarjetas (work items)**
|
|
251
|
+
- `create_task(initiative_id, title, column="Backlog", description?, priority?, kind?, assignee?, issue_type?, parent_id?, story_points?)`
|
|
252
|
+
- `move_task(initiative_id, task_id, column, order=0)`
|
|
253
|
+
- `transition_task(initiative_id, task_id, status, order=0)` — mueve por **estado** del workflow
|
|
254
|
+
(la columna destino); deja rastro (status_id/column_id).
|
|
255
|
+
- `edit_task(initiative_id, task_id, title?, description?, priority?, kind?, assignee?)` — **parcial**.
|
|
256
|
+
- `set_task_hierarchy(initiative_id, task_id, issue_type, parent_id?)` — tipo + padre (jerarquía).
|
|
257
|
+
- `set_task_details(initiative_id, task_id, story_points?, start_date?, due_date?, flagged?)` —
|
|
258
|
+
**PATCH**: solo cambia lo que pases, conserva lo demás. Fechas ISO; `""` borra una fecha.
|
|
259
|
+
- `set_task_labels(initiative_id, task_id, labels[])` — etiquetas por **nombre** (crea las que falten).
|
|
260
|
+
- `link_tasks(initiative_id, task_id, target_id, link_type)` — `blocks|is_blocked_by|relates_to`.
|
|
261
|
+
- `get_task_links(initiative_id, task_id)` — vínculos de la tarjeta (id, tipo, la otra tarjeta).
|
|
262
|
+
- `unlink_tasks(initiative_id, task_id, target_id, link_type?)` — quita el/los vínculo(s) hacia esa
|
|
263
|
+
tarjeta (resuelve el id del vínculo solo; sin `link_type` borra todos los que apunten a ella).
|
|
264
|
+
- `link_repo(initiative_id, task_id, url, kind?, title?)` — vincula la tarjeta a un recurso de
|
|
265
|
+
repositorio (`kind`: `repository|branch|pull_request|commit`); ideal para asociar el repo/branch/PR
|
|
266
|
+
donde trabajas (ADR-0016, Opción A).
|
|
267
|
+
- `get_repo_links(initiative_id, task_id)` — recursos de repo de la tarjeta (id, url, kind, title).
|
|
268
|
+
- `unlink_repo(initiative_id, task_id, url)` — quita el vínculo de repo cuya URL coincide.
|
|
269
|
+
- `delete_task(initiative_id, task_id)`
|
|
270
|
+
- `create_tasks_from_seeds(initiative_id, seed_ids)` — Vivero→Tablero (tarjetas propuestas).
|
|
271
|
+
|
|
272
|
+
**Épicas**
|
|
273
|
+
- `create_epic(initiative_id, title, column?, description?, priority?)` — work item raíz.
|
|
274
|
+
- `list_epics(initiative_id)` — tarjetas con `issue_type=epic`.
|
|
275
|
+
|
|
276
|
+
**Sprints (Scrum)**
|
|
277
|
+
- `list_sprints(initiative_id)` — sprints del tablero (state future|active|closed).
|
|
278
|
+
- `create_sprint(initiative_id, name, goal?, start_date?, end_date?)` — sprint planificado.
|
|
279
|
+
- `start_sprint(initiative_id, sprint_id)` — future → active (uno activo por tablero).
|
|
280
|
+
- `complete_sprint(initiative_id, sprint_id)` — active → closed (incompletas vuelven al backlog).
|
|
281
|
+
- `assign_task_to_sprint(initiative_id, task_id, sprint_id?)` — a un sprint, o al backlog si se omite.
|
|
282
|
+
|
|
283
|
+
**Historial de la tarjeta**
|
|
284
|
+
- `add_task_entry(initiative_id, task_id, content, kind="avance", meta=None)` — registra un **aporte
|
|
285
|
+
tipado** (ADR-0017) en el hilo, para que el output quede estructurado, no aplanado en texto.
|
|
286
|
+
`kind`: `avance` · `criterio` · `decision` · `bloqueo` (marca la bandera de impedimento) ·
|
|
287
|
+
`verificacion` · `pregunta` · `nota`. `meta` es JSON libre (p. ej. `{"commit": "abc123"}`). Queda
|
|
288
|
+
como aporte del agente (procedencia `ia`).
|
|
289
|
+
- `add_task_comment(initiative_id, task_id, content)` — deja una **nota** libre (equivale a
|
|
290
|
+
`add_task_entry` con `kind="nota"`). Queda marcada como nota del agente.
|
|
291
|
+
- `get_task_comments(initiative_id, task_id)` — lee el hilo (autor, tipo human|agent, procedencia,
|
|
292
|
+
tipo de aporte, meta, texto y fecha).
|
|
293
|
+
- `get_task_history(initiative_id, task_id)` — historial **estructurado** (ADR-0014, E4): qué campo
|
|
294
|
+
cambió, de qué valor a qué valor, quién y cuándo (created·status·priority·assignee·sprint·label·…).
|
|
295
|
+
|
|
296
|
+
**Datos con gate humano (ADR-0017 F2)** — la IA **propone**, una persona acepta/descarta. El gate es
|
|
297
|
+
**simétrico**: se ve y se completa por los **dos lados** (el tablero y estas tools). Si la sesión de
|
|
298
|
+
Claude se cierra, la decisión se toma en la app; al reabrir, `list_*` te muestra qué se decidió.
|
|
299
|
+
- `propose_criterion(initiative_id, task_id, text)` — propone un **criterio de aceptación** ("para
|
|
300
|
+
darla por hecha debe cumplirse Z"). Nace `proposed` (procedencia `ia`).
|
|
301
|
+
- `record_decision(initiative_id, task_id, title, rationale="", repo_url="")` — registra una
|
|
302
|
+
**decisión** de diseño (ADR-lite). Nace `proposed`. `repo_url` la ata a un commit/PR (ADR-0016)
|
|
303
|
+
para la trazabilidad IA→código.
|
|
304
|
+
- `list_criteria(initiative_id, task_id)` / `list_decisions(initiative_id, task_id)` — **leen** los
|
|
305
|
+
criterios/decisiones con su `status` (`proposed|accepted|rejected`), procedencia y datos del gate.
|
|
306
|
+
Úsalas para confirmar qué se aceptó/descartó (incluso si se decidió desde la app).
|
|
307
|
+
- `review_criterion(initiative_id, task_id, criterion_id, accept)` /
|
|
308
|
+
`review_decision(initiative_id, task_id, decision_id, accept)` — **gate humano** desde Claude:
|
|
309
|
+
`accept=True` lo vuelve oficial, `False` lo descarta. Es la decisión de una persona (igual que el
|
|
310
|
+
botón del tablero): úsalas solo a pedido explícito; **no auto-apruebes** lo que tú propusiste.
|
|
311
|
+
- `review_task_proposal(initiative_id, task_id, accept)` — gate humano de una **tarjeta** propuesta
|
|
312
|
+
por la IA (`status_agent="proposed"`): la acepta (tarjeta oficial) o la rechaza (queda `rejected`,
|
|
313
|
+
oculta pero con traza). Su estado se lee en `get_board`.
|
|
314
|
+
|
|
315
|
+
**Adjuntos**
|
|
316
|
+
- `list_task_attachments(initiative_id, task_id)` — metadatos de los adjuntos de una tarjeta
|
|
317
|
+
(id, filename, content_type, size, quién los subió y cuándo).
|
|
318
|
+
- `read_task_attachment(initiative_id, task_id, attachment_id)` — lee un adjunto: las **imágenes** se
|
|
319
|
+
devuelven como imagen (Claude las **ve**: mockups, capturas, diagramas), el **texto** (text/*, json,
|
|
320
|
+
csv, yaml…) como texto, y otros binarios como metadatos + aviso. Límite 10 MB (backend).
|
|
321
|
+
- `upload_task_attachment(initiative_id, task_id, path? | text? | base64_data?, filename?)` — **sube**
|
|
322
|
+
un archivo: desde una ruta del disco, desde un texto que el agente tiene en la mano o desde bytes
|
|
323
|
+
en base64 (estas dos exigen `filename`, del que sale el tipo de contenido). Una sola de las tres.
|
|
324
|
+
- `delete_task_attachment(initiative_id, task_id, attachment_id)` — **borra** un adjunto.
|
|
325
|
+
Irreversible; devuelve qué se borró (nombre y tamaño) en vez de un OK mudo.
|
|
326
|
+
|
|
327
|
+
**Prompts** (los invoca el usuario desde su cliente, como un comando; FNV-270)
|
|
328
|
+
- `trabajar_tarjeta(initiative_id, task_id)` — el ciclo completo: enterarse, hacer visible el plan,
|
|
329
|
+
construir, dejar avance con su commit, dejar evidencia y entregar. Con lo que no se negocia:
|
|
330
|
+
**«Hecho» lo decide una persona**.
|
|
331
|
+
- `dejar_avance(initiative_id, task_id)` — qué se construyó, qué quedó fuera, el commit y la
|
|
332
|
+
evidencia con números (`parcial` si falta la prueba de fuego).
|
|
333
|
+
- `repasar_tablero(initiative_id)` — qué espera a una persona, qué dice estar hecho sin
|
|
334
|
+
demostrarlo, qué lleva parado. Solo lee: no mueve nada.
|
|
335
|
+
|
|
336
|
+
**Qué declara cada herramienta** (FNV-268): todas dicen si **solo leen** (23), si **crean o
|
|
337
|
+
actualizan** sin destruir (45) o si **borran** (6). El cliente lo usa para saber qué puede aprobar
|
|
338
|
+
solo y dónde pararse — y ojo, lo no declarado se asume destructivo, así que callar no era neutral.
|
|
339
|
+
Las que borran (tarjeta, nota, adjunto, columna) además **preguntan antes**, diciendo qué se pierde
|
|
340
|
+
(FNV-269); si el cliente no sabe preguntar, siguen adelante en vez de bloquearse.
|
|
341
|
+
|
|
342
|
+
**Ergonomía pensada para el agente:**
|
|
343
|
+
- **Columnas/estados por nombre** (tolerante a acentos/mayúsculas) o por id. Cada tablero tiene las
|
|
344
|
+
suyas —siete plantillas o las que haya montado el equipo (FNV-256)—, así que se leen con
|
|
345
|
+
`get_board` y **nunca se suponen**: mira la `category` de cada columna (`todo`/`in_progress`/
|
|
346
|
+
`done`), que es lo único estable. Al crear una tarjeta sin `column`, nace en la primera `todo`.
|
|
347
|
+
- **Responsable por nombre/email**: en tableros de Área resuelve el `assignee` contra los miembros;
|
|
348
|
+
en tableros personales acepta un id. Para quitarlo: `edit_task(..., assignee="")`.
|
|
349
|
+
- `priority` ∈ `highest|high|medium|low|lowest` (también `baja|media|alta`); `kind` ∈
|
|
350
|
+
`tarea|bug|incidencia`; `issue_type` ∈ `epic|historia|tarea|bug|subtarea`.
|
|
351
|
+
|
|
352
|
+
## Límites (a propósito, para no inventar API)
|
|
353
|
+
Este MCP envuelve lo que necesita del backend. **No** hace (aún):
|
|
354
|
+
- crear/renombrar/borrar/reordenar **columnas** y editar el **workflow** (el backend ya lo soporta,
|
|
355
|
+
ADR-0014 E2; el MCP aún no lo envuelve — al crear un tablero toma el preset por defecto);
|
|
356
|
+
- **borrar** un tablero/iniciativa.
|
|
357
|
+
|
|
358
|
+
Si hace falta, se agregan como tools nuevas aquí.
|
|
359
|
+
|
|
360
|
+
## Seguridad
|
|
361
|
+
- Las mutaciones las autoriza el **servidor** por rol; el MCP no elude permisos.
|
|
362
|
+
- **No hay credenciales en archivos ni en variables de entorno** (salvo que actives el override de
|
|
363
|
+
automatización). La sesión se pide en runtime; solo el **token** se cachea (memoria, u opcional
|
|
364
|
+
gestor de credenciales del SO). La **contraseña no se persiste**.
|
|
365
|
+
- Da a la cuenta usada **solo** el acceso que necesite (invítala como colaborador únicamente a los
|
|
366
|
+
espacios que deba administrar).
|
|
367
|
+
|
|
368
|
+
## Solución de problemas
|
|
369
|
+
- **Las tools piden login cada vez** → marca **"recordar"** en el diálogo para guardar el token en el
|
|
370
|
+
gestor de credenciales del SO (si no, la sesión es solo en memoria y se pide en cada arranque).
|
|
371
|
+
- **`/mcp` muestra el server pero las tools fallan** → confirma que el backend esté arriba en
|
|
372
|
+
`FOUNDRY_API_BASE`. Prueba `whoami`; si pide login, complétalo.
|
|
373
|
+
- **403 al mutar** → la cuenta es observador, o no es miembro de ese Área.
|
|
374
|
+
- **404 en un tablero/tarea** → id equivocado, o la cuenta no ve ese tablero.
|
|
375
|
+
- **El server no conecta** → verifica la ruta de `command` (Windows `.venv/Scripts/python.exe` vs
|
|
376
|
+
POSIX `.venv/bin/python`) y que `run.ps1` haya creado el `.venv`.
|
|
377
|
+
- **"Este cliente no puede pedir credenciales…"** → el cliente MCP no soporta *elicitation*; usa el
|
|
378
|
+
override de entorno (`FOUNDRY_TOKEN` o `FOUNDRY_EMAIL`/`FOUNDRY_PASSWORD`).
|