Skip to main content

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 con FOUNDRY_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, other o unknown.
  • agent_model: nombre abierto del modelo concreto, por ejemplo gpt-5, claude-sonnet-* o gemini-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) usa clientInfo de 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: fija FOUNDRY_AGENT_MODEL si el proceso usa uno estable, o pasa agent_model en la herramienta si cambia dentro de la misma sesión. El servidor también reconoce, si existen, CODEX_MODEL, CLAUDE_MODEL, ANTHROPIC_MODEL, OPENCODE_MODEL y GEMINI_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).
  • login inicia sesión por adelantado o cambia de cuenta; logout olvida el token (memoria + SO).
  • Automatización/CI (sin diálogo): define FOUNDRY_TOKEN, o FOUNDRY_EMAIL + FOUNDRY_PASSWORD en 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 runportable (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:

  1. Tener uv en el PATH y el repo al día (git pull).
  2. Preparar el entorno para que el primer arranque no expire: cd integrations/foundry-mcp && uv sync (o .\run.ps1 en Windows).
  3. Abrir Claude Code en la carpeta del repo → aprobar el .mcp.json cuando lo pregunte.
  4. /mcpfoundry-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 .env en integrations/foundry-mcp/ con FOUNDRY_API_BASE=... — tu .env local 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-mcp está cogido por un proyecto ajeno, así que el paquete se llama foundry-boards-mcp y 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 = último main).
  • 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 (sin space_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_default y 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). preset es la clave de una plantilla; columns monta las columnas a medida ([{"name": "Ideas", "category": "todo", "color": "#5b9bd5"}, …], entre 2 y 10, con al menos una todo y una done). Con columnas a medida manda también el preset del 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_to dice 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; sin link_type borra 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 con issue_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. meta es JSON libre (p. ej. {"commit": "abc123"}). Queda como aporte del agente (procedencia ia).
  • add_task_comment(initiative_id, task_id, content) — deja una nota libre (equivale a add_task_entry con kind="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"). Nace proposed (procedencia ia).
  • record_decision(initiative_id, task_id, title, rationale="", repo_url="") — registra una decisión de diseño (ADR-lite). Nace proposed. repo_url la 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 su status (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=True lo vuelve oficial, False lo 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 (queda rejected, oculta pero con traza). Su estado se lee en get_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 exigen filename, 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 (parcial si 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_board y nunca se suponen: mira la category de cada columna (todo/in_progress/ done), que es lo único estable. Al crear una tarjeta sin column, nace en la primera todo.
  • Responsable por nombre/email: en tableros de Área resuelve el assignee contra los miembros; en tableros personales acepta un id. Para quitarlo: edit_task(..., assignee="").
  • priorityhighest|high|medium|low|lowest (también baja|media|alta); kindtarea|bug|incidencia; issue_typeepic|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).
  • /mcp muestra el server pero las tools fallan → confirma que el backend esté arriba en FOUNDRY_API_BASE. Prueba whoami; 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.exe vs POSIX .venv/bin/python) y que run.ps1 haya creado el .venv.
  • "Este cliente no puede pedir credenciales…" → el cliente MCP no soporta elicitation; usa el override de entorno (FOUNDRY_TOKEN o FOUNDRY_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

foundry_boards_mcp-0.1.0.tar.gz (122.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

foundry_boards_mcp-0.1.0-py3-none-any.whl (49.7 kB view details)

Uploaded Python 3

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

Hashes for foundry_boards_mcp-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c4f4f9a9a403601488ffd5e0dec92a0b1717608c0f459b94580b721ba2495a26
MD5 cd8579e82613663e3007cfe7be9a1e63
BLAKE2b-256 156835ddca56274ab5ee97eb9bd4188053246b0d711ec66fb66f79978b5c40e4

See more details on using hashes here.

Provenance

The following attestation bundles were made for foundry_boards_mcp-0.1.0.tar.gz:

Publisher: publish-mcp.yml on gepres/foundry

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file foundry_boards_mcp-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for foundry_boards_mcp-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4831cd6ded25bf83274164c3f82c8766e0f4baf2fd4f40d2c70688c806a446ed
MD5 dd27f4527bbacf1098d63ddcf1ba81c5
BLAKE2b-256 37e7fc9a9fb377a9332bff6518fc3d67be21405b8ea5a09c8536cdda2a6ae981

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page