TimelinesAI MCP Server
Enables Claude to read and operate a TimelinesAI WhatsApp team inbox, including chats, messages, labels, assignments, and sending, with built-in read-only and confirmation safeguards.
README
TimelinesAI MCP Server
Servidor MCP (Model Context Protocol) que expone la API pública de TimelinesAI —el inbox de WhatsApp para equipos— a Claude. Pensado para desplegarse en Railway en modo solo lectura.
👉 Los pasos de despliegue están en DEPLOY-RAILWAY.md.
Qué hace
Da a Claude 12 herramientas para leer y operar el inbox: chats, mensajes, etiquetas, responsables, números conectados y equipo — más una herramienta genérica, una de descubrimiento, y un resumen agregado del inbox.
| Herramienta | Endpoint |
|---|---|
timelines_whoami |
verifica el token, el workspace y las rejas |
timelines_request |
cualquier endpoint, cualquier método |
timelines_discover |
sondea rutas y reporta cuáles existen |
timelines_list_chats |
GET /chats con todos los filtros |
timelines_get_chat |
GET /chats/{id} |
timelines_list_messages |
GET /chats/{id}/messages |
timelines_send_message |
POST /messages o /chats/{id}/messages |
timelines_update_chat |
PATCH /chats/{id} |
timelines_manage_labels |
GET/POST/PUT /chats/{id}/labels |
timelines_list_whatsapp_accounts |
GET /whatsapp_accounts |
timelines_list_teammates |
GET /workspace/teammates |
timelines_activity_summary |
pagina /chats y cuenta todo (50 por página) |
Variables de entorno
| Variable | Requerida | Default | Descripción |
|---|---|---|---|
TIMELINES_API_TOKEN |
sí | — | Token de la API (tla_...) |
TIMELINES_MCP_TRANSPORT |
en Railway | stdio |
http para servidor remoto |
MCP_AUTH_TOKEN |
si http |
— | Secreto que protege el endpoint. Mínimo 32 caracteres |
TIMELINES_READ_ONLY |
no | ver abajo | 1 bloquea toda escritura |
TIMELINES_ALLOW_SEND |
no | 0 |
Reja aparte: enviar mensajes de WhatsApp |
TIMELINES_API_BASE |
no | https://app.timelines.ai/integrations/api |
Para apuntar a otro host |
TIMELINES_MAX_CHARS |
no | 20000 |
Truncado de respuestas |
TIMELINES_TIMEOUT |
no | 45 |
Timeout en segundos |
PORT |
no | 8000 |
Railway lo inyecta solo |
Las tres rejas
Este MCP habla con personas reales. Un mensaje enviado por WhatsApp llega al teléfono de alguien en segundos y no se puede deshacer. Por eso hay tres candados independientes.
1. TIMELINES_READ_ONLY — el default depende del transporte
stdio(local): escrituras permitidas por default.http(remoto): escrituras bloqueadas por default.
Olvidar la variable en un despliegue público lo deja en solo lectura.
2. TIMELINES_ALLOW_SEND — la reja de envío
Apagada por default en los dos transportes, incluso en local. Aunque
habilites las escrituras, enviar mensajes sigue bloqueado hasta que pongas
TIMELINES_ALLOW_SEND=1.
La razón es la asimetría: cambiar una etiqueta, reasignar un chat o cerrarlo son acciones internas y reversibles. Mandar un WhatsApp a un cliente no lo es. No tiene sentido que compartan el mismo interruptor.
3. confirm=true — la reja por llamada
Todo envío exige confirm=true además de lo anterior, igual que borrar un
archivo, reconfigurar un webhook o revocar el acceso de un compañero. La
instrucción de la herramienta es explícita: primero muéstrale al usuario el
destinatario exacto y el texto exacto, y solo con su visto bueno se confirma.
Cada rechazo dice cuál de las tres rejas lo detuvo.
Autenticación del endpoint
El protocolo MCP no trae autenticación propia. En modo http, este servidor
exige Authorization: Bearer <MCP_AUTH_TOKEN> en cada request, o el secreto
embebido en la ruta (/s/<secreto>/mcp) para los connectors de Claude.
/healthz es la única ruta pública.
El servidor se niega a arrancar si MCP_AUTH_TOKEN falta o tiene menos de
32 caracteres.
Correr en local
pip install -r requirements.txt
# stdio (para Claude Desktop)
TIMELINES_API_TOKEN=tla_xxx python timelines_mcp.py
# http (como en Railway)
TIMELINES_MCP_TRANSPORT=http \
TIMELINES_API_TOKEN=tla_xxx \
MCP_AUTH_TOKEN=$(python3 -c "import secrets;print(secrets.token_urlsafe(48))") \
PORT=8000 python timelines_mcp.py
Al arrancar imprime en qué modo quedó:
[timelines-mcp] streamable-http on 0.0.0.0:8000 token=set read_only=True allow_send=False sending_enabled=False
Notas sobre la API de TimelinesAI
Verificado contra la referencia pública (https://timelines.ai/docs/public-api-reference/overview):
-
Base:
https://app.timelines.ai/integrations/api, authAuthorization: Bearer <tla_...>. -
Los cuerpos van en JSON, no form-encoded.
-
Las respuestas vienen envueltas:
{"status":"ok","data":{...}}. Y hay fallos que llegan con HTTP 200 perostatus:"error"— este servidor los trata como error, no como éxito, porque si no un envío fallido se leería como enviado. -
Los errores traen detalle por campo:
{"status":"error","message":..., "error_code":...,"errors":[{"fields":["phone"],"msg":"..."}]}. Se muestran tal cual en el mensaje de error. -
Los filtros de varios valores van separados por coma en un solo parámetro (
label=vip,enterprise), no repetidos ni con corchetes. Pasar una lista de Python produce esa forma. -
El tamaño de página es fijo en 50 y no se puede cambiar. Verificado contra la API en vivo el 2026-08-25:
limit,per_page,page_size,size,count,takeyrowsse ignoran todos, y cada página llega con 50 registros. El único parámetro que hace algo espage, yhas_more_pagesen la respuesta dice si hay otra. Por eso las herramientas no exponen unper_page: sería un parámetro que aparenta ajustar y no ajusta nada. -
Para reducir el tamaño de una respuesta, entonces, no queda bajar la página: hay que filtrar más, o usar
fieldspara quedarte solo con las claves que necesitas. Los mensajes son el caso que más lo pide — un chat con 50 mensajes se pasa del límite de caracteres sin problema.fields=["uid","text", "from_me","timestamp"]deja lo esencial de una conversación en una fracción del tamaño. -
Ojo con los nombres de campo repetidos: un registro de mensaje trae su propia clave
data(un dict de metadatos), además deldatade la envoltura. Por esofieldsdecide qué podar por posición (lo que está dentro de una lista es un registro) y no por el nombre de la clave. -
Los teléfonos van en formato internacional con
+:+5215512345678. El modelo lo valida antes de salir a la red y limpia espacios y guiones. -
texttiene tope de 2000 caracteres; las etiquetas 64, los nombres de chat 256. -
Si omites
whatsapp_account_phone, TimelinesAI manda desde la cuenta conectada más recientemente — que rara vez es la que el usuario tiene en mente. Con más de un número conectado, conviene ser explícito. -
Los envíos se espacian ~2 segundos entre uno y otro por política de WhatsApp, y cada mensaje consume créditos (1 texto, 2 con adjunto; los fallidos se reembolsan).
-
Hay tres límites distintos y conviene no confundirlos:
Límite Valor Aplica a Tasa de peticiones 50 por minuto por workspace Todo, lecturas incluidas Volumen mensual 200,000 llamadas al mes Todo Cuota de mensajería según tu plan (créditos) Solo envíos El primero es el que muerde: pasarse devuelve 429
rate_limit_exceededa media faena, no al principio.El servidor se defiende en dos niveles, ambos en la capa de peticiones para que todas las herramientas queden cubiertas, no solo las que paginan:
- Ritmo compartido. Las llamadas se espacian 1.2 s entre sí (60÷50). Una llamada suelta no espera nada; el retraso solo aparece en ráfagas, que es justo el caso que topa el límite. El límite es por workspace y todas las herramientas comparten uno, así que el marcapasos también es único.
- Reintento con
Retry-After. Un 429 en una lectura se reintenta una vez, esperando exactamente lo que pide el servidor. Un envío nunca se reintenta solo: un mensaje que quizá salió no se repite por corazonada.
timelines_activity_summaryademás devuelve lo que alcanzó a contar con una notastopped_earlysi aun así lo cortan. Para preguntas por persona conviene filtrar (responsible=alguien@...) en lugar de escanear páginas: una petición en vez de veinte. Se pueden pedir límites mayores escribiendo a hello@timelines.ai. -
No hay endpoint de agregación. Por eso
timelines_activity_summarypagina y cuenta del lado del servidor MCP, y avisa concomplete=falsecuando el conteo no llegó al final.
Seguridad
- Los secretos van en variables de entorno, nunca en el código. El
.gitignorebloquea archivos.env. - Un token de TimelinesAI da acceso a todo el workspace: todas las conversaciones de WhatsApp del equipo, con sus teléfonos y su contenido. Es información de clientes reales — trátala como tal.
- Un solo token compartido significa cero trazabilidad por persona.
- Para cortar el acceso de golpe: revoca el token en el dashboard de TimelinesAI — el servidor queda inútil al instante.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.