Foundry Boards — MCP para agentes de IA
Servidor MCP (Model Context Protocol) que le da a Claude Code, Codex, OpenCode, Gemini y otros clientes compatibles herramientas para administrar los tableros de Foundry con un modelo de gestión de trabajo ágil (ADR-0014): listar/crear tableros, crear/mover/editar tarjetas (work items), transicionar por estados, gestionar jerarquía (épicas/historias/subtareas), etiquetas, vínculos, sprints (Scrum), leer el historial estructurado y gestionar adjuntos (leer imágenes, subir y borrar) — además de mover un tablero personal a un Área.
No forma parte del backend ni lo modifica: habla el mismo contrato REST público que el
frontend, autenticándose como una cuenta de usuario (JWT). Corre en tu máquina, igual que
integrations/discord-porrin y integrations/porrin-meet.
Agente IA ──stdio──► foundry-boards (este MCP) ──HTTP + JWT──► Foundry API (/api/v1)
tools de tablero (permisos por rol)
Por qué un MCP (y no llamar al backend a mano)
Con el MCP conectado, le pides al agente cosas en lenguaje natural y opera el tablero:
- "Lista mis tableros y muéstrame las tarjetas del de Marketing."
- "Crea la tarea 'Migrar auth a OAuth' en En progreso, prioridad alta, asígnala a Ana."
- "Mueve todas las tarjetas de En revisión que ya estén aprobadas a Hecho."
Los permisos los valida el backend por rol: dueño/colaborador pueden mutar; observador solo lee (una mutación devuelve 403 y Claude te lo dice).
Requisitos
- Python 3.10+ (lo gestiona
uv; no necesitas python/pip en el PATH). - Un backend con el que hablar. Por omisión, el Foundry público
(
https://foundry.collie.digital): no hace falta levantar nada. Para apuntar a otro —el tuyo en local, o uno propio— se dice conFOUNDRY_API_BASE(ver Configuración). - Una cuenta de Foundry; para administrar tableros de un Área, esa cuenta debe ser miembro colaborador/dueño de ese Área. Puede ser tu propia cuenta o una dedicada.
Instalación (con uv)
cd integrations/foundry-mcp
.\run.ps1 # crea .venv, instala deps y hace un chequeo de humo (no pide credenciales)
Manual (o en Linux/Mac):
cd integrations/foundry-mcp
uv sync # crea .venv e instala deps desde pyproject.toml/uv.lock (portable)
uv run python -m foundry_mcp # (opcional) arranque manual por stdio; normalmente lo lanza Claude Code
No necesitas .env: no se configuran credenciales. Como mucho, un .env con
FOUNDRY_API_BASE para apuntar a otro backend, FOUNDRY_AGENT_SOURCE para corregir la identidad
de un cliente que no se anuncie bien o FOUNDRY_AGENT_MODEL para declarar el modelo usado (tu
.env local gana sobre el default del .mcp.json).
Identidad del agente en tareas, comentarios e historial
Cada descripción, comentario, avance, bloqueo, verificación o cambio de historial creado por el
MCP conserva la procedencia ia y guarda dos datos separados:
agent_source:claude_code,codex,opencode,gemini,otherounknown.agent_model: nombre abierto del modelo concreto, por ejemplogpt-5,claude-sonnet-*ogemini-2.5-pro.
Foundry los muestra como IA · Codex · gpt-* junto a la descripción, en cada aporte y en cada
evento del historial; no hace falta firmar el texto. El MCP adjunta la identidad como cabeceras a
sus peticiones, de modo que también cubre movimientos, etiquetas, vínculos, sprints y otras
mutaciones que dejan ChangeLog.
FOUNDRY_AGENT_SOURCE=auto(recomendado) usaclientInfode la sesión MCP.- Si el cliente se identifica con un nombre genérico, fija un override, por ejemplo
FOUNDRY_AGENT_SOURCE=codex. - MCP no estandariza el modelo en
clientInfo: fijaFOUNDRY_AGENT_MODELsi el proceso usa uno estable, o pasaagent_modelen la herramienta si cambia dentro de la misma sesión. El servidor también reconoce, si existen,CODEX_MODEL,CLAUDE_MODEL,ANTHROPIC_MODEL,OPENCODE_MODELyGEMINI_MODEL. - Los clientes antiguos siguen funcionando: sus descripciones y eventos de agente aparecen como
IA · Desconocido · Modelo desconocido. - La identidad es declarada por el cliente o por la configuración local, no una certificación criptográfica. No debe usarse como control de autorización; los permisos siguen dependiendo del JWT y del rol de la cuenta.
Autenticación (interactiva — te la pide Claude Code)
No hay credenciales en archivos ni en variables de entorno. La primera acción sobre un tablero
(o la tool login) abre un diálogo de Claude Code que te pide email + contraseña (o pegar un
token). Con eso el MCP obtiene un JWT y lo usa durante la sesión.
- El token se cachea en memoria para la sesión. Si marcas "recordar" en el diálogo, se
guarda en el gestor de credenciales del sistema operativo (Windows Credential Manager / macOS
Keychain / Secret Service) — nunca en
.env, en un archivo ni en el repo. La contraseña no se guarda en ningún lado: solo se usa para obtener el token. - El token de Foundry dura 24 h y no hay renovación automática (la contraseña no se guarda). Al caducar, el MCP relee primero el gestor de credenciales: si otra sesión ya renovó (y guardó con "recordar"), lo reutiliza sin preguntar — con varias ventanas de Claude Code abiertas, solo la primera pide login. Si el guardado también caducó, vuelve el diálogo (una vez al día como mucho).
logininicia sesión por adelantado o cambia de cuenta;logoutolvida el token (memoria + SO).- Automatización/CI (sin diálogo): define
FOUNDRY_TOKEN, oFOUNDRY_EMAIL+FOUNDRY_PASSWORDen el entorno y el MCP se autentica sin preguntar. Es opcional; para uso normal, no lo definas.
Se usa elicitation en modo formulario. Para un backend local que tú controlas es lo práctico; como solo se persiste el JWT (nunca la contraseña), el riesgo es acotado.
Registrar en Claude Code
El registro solo necesita cómo lanzar el server (sin secretos: la sesión se pide en runtime).
El repo ya trae un .mcp.json en la raíz (scope de proyecto, compartido con el equipo) que
lanza el server con uv run — portable (Windows/Linux/Mac, sin rutas de .venv) — y fija el
backend de prod:
{
"mcpServers": {
"foundry-boards": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory", "${CLAUDE_PROJECT_DIR:-.}/integrations/foundry-mcp", "python", "run_server.py"],
"env": {
"FOUNDRY_API_BASE": "https://foundry.collie.digital/api/v1",
"FOUNDRY_AGENT_SOURCE": "auto"
}
}
}
}
Si ese proceso usa un modelo fijo, añade
"FOUNDRY_AGENT_MODEL": "<modelo-actual>" dentro de env. Si permite cambiar de modelo durante
la sesión, deja la configuración sin ese valor y usa el argumento agent_model de cada aporte,
creación o edición de tarea.
Claude Code pide aprobarlo la primera vez (claude mcp reset-project-choices para reelegir).
Requiere uv en el PATH (el mismo que usa el backend).
Alternativa personal (sin .mcp.json, solo para ti): claude mcp add-json foundry-boards '<json>'
con la misma estructura pero ruta absoluta en --directory (en ~/.claude.json no se expande
${CLAUDE_PROJECT_DIR}). Si no vas a tocar el código del MCP, es más simple instalarlo: el
mcp.json.example trae esa forma, la de Instalarlo sin el
repo, que no depende de dónde tengas el proyecto.
Verifica: /mcp debe mostrar foundry-boards con sus tools. Prueba "usa whoami de foundry-boards".
Compartir con el equipo (onboarding)
Todo lo necesario ya vive en el repo (el .mcp.json y el código); no hay secretos que repartir —
cada quien entra con su cuenta. Cada compañero, una vez:
- Tener
uven el PATH y el repo al día (git pull). - Preparar el entorno para que el primer arranque no expire:
cd integrations/foundry-mcp && uv sync(o.\run.ps1en Windows). - Abrir Claude Code en la carpeta del repo → aprobar el
.mcp.jsoncuando lo pregunte. /mcp→foundry-boards(74 tools: tablero + notas). La primera acción abre el diálogo de login: entra con tu cuenta (debes ser miembro colaborador/dueño de los espacios que quieras editar).
- Backend: por defecto prod (fijado en el
.mcp.json). Para apuntar a otro (p. ej. local), crea un.envenintegrations/foundry-mcp/conFOUNDRY_API_BASE=...— tu.envlocal gana sobre el default del.mcp.json. - Si ya lo tenías registrado a mano (scope local/usuario), quítalo para que mande el de proyecto:
claude mcp remove foundry-boards -s local.
Instalarlo sin el repo (desde PyPI)
Quien no tiene el monorepo —ni tiene por qué tenerlo— instala el paquete publicado. Basta con
uv en el PATH: uvx lo baja, lo cachea y lo ejecuta sin dejar nada en tu carpeta de trabajo.
claude mcp add-json foundry-boards '{ "type":"stdio", "command":"uvx", "args":["foundry-boards-mcp"] }'
Y ya está: no hay que configurar ningún backend, porque por omisión habla con el Foundry
público (https://foundry.collie.digital). Lo demás es igual que para el equipo — la primera
herramienta abre el diálogo de login y entras con tu cuenta.
Aún no publicado. La primera versión todavía no está en PyPI; hasta entonces, usa la vía desde git de aquí abajo. El nombre ya está decidido:
foundry-mcpestá cogido por un proyecto ajeno, así que el paquete se llamafoundry-boards-mcpy el comando, igual.
- Para clavar una versión concreta:
"args": ["foundry-boards-mcp@0.1.0"]. - Para apuntar a otro backend —el tuyo en local, o uno propio—, añade
"env": {"FOUNDRY_API_BASE": "http://localhost:8000/api/v1"}. - Necesitas una cuenta de Foundry; para editar los tableros de un Área, ser miembro colaborador o dueño de ella. No hay nada más que repartir: ni claves, ni tokens.
Desde git, sin esperar a una publicación (requiere acceso al repositorio, que es privado):
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"] }'
- Se registra en tu scope local/usuario (ruta git absoluta;
${CLAUDE_PROJECT_DIR}no aplica sin repo). - Para fijar rama o etiqueta:
...foundry.git@<tag-o-rama>#subdirectory=integrations/foundry-mcp(sin@, usa la rama por defecto = últimomain). - La primera vez uv clona el repo una vez (en su caché, no en tu workspace) para construir el paquete; los arranques siguientes son rápidos.
Herramientas
Sesión
login— inicia sesión (abre el diálogo de credenciales) o cambia de cuenta.logout— olvida el token (memoria + gestor de credenciales del SO).
Lectura
whoami— la cuenta con la que actúa el MCP (verifica la sesión).list_spaces— Áreas de trabajo visibles.list_boards(space_id?)— tableros personales (sinspace_id) o los de un Área.list_all_boards— panorama: personales + los de cada Área.get_board(initiative_id)— tablero completo: columnas con sus tarjetas.
Tableros
list_board_presets()— las plantillas de columnas para el alta:key,label,template(kanban/scrum),is_defaulty las columnas de cada una con su categoría. Léelas antes de crear: las claves no se adivinan.create_board(title, space_id?, preset?, columns?)— tablero nuevo (personal o de un Área).presetes la clave de una plantilla;columnsmonta las columnas a medida ([{"name": "Ideas", "category": "todo", "color": "#5b9bd5"}, …], entre 2 y 10, con al menos unatodoy unadone). Con columnas a medida manda también elpresetdel que partes: es quien fija la plantilla del tablero y, con ella, si hay sprints.move_board_to_space(initiative_id, space_id)— comparte un tablero personal con un Área.
Columnas del tablero (FNV-267; el servidor aplica el tope de 10, los nombres sin repetir y el invariante de ≥1 de entrada y ≥1 de cierre)
add_column(initiative_id, name, category="in_progress", color?)— al final del tablero.rename_column(initiative_id, column, name)— el id no cambia: el historial no se toca.set_column_category(initiative_id, column, category)—todo·in_progress·done; es lo que decide dónde entra una tarjeta y qué la da por cerrada.set_column_color(initiative_id, column, color?)—#rrggbb, o vacío para heredar el de su tipo.reorder_columns(initiative_id, columns)— todas las columnas en el orden que quedan.delete_column(initiative_id, column, reassign_to?)— si tiene tarjetas,reassign_todice a dónde se mudan (se avisa antes con cuántas son). Marcada como destructiva para el cliente.
Tarjetas (work items)
create_task(initiative_id, title, column="Backlog", description?, priority?, kind?, assignee?, issue_type?, parent_id?, story_points?)move_task(initiative_id, task_id, column, order=0)transition_task(initiative_id, task_id, status, order=0)— mueve por estado del workflow (la columna destino); deja rastro (status_id/column_id).edit_task(initiative_id, task_id, title?, description?, priority?, kind?, assignee?)— parcial.set_task_hierarchy(initiative_id, task_id, issue_type, parent_id?)— tipo + padre (jerarquía).set_task_details(initiative_id, task_id, story_points?, start_date?, due_date?, flagged?)— PATCH: solo cambia lo que pases, conserva lo demás. Fechas ISO;""borra una fecha.set_task_labels(initiative_id, task_id, labels[])— etiquetas por nombre (crea las que falten).link_tasks(initiative_id, task_id, target_id, link_type)—blocks|is_blocked_by|relates_to.get_task_links(initiative_id, task_id)— vínculos de la tarjeta (id, tipo, la otra tarjeta).unlink_tasks(initiative_id, task_id, target_id, link_type?)— quita el/los vínculo(s) hacia esa tarjeta (resuelve el id del vínculo solo; sinlink_typeborra todos los que apunten a ella).link_repo(initiative_id, task_id, url, kind?, title?)— vincula la tarjeta a un recurso de repositorio (kind:repository|branch|pull_request|commit); ideal para asociar el repo/branch/PR donde trabajas (ADR-0016, Opción A).get_repo_links(initiative_id, task_id)— recursos de repo de la tarjeta (id, url, kind, title).unlink_repo(initiative_id, task_id, url)— quita el vínculo de repo cuya URL coincide.delete_task(initiative_id, task_id)create_tasks_from_seeds(initiative_id, seed_ids)— Vivero→Tablero (tarjetas propuestas).
Épicas
create_epic(initiative_id, title, column?, description?, priority?)— work item raíz.list_epics(initiative_id)— tarjetas conissue_type=epic.
Sprints (Scrum)
list_sprints(initiative_id)— sprints del tablero (state future|active|closed).create_sprint(initiative_id, name, goal?, start_date?, end_date?)— sprint planificado.start_sprint(initiative_id, sprint_id)— future → active (uno activo por tablero).complete_sprint(initiative_id, sprint_id)— active → closed (incompletas vuelven al backlog).assign_task_to_sprint(initiative_id, task_id, sprint_id?)— a un sprint, o al backlog si se omite.
Historial de la tarjeta
add_task_entry(initiative_id, task_id, content, kind="avance", meta=None)— registra un aporte tipado (ADR-0017) en el hilo, para que el output quede estructurado, no aplanado en texto.kind:avance·criterio·decision·bloqueo(marca la bandera de impedimento) ·verificacion·pregunta·nota.metaes JSON libre (p. ej.{"commit": "abc123"}). Queda como aporte del agente (procedenciaia).add_task_comment(initiative_id, task_id, content)— deja una nota libre (equivale aadd_task_entryconkind="nota"). Queda marcada como nota del agente.get_task_comments(initiative_id, task_id)— lee el hilo (autor, tipo human|agent, procedencia, tipo de aporte, meta, texto y fecha).get_task_history(initiative_id, task_id)— historial estructurado (ADR-0014, E4): qué campo cambió, de qué valor a qué valor, quién y cuándo (created·status·priority·assignee·sprint·label·…).
Datos con gate humano (ADR-0017 F2) — la IA propone, una persona acepta/descarta. El gate es
simétrico: se ve y se completa por los dos lados (el tablero y estas tools). Si la sesión de
Claude se cierra, la decisión se toma en la app; al reabrir, list_* te muestra qué se decidió.
propose_criterion(initiative_id, task_id, text)— propone un criterio de aceptación ("para darla por hecha debe cumplirse Z"). Naceproposed(procedenciaia).record_decision(initiative_id, task_id, title, rationale="", repo_url="")— registra una decisión de diseño (ADR-lite). Naceproposed.repo_urlla ata a un commit/PR (ADR-0016) para la trazabilidad IA→código.list_criteria(initiative_id, task_id)/list_decisions(initiative_id, task_id)— leen los criterios/decisiones con sustatus(proposed|accepted|rejected), procedencia y datos del gate. Úsalas para confirmar qué se aceptó/descartó (incluso si se decidió desde la app).review_criterion(initiative_id, task_id, criterion_id, accept)/review_decision(initiative_id, task_id, decision_id, accept)— gate humano desde Claude:accept=Truelo vuelve oficial,Falselo descarta. Es la decisión de una persona (igual que el botón del tablero): úsalas solo a pedido explícito; no auto-apruebes lo que tú propusiste.review_task_proposal(initiative_id, task_id, accept)— gate humano de una tarjeta propuesta por la IA (status_agent="proposed"): la acepta (tarjeta oficial) o la rechaza (quedarejected, oculta pero con traza). Su estado se lee enget_board.
Adjuntos
list_task_attachments(initiative_id, task_id)— metadatos de los adjuntos de una tarjeta (id, filename, content_type, size, quién los subió y cuándo).read_task_attachment(initiative_id, task_id, attachment_id)— lee un adjunto: las imágenes se devuelven como imagen (Claude las ve: mockups, capturas, diagramas), el texto (text/*, json, csv, yaml…) como texto, y otros binarios como metadatos + aviso. Límite 10 MB (backend).upload_task_attachment(initiative_id, task_id, path? | text? | base64_data?, filename?)— sube un archivo: desde una ruta del disco, desde un texto que el agente tiene en la mano o desde bytes en base64 (estas dos exigenfilename, del que sale el tipo de contenido). Una sola de las tres.delete_task_attachment(initiative_id, task_id, attachment_id)— borra un adjunto. Irreversible; devuelve qué se borró (nombre y tamaño) en vez de un OK mudo.
Prompts (los invoca el usuario desde su cliente, como un comando; FNV-270)
trabajar_tarjeta(initiative_id, task_id)— el ciclo completo: enterarse, hacer visible el plan, construir, dejar avance con su commit, dejar evidencia y entregar. Con lo que no se negocia: «Hecho» lo decide una persona.dejar_avance(initiative_id, task_id)— qué se construyó, qué quedó fuera, el commit y la evidencia con números (parcialsi falta la prueba de fuego).repasar_tablero(initiative_id)— qué espera a una persona, qué dice estar hecho sin demostrarlo, qué lleva parado. Solo lee: no mueve nada.
Qué declara cada herramienta (FNV-268): todas dicen si solo leen (23), si crean o actualizan sin destruir (45) o si borran (6). El cliente lo usa para saber qué puede aprobar solo y dónde pararse — y ojo, lo no declarado se asume destructivo, así que callar no era neutral. Las que borran (tarjeta, nota, adjunto, columna) además preguntan antes, diciendo qué se pierde (FNV-269); si el cliente no sabe preguntar, siguen adelante en vez de bloquearse.
Ergonomía pensada para el agente:
- Columnas/estados por nombre (tolerante a acentos/mayúsculas) o por id. Cada tablero tiene las
suyas —siete plantillas o las que haya montado el equipo (FNV-256)—, así que se leen con
get_boardy nunca se suponen: mira lacategoryde cada columna (todo/in_progress/done), que es lo único estable. Al crear una tarjeta sincolumn, nace en la primeratodo. - Responsable por nombre/email: en tableros de Área resuelve el
assigneecontra los miembros; en tableros personales acepta un id. Para quitarlo:edit_task(..., assignee=""). priority∈highest|high|medium|low|lowest(tambiénbaja|media|alta);kind∈tarea|bug|incidencia;issue_type∈epic|historia|tarea|bug|subtarea.
Límites (a propósito, para no inventar API)
Este MCP envuelve lo que necesita del backend. No hace (aún):
- crear/renombrar/borrar/reordenar columnas y editar el workflow (el backend ya lo soporta, ADR-0014 E2; el MCP aún no lo envuelve — al crear un tablero toma el preset por defecto);
- borrar un tablero/iniciativa.
Si hace falta, se agregan como tools nuevas aquí.
Seguridad
- Las mutaciones las autoriza el servidor por rol; el MCP no elude permisos.
- No hay credenciales en archivos ni en variables de entorno (salvo que actives el override de automatización). La sesión se pide en runtime; solo el token se cachea (memoria, u opcional gestor de credenciales del SO). La contraseña no se persiste.
- Da a la cuenta usada solo el acceso que necesite (invítala como colaborador únicamente a los espacios que deba administrar).
Solución de problemas
- Las tools piden login cada vez → marca "recordar" en el diálogo para guardar el token en el gestor de credenciales del SO (si no, la sesión es solo en memoria y se pide en cada arranque).
/mcpmuestra el server pero las tools fallan → confirma que el backend esté arriba enFOUNDRY_API_BASE. Pruebawhoami; si pide login, complétalo.- 403 al mutar → la cuenta es observador, o no es miembro de ese Área.
- 404 en un tablero/tarea → id equivocado, o la cuenta no ve ese tablero.
- El server no conecta → verifica la ruta de
command(Windows.venv/Scripts/python.exevs POSIX.venv/bin/python) y querun.ps1haya creado el.venv. - "Este cliente no puede pedir credenciales…" → el cliente MCP no soporta elicitation; usa el
override de entorno (
FOUNDRY_TOKENoFOUNDRY_EMAIL/FOUNDRY_PASSWORD).
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file foundry_boards_mcp-0.1.0.tar.gz.
File metadata
- Download URL: foundry_boards_mcp-0.1.0.tar.gz
- Upload date:
- Size: 122.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4f4f9a9a403601488ffd5e0dec92a0b1717608c0f459b94580b721ba2495a26
|
|
| MD5 |
cd8579e82613663e3007cfe7be9a1e63
|
|
| BLAKE2b-256 |
156835ddca56274ab5ee97eb9bd4188053246b0d711ec66fb66f79978b5c40e4
|
Provenance
The following attestation bundles were made for foundry_boards_mcp-0.1.0.tar.gz:
Publisher:
publish-mcp.yml on gepres/foundry
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
foundry_boards_mcp-0.1.0.tar.gz -
Subject digest:
c4f4f9a9a403601488ffd5e0dec92a0b1717608c0f459b94580b721ba2495a26 - Sigstore transparency entry: 2484646960
- Sigstore integration time:
-
Permalink:
gepres/foundry@70a122796a10b597e47793ea4ae7d42d3afbac80 -
Branch / Tag:
refs/tags/foundry-boards-mcp-v0.1.0 - Owner: https://github.com/gepres
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-mcp.yml@70a122796a10b597e47793ea4ae7d42d3afbac80 -
Trigger Event:
push
-
Statement type:
File details
Details for the file foundry_boards_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: foundry_boards_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 49.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4831cd6ded25bf83274164c3f82c8766e0f4baf2fd4f40d2c70688c806a446ed
|
|
| MD5 |
dd27f4527bbacf1098d63ddcf1ba81c5
|
|
| BLAKE2b-256 |
37e7fc9a9fb377a9332bff6518fc3d67be21405b8ea5a09c8536cdda2a6ae981
|
Provenance
The following attestation bundles were made for foundry_boards_mcp-0.1.0-py3-none-any.whl:
Publisher:
publish-mcp.yml on gepres/foundry
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
foundry_boards_mcp-0.1.0-py3-none-any.whl -
Subject digest:
4831cd6ded25bf83274164c3f82c8766e0f4baf2fd4f40d2c70688c806a446ed - Sigstore transparency entry: 2484647085
- Sigstore integration time:
-
Permalink:
gepres/foundry@70a122796a10b597e47793ea4ae7d42d3afbac80 -
Branch / Tag:
refs/tags/foundry-boards-mcp-v0.1.0 - Owner: https://github.com/gepres
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-mcp.yml@70a122796a10b597e47793ea4ae7d42d3afbac80 -
Trigger Event:
push
-
Statement type: