bitacora-mcp
Allows deploying HTML presentations as Google Apps Script web apps, including publishing a specific version and querying the deployment status.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@bitacora-mcpCreate a new presentation from the file ~/slides.html"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
bitacora-mcp — Fase 3 (código local)
MCP server en NestJS para crear, versionar, recuperar y publicar presentaciones HTML. El store git es la fuente de verdad; Apps Script (Google Workspace) es el target de publicación, descartable y reconstruible desde cualquier commit. Corriendo por HTTP, la identidad es un login real de Google Workspace, no un argumento de texto libre.
Qué hace (y qué no, todavía)
✅
create/update/get/list/list_versions/rollback✅ Cada operación es un commit → historial real en git, rollback no destructivo
✅ Normaliza el HTML: envuelve fragments en documento completo con
<title>escapado (mismo patrónescHtmldel review de XSS)✅
deploy/get_deployment: publica un commit como web app de Apps Script (idempotente por versión) y consulta el estado de publicación✅ Transform sandbox-safe antes de publicar: fuerza
<!DOCTYPE html>,<base target="_top">y bloquea assetshttp://(mixed content)✅ Bootstrap HTTP alternativo (
npm run start:http) con login de Google Workspace:presentation_createusa el email autenticado comoownerreal, ignorando lo que mande el cliente. Restringido a un dominio (bidcom.com.arpor defecto).✅
create_from_file/update_from_file: leen el HTML directo de un archivo local, byte a byte, para decks grandes o con contenido binario embebido (imágenes en base64) que un modelo no puede reproducir de forma confiable como argumento de texto.⛔ Sigue corriendo solo local — el service account de dominio (en vez de cuenta personal) queda pendiente, fuera del alcance de "solo código" de este momento. Este MCP nunca se hostea en un cluster propio: lo único que se publica en infraestructura externa son las presentaciones, como web apps de Google Workspace vía Apps Script.
Related MCP server: google-workspace-mcp-server
Arquitectura interna
Los módulos mapean 1:1 a los futuros packages/ del monorepo:
core/→ normalización y validación de HTML (DeckService,escHtml)store/→GitSpecStore, el store versionado en git (decks + índice de deployments)presentations/→ orquestación +@McpControllercon las 6 tools de versionadodeployer/→ toda la fricción de Google (Apps Script) en un lugar: OAuth, cliente de la Apps Script API, transform sandbox-safe, y las 2 tools de publicaciónauth/→ guard de dominio + config del servidor de autorización OAuth para el bootstrap HTTPshared-tools.module.ts→ controllers/providers de las 8 tools, importado tanto por el bootstrap stdio (app.module.ts) como por el HTTP (http-app.module.ts) para no duplicar la lista
Correr
npm install
npm run build
npm start # levanta el server por stdioEl store se crea en ~/.bitacora-store (configurable con DECK_STORE_DIR).
Publicar en Apps Script (setup de Google, una sola vez)
El deploy corre bajo cuenta personal en esta fase (Fase 3 migra a service account de dominio). Pasos previos, una sola vez por máquina/cuenta:
En Google Cloud Console, un proyecto (o uno nuevo).
Habilitar la Google Apps Script API en ese proyecto (APIs & Services → Library).
Credentials → Create credentials → OAuth client ID, tipo Desktop app.
Descargar el JSON y guardarlo en
~/.bitacora-google/oauth-client.json(override conGOOGLE_OAUTH_CLIENT_PATH).Correr el consent flow local:
npm run build npm run google:authorizeAbre una URL de consentimiento, levanta un server local (loopback) para recibir el redirect, y cachea el refresh token en
~/.bitacora-google/token.json(override conGOOGLE_TOKEN_PATH). Se refresca solo de ahí en más.
Las credenciales de Google se guardan fuera del store git a propósito
(~/.bitacora-google/, no DECK_STORE_DIR): el store se versiona y podría
compartirse; nada con secretos debe vivir ahí.
Variables opcionales para el manifest del web app:
Env var | Default | Qué controla |
|
| Quién puede abrir la URL publicada ( |
|
| Con qué identidad corre el |
Prueba end-to-end
npm run smoke # cliente MCP que ejercita todo el ciclo sobre stdioEl smoke test corre con DECK_DEPLOYER_MOCK=1: el ciclo deploy /
get_deployment se ejercita contra un cliente de Apps Script en memoria, sin
tocar Google ni requerir credenciales. Para probar contra la API real, corré
el server con DECK_DEPLOYER_MOCK sin setear (o en 0) y las credenciales de
la sección anterior ya cacheadas.
Correr con login de Google Workspace (HTTP, local)
Bootstrap alternativo al stdio de siempre: el server escucha por HTTP y exige un login real de Workspace antes de dejar usar cualquier tool. Pensado para probar el flujo de identidad localmente antes de decidir dónde corre este proceso para uso remoto (Fase 3 completa, fuera de alcance por ahora) — nunca en un cluster propio como EKS; lo único que este proyecto publica en infraestructura externa son las presentaciones, vía Apps Script.
Es un segundo OAuth client, distinto del "Desktop app" que ya usa el deployer de Apps Script — este es para loguear usuarios, no para llamar a una API:
En el mismo proyecto de Google Cloud Console → Create Credentials → OAuth client ID → tipo Web application (¡no Desktop app! ese tipo no tiene redirect URI configurable).
Authorized JavaScript origins:
http://localhost:3030(sin path, sin/final).Authorized redirect URIs:
http://localhost:3030/auth/callback(con path, exacto).Anotá el Client ID y el Client secret (o descargá el JSON).
Variables de entorno para levantar el bootstrap HTTP:
Env var | Requerida | Qué es |
| sí | Client ID del OAuth client "Web application" de arriba |
| sí | Su client secret |
| sí | Firma los tokens que emite el servidor de autorización propio. Generá uno con |
| no (default | Dominio al que se restringen los logins — cualquier otra cuenta de Google recibe 403 |
| no (default | Base URL del server |
| no (default | Puerto HTTP |
npm run build
export GOOGLE_WORKSPACE_CLIENT_ID=...
export GOOGLE_WORKSPACE_CLIENT_SECRET=...
export JWT_SECRET=$(openssl rand -hex 32)
npm run start:httpEl server queda escuchando en http://localhost:3030/mcp, con los endpoints
OAuth estándar del servidor de autorización embebido bajo /auth/* y
/.well-known/* (discovery). Un cliente MCP real (Claude, MCP Inspector) hace
todo el baile de login solo; para un chequeo manual sin un cliente a mano, un
cliente OAuth de prueba (registro DCR + PKCE + tools/call) sirve para
verificar que owner termina siendo el email autenticado, no lo que mande
quien llama.
Por qué dos capas de OAuth: Google no soporta Dynamic Client
Registration, que es justo lo que un cliente MCP remoto (Claude) necesita
para autoregistrarse contra el servidor de autorización sin configuración
previa. Apuntar un cliente MCP directo a Google como authorization server
rompe con mcp_registration_failed — ya nos pasó antes. La solución (la que
usa este server) es que nuestro propio servidor de autorización (el
McpAuthModule de @rekog/mcp-nest-auth) hable el protocolo OAuth 2.1/MCP
completo con el cliente MCP (DCR, PKCE, discovery), y delegue solo el login
a Google por dentro. El cliente MCP nunca sabe que Google existe.
Conectar a Claude Desktop
En claude_desktop_config.json:
{
"mcpServers": {
"bitacora": {
"command": "node",
"args": ["/RUTA/ABSOLUTA/bitacora-mcp/dist/main.js"],
"env": { "DECK_STORE_DIR": "/RUTA/ABSOLUTA/deck-store" }
}
}
}Decks grandes
Hay dos problemas distintos detrás de "el HTML es grande", con soluciones distintas:
1. El HTML ya existe como archivo en disco. Usá create_from_file /
update_from_file — el server lo lee directo del filesystem, byte a byte. El
modelo nunca ve ni reproduce el contenido, así que no importa cuán grande sea
ni si tiene imágenes en base64 embebidas: no hay riesgo de truncamiento ni de
corrupción por transcripción.
presentation_create_from_file({ path: "/ruta/absoluta/deck.html", title, owner })
presentation_deploy({ id })2. El HTML lo está generando el modelo mismo (no existe como archivo) y es demasiado grande para una sola tool call — el límite real lo pone el cliente MCP emitiendo el argumento (en la práctica, unos ~40 KB por llamada), no este server. Para ese caso existe la carga por chunks:
presentation_create({ title, html: chunk0, owner, partial: true }) -> { id }
presentation_append({ id, html: chunk1, done: false }) // repetir N veces
presentation_append({ id, html: chunkN, done: true }) // cierra y comitea
presentation_deploy({ id }) // igual que siempreCon partial: true no se toca git todavía — solo se reserva el id y se
guarda el HTML recibido en memoria. Recién en el done: true corre la
normalización de siempre (Fase 1) y se comitea, exactamente como si hubiera
llegado en una sola llamada. Una carga sin cerrar (sin done: true) no deja
rastro en el store; se pierde si el proceso reinicia, que es aceptable porque
solo afecta a esa carga en curso, no a decks ya guardados.
Chunking no resuelve el problema (1): un modelo tiene que regenerar cada
byte del argumento de cada chunk, y para contenido grande con base64 embebido
eso es un problema de fidelidad de transcripción, no de tamaño — por eso
existe create_from_file como camino aparte.
Tools
Tool | Qué hace |
| Crea un deck y lo guarda versionado. Devuelve |
| Igual que |
| Agrega un chunk de HTML a una carga iniciada con |
| Nueva versión con HTML y/o metadata nuevos. |
| Igual que |
| HTML + metadata en HEAD o en un |
| Lista los decks, filtrable por |
| Historial de commits de un deck. |
| Vuelve a un |
| Publica un |
| Devuelve el estado de publicación actual (commit, scriptId, deploymentId, url). |
Notas de stack
@rekog/mcp-nestv2 — APIMcpStrategy+@McpController(noMcpModule.forRoot).Transporte stdio:
logger: falseporque stdout está reservado para el protocolo.@rekog/mcp-nest-auth— servidor de autorización OAuth 2.1/MCP embebido (McpAuthModule), conGoogleOAuthProviderdelegando el login. Solo se usa en el bootstrap HTTP (http-app.module.ts/main-http.ts); el stdio (app.module.ts/main.ts) no lo toca.Bajo stdio no hay request HTTP, así que ninguna tool ve un usuario autenticado (
@McpUser()daundefined) — es el comportamiento esperado para uso local en Claude Desktop, documentado por la propia librería.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
Flicense-qualityBmaintenanceMCP server that wraps the Slideless HTTP API as tools for listing, sharing, uploading, and managing HTML presentations from any MCP host without installing the CLI.Last updated- AlicenseAqualityDmaintenanceMCP server for Google Workspace APIs - Docs, Sheets, Drive, Gmail, and Calendar. Enables reading, creating, and editing Google Docs and Sheets, managing comments, reading emails, and viewing calendar events.Last updated2345416MIT
- Alicense-qualityCmaintenanceProvides MCP server for Google Slides API, enabling creation, reading, modification, and management of Google Slides presentations using service account authentication.Last updated254GPL 3.0
- AlicenseBqualityCmaintenanceProduction-ready MCP server for Google Workspace providing broad coverage across Gmail, Drive, Calendar, Docs, Sheets, and more, with safe-by-default write operations and markdown-to-Google-Docs support.Last updated100MIT
Related MCP Connectors
List, share, upload, and manage Slideless HTML presentations from any MCP host.
Streamable HTTP MCP server for Google Calendar and Sheets with OAuth login.
Presentations.AI MCP server — create designed slide decks from a topic, text, or document.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Bidcomsrl/bitacora-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server