Skip to main content
Glama

bitacora-mcp

MCP server en NestJS para crear, versionar, recuperar y publicar presentaciones HTML dirigidas a directivos y PO de Bidcom. Los decks se persisten versionados y se publican en Google Workspace vía Google Apps Script, con una URL estable, editable y con historial.

Qué hace

  • 18 tools para crear, editar, versionar, buscar, comparar, validar y publicar presentaciones HTML (ver tabla completa más abajo).

  • Dos backends de store, switch via env vars:

    • git (default): filesystem local, single-user — ideal para desarrollo

    • mongodb: multi-user, AWS-ready — para deployment centralizado

  • OAuth de Google Workspace restringido a bidcom.com.ar (login real, no texto libre). Sesiones persistidas en SQLite o MongoDB.

  • Publicación en Apps Script con idempotencia por commit + access, reintentos con backoff exponencial, y historial completo de publicaciones.

  • Validación pre-deploy que unifica chequeos de sandbox + estructura HTML.

Related MCP server: marp-agent-mcp

Prerequisitos

  • Node 22 (usa --env-file nativo, sin dependencia de dotenv)

  • MongoDB 7+ (solo si vas a usar DECK_STORE=mongodb o OAUTH_STORE=mongodb)

  • Docker (para levantar MongoDB local fácilmente)

Setup inicial

git clone <repo> bitacora-mcp
cd bitacora-mcp
npm install
npm run build

Configuración

Copiá el template de environment y llená los valores:

cp .env.example .env

Editá .env con los valores correspondientes (el archivo está en .gitignore, no se commitea). Los campos obligatorios dependen del modo de uso:

Modo stdio (local, sin login de Google)

Para usar desde Claude Desktop local sin login de Google, no hace falta .env ni credenciales. Las tools corren con owner libre (texto):

npm start          # levanta el server por stdio

Modo HTTP (con login de Google Workspace)

Requiere credenciales de OAuth en GCP (ver más abajo). Llená en .env:

GOOGLE_WORKSPACE_CLIENT_ID=<client-id>
GOOGLE_WORKSPACE_CLIENT_SECRET=<client-secret>
JWT_SECRET=<openssl rand -hex 32>
npm run start:http # levanta el server por HTTP en http://localhost:3030

Store: git (default) o MongoDB

# Para usar MongoDB (multi-user, AWS-ready):
DECK_STORE=mongodb
OAUTH_STORE=mongodb
MONGODB_URI=mongodb://localhost:27017/bitacora

Si no seteás estas vars, el server usa git + SQLite (filesystem local).

Credenciales de Google (setup una sola vez)

Hay dos OAuth clients distintos en el mismo proyecto GCP:

1. OAuth client "Desktop app" — para deployar en Apps Script

  1. Google Cloud Console → proyecto (nuevo o existente)

  2. Habilitar Google Apps Script API (APIs & Services → Library)

  3. Credentials → Create Credentials → OAuth client ID → Desktop app

  4. Descargar JSON → ~/.bitacora-google/oauth-client.json

  5. Correr el consent flow:

    npm run build
    npm run google:authorize

    Abre el navegador, pedí consent, cachea el refresh token en ~/.bitacora-google/token.json. Se refresca solo.

2. OAuth client "Web application" — para login de usuarios (modo HTTP)

  1. En el mismo proyecto GCP → Credentials → Create Credentials → OAuth client ID

  2. Tipo: Web application (no Desktop app — ese no tiene redirect URIs editables)

  3. Authorized redirect URIs: http://localhost:3030/auth/callback

  4. Anotá Client ID y Client Secret → van en .env:

    GOOGLE_WORKSPACE_CLIENT_ID=<este>
    GOOGLE_WORKSPACE_CLIENT_SECRET=<este>

Levantar MongoDB local (para modo MongoDB)

docker run -d --name bitacora-mongo -p 27017:27017 mongo:7

MongoDB queda en mongodb://localhost:27017. Seteá en .env:

DECK_STORE=mongodb
OAUTH_STORE=mongodb
MONGODB_URI=mongodb://localhost:27017/bitacora

Pruebas locales

Smoke test (sin credenciales de Google)

Corre las 18 tools end-to-end contra un cliente de Apps Script mockeado:

# Modo git (default)
npm run smoke

# Modo MongoDB
DECK_STORE=mongodb MONGODB_URI=mongodb://localhost:27017/bitacora-smoke npm run smoke

Los 48 tests cubren: create → update → rollback → deploy → unpublish → list_deployments, diff, search, archive, validate, fragment update, y cargas chunked/from-file.

Probar con MCP Inspector

  1. Levantá el server HTTP:

    npm run build
    npm run start:http
  2. En otra terminal, abrí el Inspector:

    npx @modelcontextprotocol/inspector
  3. En el Inspector: Add Server → Streamable HTTP → URL: http://localhost:3030/mcp

  4. Al llamar una tool, se abre el navegador para login de Google Workspace. Logueate con tu cuenta @bidcom.com.ar.

  5. Las tools van a usar tu email real como owner automáticamente.

Probar con Claude Desktop

  1. Configurá claude_desktop_config.json (en ~/Library/Application Support/Claude/ en macOS):

    {
      "mcpServers": {
        "bitacora-remote": {
          "url": "http://localhost:3030/mcp"
        }
      }
    }
  2. Reiniciá Claude Desktop (Cmd+Q y volver a abrir).

  3. Pedile a Claude: "Mostrame las presentaciones que tengo" — debería disparar el flujo OAuth la primera vez y listar tus decks.

Sesión persistente: si ya te logueaste desde el Inspector, Claude Desktop reusa esa sesión (SQLite/MongoDB la persiste). Para forzar el flujo OAuth desde cero, borrá el store de sesiones: rm ~/.bitacora-store/oauth.db (SQLite) o limpiá las colecciones oauth_* en MongoDB.

Conectar a Claude Desktop (modo stdio, sin login)

Para uso local sin login de Google, stdio es más simple:

{
  "mcpServers": {
    "bitacora": {
      "command": "node",
      "args": ["/RUTA/ABSOLUTA/bitacora-mcp/dist/main.js"],
      "env": {
        "DECK_STORE_DIR": "/RUTA/ABSOLUTA/deck-store",
        "DECK_STORE": "git"
      }
    }
  }
}

O con MongoDB:

{
  "mcpServers": {
    "bitacora": {
      "command": "node",
      "args": ["/RUTA/ABSOLUTA/bitacora-mcp/dist/main.js"],
      "env": {
        "DECK_STORE": "mongodb",
        "MONGODB_URI": "mongodb://localhost:27017/bitacora"
      }
    }
  }
}

Tools (18)

Versionado (13)

Tool

Qué hace

presentation_create

Crea un deck y lo guarda versionado. Devuelve id + version. Con partial: true, reserva el id y guarda el HTML recibido como primer chunk sin comitear nada — hay que cerrar con presentation_append.

presentation_create_from_file

Igual que presentation_create, pero lee el HTML de un archivo local (path absoluto) en vez de tomarlo como argumento. Para decks grandes o con base64 embebido.

presentation_append

Agrega un chunk de HTML a una carga iniciada con presentation_create({partial: true}). done: true en el último chunk cierra, valida y comitea el deck completo.

presentation_update

Nueva versión con HTML y/o metadata nuevos. Con fragment: true, inyecta el HTML antes de </body> sin reemplazar el documento completo.

presentation_update_from_file

Igual que presentation_update, pero lee el HTML nuevo de un archivo local.

presentation_get

HTML + metadata en HEAD o en un version histórico. La descripción le pide al asistente mostrar el html como Artifact.

presentation_list

Lista los decks, filtrable por owner. Excluye archivados por defecto (includeArchived: true para verlos).

presentation_list_versions

Historial de commits/versiones de un deck.

presentation_rollback

Vuelve a un version anterior creando una versión nueva (no destructivo).

presentation_search

Búsqueda full-text sobre título, tags y contenido HTML. Devuelve matches con snippet y matchedIn.

presentation_diff

Dif textual + visual HTML side-by-side entre dos versiones. Resuelve "¿qué cambió entre la versión que aprobó el director y la actual?".

presentation_archive

Soft-delete no destructivo: marca el deck como archivado, lo saca de list/search.

presentation_unarchive

Restaura un deck archivado.

presentation_validate

Reporte estructurado pre-deploy: DOCTYPE, mixed content, <base target>, charset, viewport, scripts inline, event handlers, múltiples <body>. Devuelve canDeploy.

Publicación (5)

Tool

Qué hace

presentation_deploy

Publica un version (default HEAD) como web app de Apps Script. access opcional controla quién puede verla (MYSELF/DOMAIN/ANYONE/ANYONE_ANONYMOUS, default DOMAIN). Idempotente por commit + access.

presentation_get_deployment

Devuelve el estado de publicación actual (commit, scriptId, deploymentId, url).

presentation_list_deployments

Historial completo de publicaciones por deck (incluye despublicadas), para auditoría.

presentation_unpublish

Despublica: borra el deployment de Apps Script (la URL deja de servir), marca el registro con unpublishedAt. No destructivo.

presentation_get_deployment

Estado de publicación actual de un deck.

Decks grandes

Dos problemas distintos, dos soluciones distintas:

1. El HTML ya existe como archivo en disco → create_from_file / update_from_file. El server lo lee directo del filesystem, byte a byte. El modelo nunca reproduce el contenido, así que no importa cuán grande sea ni si tiene base64 embebido.

2. El HTML lo está generando el modelo y no entra en una sola tool call → create({partial: true}) + append por chunks. Recién en done: true se normaliza y comitea, igual que un create de una sola llamada.

Arquitectura

src/
  core/                    # DeckService (normalize/escHtml), DeckValidateService
  store/                   # DeckStore interface + GitSpecStore | MongoDeckStore
  auth/                    # WorkspaceDomainGuard, SqliteOAuthStore, MongoOAuthStore
  presentations/           # PresentationsService + Controller (13 tools), PendingUpload
  deployer/               # AppsScriptClient (real/mock), SandboxTransform, DeployerService (5 tools)
  shared-tools.module.ts  # controllers + providers, importado por stdio y HTTP
  app.module.ts            # bootstrap stdio (sin auth)
  http-app.module.ts       # bootstrap HTTP (con OAuth de Workspace)
  main.ts / main-http.ts   # entry points

Dos modos de store, dos modos de auth:

Componente

Default (local)

MongoDB (multi-user/AWS)

Decks

GitSpecStore (filesystem)

MongoDeckStore (colección decks)

OAuth sessions

SqliteOAuthStore (archivo)

MongoOAuthStore (colecciones oauth_*)

Switch via DECK_STORE y OAUTH_STORE env vars.

Notas de stack

  • @rekog/mcp-nest v2 — API McpStrategy + @McpController

  • @rekog/mcp-nest-auth v2 — servidor de autorización OAuth 2.1/MCP embebido (McpAuthModule + GoogleOAuthProvider)

  • Node 22 con --env-file=.env nativo (sin dotenv)

  • mongodb driver oficial (sin Mongoose ni ODM)

  • simple-git para el store git, better-sqlite3 para el store de sesiones

  • zod v4 para schemas de las tools

  • TypeScript 7.x, module/moduleResolution: nodenext

Available Tools

8 tools
presentation_createA

Crea una presentación HTML y la guarda versionada en el store. No la publica (deploy es Fase 2). Devuelve id y versión (commit SHA).

Inputs: html (required), title (required), tags, owner.

presentation_deployA

Publica una versión (commit) de una presentación como web app de Apps Script y devuelve su URL. Idempotente por versión: si ese commit ya está publicado, devuelve la URL existente sin volver a deployar.

Inputs: id (required), version.

presentation_getA

Devuelve el HTML y la metadata de una presentación. Por defecto la versión actual (HEAD); con "version" (SHA) devuelve esa versión histórica.

Inputs: id (required), version.

presentation_get_deploymentA

Devuelve el estado de publicación actual de una presentación (commit, scriptId, deploymentId, url).

Inputs: id (required).

presentation_listB

Lista las presentaciones guardadas, opcionalmente filtradas por dueño.

Inputs: owner.

presentation_list_versionsA

Lista el historial de versiones (commits) de una presentación, del más nuevo al más viejo.

Inputs: id (required).

presentation_rollbackA

Vuelve una presentación a una versión anterior creando un nuevo commit con ese contenido (rollback no destructivo).

Inputs: id (required), version (required).

presentation_updateA

Actualiza una presentación existente (reemplaza HTML y/o metadata) creando una nueva versión. No borra el historial.

Inputs: id (required), html, tags, title.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.2/5.0

    Scored across 8 tools

    Disambiguation5/5

    Each tool targets a distinct resource and action: create, update, get, list_versions, list, rollback, deploy, and get_deployment. The boundaries are clear, e.g., presentation_get for content vs presentation_get_deployment for deployment status.

    Naming Consistency5/5

    All tools follow the presentation_verb pattern consistently, using straightforward verbs like create, update, get, list, rollback, deploy. Even sub-actions like list_versions and get_deployment maintain the pattern.

    Tool Count5/5

    8 tools is well-scoped for a presentation management service with versioning and deployment. Each tool serves a distinct purpose without redundancy or bloat.

    Completeness4/5

    The lifecycle is well covered with create, read, update, versioning, rollback, and deployment. The only notable gap is the absence of a delete/purge operation for presentations, which agents might need for full lifecycle management.

    Related MCP Connectors

    Related MCP Servers