Le escribí “prepárame para mi reunión de las 2pm” en WhatsApp. Treinta segundos después, mi celular vibró con un resumen estructurado: quién era la persona, de qué habíamos hablado por correo, qué dijo mi equipo sobre ella en Slack, y tres puntos clave. Sin pestañas del navegador. Sin laptop. Solo un mensaje en mi camino al trabajo.

Esa es la promesa de un asistente de AI siempre activo. Y hasta hace poco, era casi imposible construir uno que realmente funcionara.

Frameworks de código abierto como OpenClaw popularizaron los agentes de mensajería bidireccional sin interfaz. Los Claude Code Channels confirmaron que el enfoque tenía futuro. Channels está en vista previa de investigación, pero la dirección es clara. Anthropic ya usa este patrón para transiciones entre su app de escritorio, app móvil y Claude Code. Todo indica que llegará a disponibilidad general pronto.

Pero pasar de un demo de fin de semana a un asistente confiable deja al descubierto problemas que ninguna ingeniería de prompts resuelve. Autorización. Confiabilidad de herramientas. Gestión de sesiones. El agente necesita acceso a tu calendario, correo y Slack, y tienes que asegurarte de que no sea un riesgo de seguridad.

Construí una versión funcional. Esta guía recorre todo el proceso: un servidor relay para WhatsApp, un servidor MCP, Claude Code como cerebro y Arcade.dev para acceso seguro a herramientas. Código funcional en cada paso.

Empezamos con los problemas que debes entender y después lo construimos.

TL;DR

  • Los frameworks sin interfaz estilo OpenClaw le dan a tu agente acceso total a cada servicio conectado, dependen de wrappers frágiles, saturan la ventana de contexto con respuestas brutas de API y no generan ningún registro de auditoría. Comprar una Mac Mini dedicada para correrlos no ayuda. La máquina no es el problema de seguridad: las credenciales sí.
  • Esta guía construye un asistente de AI en WhatsApp con un servidor relay que maneja los webhooks de Meta, un servidor MCP que conecta con Claude Code, Arcade para acceso seguro a herramientas y registro de auditoría, y una habilidad de preparación para reuniones que extrae datos de Google Calendar, Gmail y Slack para entregar resúmenes directamente en WhatsApp.
  • Cada capa incluye código funcional que puedes correr localmente: ingesta de webhooks con validación de firma HMAC, una cola de mensajes basada en cursor, definiciones de herramientas MCP, configuración de Claude Code y un archivo de habilidad completo que codifica un flujo de preparación para reuniones en tres fases.

Del demo a producción: los cuatro errores comunes de los agentes de AI siempre activos

La arquitectura sin interfaz que OpenClaw popularizó es el punto de partida. En cuanto intentas pasar de un proof of concept de fin de semana a algo en lo que realmente confiarías con tu calendario y correo, aparecen cuatro problemas arquitectónicos.

Error 1: Credenciales con acceso total y el riesgo de seguridad del agente

Los frameworks de agentes sin interfaz heredan el perfil de acceso completo de la máquina anfitriona. El agente obtiene los mismos permisos que el desarrollador que lo lanzó. Cada token OAuth, cada API key, cada servicio conectado, completamente expuestos.

Una sola inyección de prompt o dependencia comprometida se propaga por todo. Tu Google Drive, tu CRM, tus repositorios de código fuente. Una entrada maliciosa y el agente se convierte en una amenaza interna.

No es teórico. CVE-2026-25253 expuso un RCE de un clic en OpenClaw. El gateway carecía de validación de origen. Un atacante podía exfiltrar el token de auth mediante un enlace malicioso y lograr un compromiso total del sistema.

Escribimos sobre este patrón en detalle en OpenClaw doesn’t need your tokens.

Error 2: Wrappers de API frágiles y el problema de confiabilidad de herramientas

La mayoría de las herramientas para agentes son wrappers delgados sobre APIs REST. Obligan al modelo a adivinar parámetros complejos y reintentar cuando el lenguaje natural no encaja con esquemas rígidos.

Luego aparecen los registros paralelos. Distintos equipos construyen wrappers duplicados y sin versión para las mismas APIs. Un cambio de API sin aviso rompe múltiples agentes de formas que nadie anticipó. Los registros públicos de herramientas ya se convirtieron en un vector de ataque a la cadena de suministro, con herramientas maliciosas que exfiltran estado local o establecen backdoors.

Para patrones que hacen las herramientas MCP más resilientes, consulta 54 Patterns for Building Better MCP Tools.

Error 3: Saturación de la ventana de contexto con respuestas brutas de API

Las herramientas sin optimizar vuelcan la respuesta completa de la API en la ventana de contexto. ¿El historial de un ticket de Jira? Decenas de miles de tokens de metadatos irrelevantes. El razonamiento del agente se vuelve errático. Los costos se disparan con cada turno de conversación.

Error 4: Sin registro de auditoría, sin confiabilidad, sin cumplimiento normativo

Mantener vivo un agente autohospedado con tmux o systemd crea un agujero negro de auditoría. Cuando el proceso falla o se comporta mal, no hay un registro estructurado para rastrear qué pasó. ¿Qué acción se ejecutó? ¿Con qué parámetros? ¿Qué usuario inició la solicitud?

No puedes responder “¿qué hizo el agente?” si nunca lo registraste.

Eso es un fallo inmediato para SOC2, ISO27001 y cualquier revisión de cumplimiento seria.

Por qué comprar una Mac Mini no resuelve nada de esto

Hay una tendencia creciente: desarrolladores que compran Mac Minis dedicadas o levantan VMs para correr agentes estilo OpenClaw 24/7. La lógica es que, si el agente tiene su propia máquina, lo aislaste.

No es así. La máquina no es el modelo de amenaza. Las credenciales sí.

Esa Mac Mini igual necesita tokens OAuth para Google Calendar, API keys para tu CRM, acceso a tu workspace de Slack. Una dependencia comprometida no distingue si corre en tu laptop o en un servidor dedicado dentro de un clóset. El radio de impacto es idéntico. Para una comparación más profunda de estrategias de aislamiento que realmente lo reducen, consulta Guía de Sandboxing para Agentes de AI.

El aislamiento por hardware resuelve disponibilidad. No toca autorización, confiabilidad de herramientas, gestión de contexto ni registros de auditoría.

Construiste una máquina cara, siempre encendida, con acceso sin restricciones a tus sistemas de negocio. Todos los problemas anteriores siguen ahí.

Cómo Arcade, Claude Code y los Skills resuelven estos problemas

Necesitaba tres cosas: una forma segura de conectarme a herramientas de negocio, un runtime de agente probado en producción, y una manera de codificar flujos de trabajo sin escribir código de integración.

Arcade resuelve la capa de herramientas y autenticación. Se ubica entre el agente y tus herramientas de negocio. Cuando el agente quiere leer tu calendario, Arcade evalúa los permisos, genera un token just-in-time con alcance a esa acción específica y ejecuta la llamada. El LLM nunca ve credenciales de larga duración. Tu token de Google Calendar no está guardado en un archivo .env en una Mac Mini. Lo gestiona el runtime de Arcade con autorización por acción.

Arcade también resuelve el problema de herramientas frágiles. En lugar de escribir wrappers REST quebradizos, usas integraciones preconstruidas y optimizadas para agentes que devuelven datos resumidos, no volcados de JSON crudo. Cuando Google cambia su API de Calendar, Arcade lo maneja. Tu código del agente no se toca. Y cada llamada a una herramienta genera registros de auditoría estructurados vinculados al usuario y la acción específicos.

Claude Code es el runtime del agente. Está más probado en producción que OpenClaw, tiene soporte nativo para MCP y maneja la orquestación de herramientas sin la gestión frágil de procesos de tmux y systemd scripts.

Los Skills codifican los flujos de trabajo reales. Esta es la pieza que la mayoría pasa por alto. Arcade le da al agente acceso a tus herramientas con la autenticación correcta. Los Skills le dicen al agente cómo usarlas bien. Para una mirada más detallada a la distinción, consulta Skills vs Tools para Agentes de AI.

Un skill es un archivo markdown que codifica experiencia de dominio: qué herramientas llamar, en qué orden, qué buscar en los resultados, cómo formatear la salida. Sin un skill, tienes un agente con acceso al calendario pero sin idea de cómo preparar un resumen de reunión. Con un skill, tienes un asistente que obtiene eventos del calendario, cruza referencias con hilos de correo, revisa Slack para obtener contexto interno y entrega un briefing estructurado, todo desde un solo mensaje de WhatsApp.

Arcade da acceso. Los Skills dan experiencia. Juntos, convierten un LLM en un asistente útil.

Y como los skills son solo archivos markdown, cualquier persona del equipo puede escribirlos e iterarlos. Sin despliegue de código. Sin tickets de ingeniería.

Esto es lo que estamos construyendo: un relay de WhatsApp para mensajería, Claude Code como cerebro, Arcade para acceso a herramientas con autenticación gestionada, y skills que codifican los flujos de trabajo de tu equipo.

Paso a paso: construye el asistente de AI para WhatsApp con MCP y Arcade

Suficiente arquitectura. Esto es lo que vamos a hacer: los mensajes de WhatsApp fluyen a través de un servidor relay hacia un servidor MCP, que los envía a Claude Code. Claude Code procesa los mensajes usando skills, llama a herramientas de negocio a través de Arcade y responde por la misma cadena.

Un detalle importante: la Cloud API de WhatsApp solo soporta webhooks. No hay opción de WebSocket ni long-polling. Eso significa que algo tiene que estar en una URL pública para recibir los callbacks de Meta. Como corremos todo localmente, el servidor relay cumple ese rol, y ngrok tuneliza el tráfico desde los servidores de Meta hasta tu máquina.

A detailed technical architecture diagram illustrating the integration flow from a WhatsApp user on a smartphone to Claude Code. The horizontal sequential flow proceeds through Meta Cloud API, ngrok, Relay Server, and MCP Server before reaching Claude Code. An auxiliary 'Arcade' service box (with integrated services like Calendar, Email, Slack, and CRM) is connected to Claude Code. A dashed return line labeled 'replies' indicates a feedback path from Claude Code back to the Relay Server.

Requisitos previos: WhatsApp Business API, Claude Code y Arcade

Antes de empezar, asegúrate de tener una cuenta de desarrollador de Meta con una WhatsApp Business App configurada (guía de inicio de Meta), Node.js 20+ y npm, ngrok para tunelizar webhooks a tu máquina local, Claude Code instalado y configurado, y una cuenta de Arcade con acceso a la API y un número de teléfono registrado en WhatsApp Business API.

Paso 1: Estructura del proyecto y configuración del entorno

Así queda la estructura de carpetas:

whatsapp-assistant/
├── whatsapp.ts          # MCP server (bridge between relay and Claude Code)
├── package.json         # MCP server dependencies
├── .mcp.json            # Claude Code MCP server registration
├── whatsapp-relay/
│   ├── relay.ts         # Relay server (faces the internet via ngrok)
│   ├── package.json     # Relay server dependencies
│   └── .env             # WhatsApp API credentials (from .env.example)
└── skills/
    └── meeting-prep/
        └── SKILL.md     # Meeting preparation skill for Claude Code

Empieza configurando ambos proyectos:

# Create the project
mkdir whatsapp-assistant && cd whatsapp-assistant

# Initialize the MCP server
npm init -y
npm install @modelcontextprotocol/sdk
npm install -D typescript @types/node tsx

# Initialize the relay server
mkdir whatsapp-relay && cd whatsapp-relay
npm init -y
npm install hono @hono/node-server
npm install -D typescript @types/node tsx
cd ..

Crea tu archivo .env dentro de whatsapp-relay/ con las siguientes variables:

# Meta WhatsApp Cloud API
WHATSAPP_ACCESS_TOKEN=        # Bearer token from Meta App Dashboard
WHATSAPP_PHONE_NUMBER_ID=     # Bot's phone number ID
WHATSAPP_VERIFY_TOKEN=        # Any string, used for webhook verification handshake
WHATSAPP_APP_SECRET=          # App secret for validating webhook signatures

# Relay auth
RELAY_SECRET=                 # Shared secret, local MCP server sends this in X-Relay-Secret header

La RELAY_SECRET es una clave compartida entre el relay y el servidor MCP. Genera algo aleatorio (openssl rand -hex 32). Evita que cualquier proceso en tu red suplante al servidor MCP.

Paso 2: Construye el servidor relay de webhooks de WhatsApp

El relay es el único componente expuesto a internet. Tiene tres funciones: validar los webhooks entrantes de WhatsApp, poner mensajes en cola para el servidor MCP y hacer proxy de los mensajes salientes hacia la API de Meta.

Validación de firma del webhook

Cada payload de webhook que envía Meta incluye una firma HMAC-SHA256. El relay la verifica antes de procesar cualquier cosa:

import { createHmac, timingSafeEqual } from 'node:crypto';

const APP_SECRET = process.env.WHATSAPP_APP_SECRET!;

function verifySignature(rawBody: string, header: string | undefined): boolean {
  if (!header) return false;
  const sig = header.replace('sha256=', '');
  if (!sig) return false;
  const expected = createHmac('sha256', APP_SECRET).update(rawBody).digest('hex');
  if (sig.length !== expected.length) return false;
  return timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

Esto usa timingSafeEqual para evitar ataques de temporización, un detalle que importa cuando validas firmas de terceros.

Handler del webhook: siempre devuelve 200

Meta usa entrega at-least-once. Si tu endpoint devuelve algo distinto de 200, Meta reintenta y puede generar una avalancha de eventos duplicados. El relay confirma de inmediato y procesa de forma asíncrona:

app.post('/webhook', async c => {
  const rawBody = await c.req.text();

  if (!verifySignature(rawBody, c.req.header('x-hub-signature-256'))) {
    // Still return 200. Returning 4xx causes Meta to retry with the same bad signature.
    console.error('webhook: invalid signature');
    return c.text('ok', 200);
  }

  try {
    const payload = JSON.parse(rawBody) as WaWebhookPayload;
    parseMessages(payload);
  } catch (err) {
    console.error('webhook: parse error:', err);
  }

  return c.text('ok', 200);
});

Nota el patrón: incluso con una firma inválida, devolvemos 200. Con registrar el rechazo basta. Devolver 4xx solo hace que Meta reintente con el mismo payload malo.

Cola de mensajes en memoria con polling

El relay pone en cola los mensajes validados y expone un endpoint de polling para el servidor MCP. El servidor MCP pasa un cursor (el ID del último mensaje que procesó) para recibir solo los nuevos:

let queue: InboundMessage[] = [];
let nextId = 1;
const MAX_QUEUE = 1000;

function enqueue(msg: Omit<InboundMessage, 'id' | 'timestamp'>): void {
  queue.push({ ...msg, id: nextId++, timestamp: Date.now() });
  if (queue.length > MAX_QUEUE) {
    queue = queue.slice(queue.length - MAX_QUEUE);
  }
}

// Polling endpoint, protected by relay secret
app.get('/poll', c => {
  const since = Number(c.req.query('since') ?? '0') || 0;
  const messages = queue.filter(m => m.id > since);
  const cursor = messages.length > 0 ? messages[messages.length - 1].id : since;
  return c.json({ messages, cursor });
});

El relay autentica todas las rutas internas con el secreto compartido mediante el header x-relay-secret. Las rutas de webhook que miran hacia WhatsApp no lo usan; se validan con la firma HMAC de Meta.

Proxy de mensajes salientes

Cuando Claude Code quiere responder, pasa por el servidor MCP, que llama al relay, que llama a la API de Meta:

const WA_API = `https://graph.facebook.com/v21.0/${PHONE_NUMBER_ID}`;

async function waApi(
  path: string,
  body: Record<string, unknown>,
): Promise<{ ok: boolean; status: number; data: unknown }> {
  const res = await fetch(`${WA_API}${path}`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${ACCESS_TOKEN}`,
    },
    body: JSON.stringify(body),
  });
  const data = await res.json();
  return { ok: res.ok, status: res.status, data };
}

El relay está construido con Hono, un framework ligero que mantiene el código al mínimo. El relay completo tiene unas 200 líneas y maneja mensajes de texto, imágenes, documentos, audio, video, stickers, reacciones y ubicaciones compartidas.

Paso 3: Construye el servidor MCP para Claude Code

El servidor MCP es el puente entre el relay y Claude Code. Hace polling al relay para recibir mensajes entrantes de WhatsApp y expone herramientas que Claude Code puede invocar para responder.

Definición de herramientas

El servidor registra cuatro herramientas con Claude Code a través del Model Context Protocol:

const mcp = new Server(
  { name: 'whatsapp', version: '1.0.0' },
  {
    capabilities: { tools: {}, experimental: { 'claude/channel': {} } },
    instructions: [
      'The sender reads WhatsApp, not this session.',
      'Anything you want them to see must go through the reply tool.',
      'Messages arrive as <channel source="whatsapp" chat_id="..." wamid="..." user="..." ts="...">.',
      'Reply with the reply tool. Pass chat_id (phone number) back.',
      'WhatsApp has a 24-hour session window: you can only send free-form messages',
      "within 24 hours of the user's last message.",
    ].join('\n'),
  },
);

El campo instructions le indica a Claude Code cómo interpretar los mensajes entrantes y que debe usar la herramienta reply para enviar cualquier respuesta. Sin esto, el modelo podría intentar responder en su propio transcript, algo que el usuario de WhatsApp nunca vería.

Las cuatro herramientas son reply (enviar texto), react (reacciones con emoji), mark_read (confirmaciones de lectura), y send_media (imágenes, documentos, audio, video). Aquí está la definición de la herramienta de respuesta:

{
  name: 'reply',
  description: 'Reply on WhatsApp. Pass chat_id (phone number) from the inbound message.',
  inputSchema: {
    type: 'object',
    properties: {
      chat_id: { type: 'string', description: 'Phone number to send to' },
      text: { type: 'string', description: 'Message text' },
      reply_to: { type: 'string', description: 'wamid to quote-reply to (optional)' },
    },
    required: ['chat_id', 'text'],
  },
}

Ciclo de polling con persistencia de cursor

El servidor MCP consulta el relay cada 2 segundos y reenvía los mensajes nuevos a Claude Code como notificaciones de canal:

const CURSOR_FILE = join(process.env.HOME || '/tmp', '.whatsapp-relay-cursor');
let cursor = loadCursor();

async function poll(): Promise<void> {
  try {
    const result = await relay(`/poll?since=${cursor}`);
    if (!result.ok) return;

    const { messages, cursor: newCursor } = result.data as {
      messages: InboundMessage[];
      cursor: number;
    };

    for (const msg of messages) {
      const meta = {
        chat_id: msg.from,
        wamid: msg.wamid,
        user: msg.pushName || msg.from,
        ts: new Date(msg.timestamp).toISOString(),
        type: msg.type,
      };

      mcp.notification({
        method: 'notifications/claude/channel',
        params: {
          content: msg.text ?? `(${msg.type})`,
          meta,
        },
      });
    }

    if (newCursor > cursor) {
      cursor = newCursor;
      saveCursor(cursor);
    }
  } catch (err) {
    process.stderr.write(`whatsapp channel: poll error: ${err}\n`);
  }
}

El cursor se guarda en disco (~/.whatsapp-relay-cursor), así que reiniciar el servidor MCP no reprocesa mensajes anteriores. Cada mensaje se convierte en una notificación de canal que Claude Code recibe como nueva entrada, incluyendo el número de teléfono del remitente, nombre visible, timestamp y tipo de mensaje como metadatos.

Paso 4: Registra el servidor MCP con Claude Code

Crea un archivo .mcp.json en la raíz de tu proyecto:

{
  "mcpServers": {
    "whatsapp": {
      "command": "node",
      "args": ["--import", "tsx", "whatsapp.ts"]
    }
  }
}

Eso es todo. Cuando Claude Code arranca en este directorio, detecta el servidor MCP, lo lanza como proceso hijo vía stdio, y el canal de WhatsApp queda disponible. Claude Code ahora recibe mensajes de WhatsApp como notificaciones de canal y puede llamar las herramientas reply, react, mark_read y send_media.

Paso 5: Configura el gateway de Arcade y conéctalo a Claude Code

Antes de que el asistente pueda acceder a herramientas de negocio, necesitas crear un gateway de Arcade que defina qué herramientas puede usar el agente y con qué permisos.

Entra al dashboard de Arcade, crea un nuevo gateway y agrega los servidores MCP de los servicios que tu asistente necesita: Google Calendar, Gmail, Slack y cualquier otro relevante para tus flujos de trabajo. Para cada servidor, selecciona solo las herramientas específicas a las que quieres que el agente acceda. Aquí es donde delimitas los permisos. Si la skill de preparación de reuniones solo necesita listar eventos del calendario y buscar correos, no tiene sentido exponer herramientas que eliminen eventos o envíen correos en tu nombre.

Una vez creado el gateway, regístralo con Claude Code desde la línea de comandos:

claude mcp add 'arcade-gateway' \
  --transport http 'https://api.arcade.dev/mcp/<your-gateway-slug>' \
  --header "Authorization: Bearer <your-arcade-api-key>" \
  --header 'Arcade-User-ID: <your-email>'

Esto escribe la configuración del gateway en ~/.claude.json. Claude Code ahora tiene dos servidores MCP: el servidor local del canal de WhatsApp (desde .mcp.json en el proyecto) y el gateway remoto de Arcade (desde ~/.claude.json). El servidor de WhatsApp maneja la mensajería. El gateway de Arcade gestiona el acceso a herramientas de negocio con autorización por acción.

El encabezado Arcade-User-ID le indica a Arcade qué credenciales de usuario usar al ejecutar llamadas a herramientas. En la configuración de un solo usuario, este es tu correo. En la arquitectura multiusuario descrita más adelante, el orquestador pasa un ID de usuario diferente por sesión.

Paso 6: Crea una skill de preparación de reuniones con herramientas de Arcade

Con el canal conectado, el asistente necesita capacidades. Aquí es donde las herramientas y las skills trabajan juntas. Arcade provee acceso seguro a herramientas de negocio (Google Calendar, Gmail, Slack), y las skills le indican al agente cómo usar esas herramientas para completar un flujo de trabajo específico.

Las skills en Claude Code son archivos markdown. Sin código, sin despliegues, solo un prompt estructurado que codifica experiencia del dominio. Esta es la estructura:

skills/
└── meeting-prep/
    └── SKILL.md

El archivo de skill tiene dos partes: un frontmatter que le dice a Claude Code cuándo activarla, y un cuerpo que define el flujo de trabajo. Aquí está la skill de preparación de reuniones:

---
name: meeting-prep
description: "Prepare briefings for upcoming customer meetings by reading
  your Google Calendar, identifying external/customer meetings (based on
  attendee email domains), then pulling relevant context from Gmail threads
  and Slack conversations."
---

# Meeting Prep

You are a meeting preparation assistant. Your job is to create concise,
actionable briefings for upcoming external meetings.

## Customer Directory
Read the centralized client registry at `$AGENT_DATA_DIR/clients.md`.
Use it to match calendar attendee domains to known customers, find the
correct Slack channel, and locate customer-specific data files.

## Phase 1: Discover (Find the Meeting)

- Search Google Calendar using `list_events` for the relevant time window
- Identify external meetings by checking attendee email domains
- Any attendee whose domain is NOT your organization signals an external meeting

## Phase 2: Gather (Pull Context from Email and Slack)

### Email Context (Gmail)
1. Search for recent threads involving external attendees (last 30 days)
2. Read the 3-5 most relevant threads, looking for decisions, action items, tone
3. Check the calendar event itself for agenda or documents

### Slack Context
1. If there's a dedicated customer channel, read recent messages there
2. Otherwise search by company name or contact names (last 2 weeks)
3. Look for internal context not in email: concerns, feature requests, deal status

## Phase 3: Brief (Deliver the Prep)

### Meeting Briefing: [Title]
**When:** [Date & Time]
**With:** [Attendees + roles/company]
**Meeting type:** [Quarterly review, Demo, Follow-up, Intro call]

**Quick Context:** 2-3 sentences on where things stand
**Recent History:** Chronological recap of last interactions
**Key Things to Know:** Open items, concerns, opportunities
**Suggested Talking Points:** 3-5 practical conversation starters
**People Notes:** Brief note on new stakeholders or unfamiliar attendees

La skill le indica al agente exactamente qué herramientas de Arcade usar (list_events, search_messages, read_thread), en qué orden, qué señales buscar en los resultados y cómo formatear la salida. La búsqueda en el directorio de clientes evita que el agente desperdicie tokens haciendo coincidencias difusas de nombres de empresas. Va directo al dominio de correo y canal de Slack correctos.

Cuando un usuario escribe “prepárame para mi reunión de las 2pm” en WhatsApp, Claude Code recibe el mensaje por el canal, activa esta skill, ejecuta el flujo de tres fases a través de las herramientas de Arcade y envía el resumen de vuelta por la herramienta de respuesta de WhatsApp. Todo el flujo, desde el mensaje de WhatsApp hasta el resumen estructurado, ocurre sin que el usuario salga del chat.

Paso 7: Ejecuta y prueba el asistente de WhatsApp localmente

Arranca todo en orden:

# Terminal 1: Start the relay server
cd whatsapp-relay
node --import tsx relay.ts
# → "whatsapp relay listening on :3000"

# Terminal 2: Expose the relay via ngrok
ngrok http 3000
# → Copy the https:// forwarding URL

# Terminal 3: Start Claude Code from the project root
cd whatsapp-assistant
claude --dangerously-load-development-channels server:whatsapp
# Claude Code discovers .mcp.json and launches the MCP server
# → "whatsapp channel: connected, polling http://localhost:3000 every 2000ms"

Registra tu webhook con Meta entrando a tu app en el Meta Developer Dashboard, luego ve a WhatsApp, Configuración, Webhook. Establece la URL de Callback como tu URL de ngrok más /webhook (p. ej., https://abc123.ngrok.io/webhook), establece el Verify Token con el valor de tu archivo .env y suscríbete a messages campo webhook.

Ahora envía un mensaje desde tu celular al número de WhatsApp Business. Deberías verlo pasar por el relay, entrar al servidor MCP y aparecer en Claude Code. Claude Code lo procesa y envía una respuesta por la misma cadena.

Prueba enviando “prepárame para mi próxima reunión.” La primera vez que Claude Code llama a una herramienta de Arcade (como leer tu calendario), Arcade imprime una URL de autorización en la terminal. Ábrela en tu navegador y autentícate con la cuenta correspondiente (Google, Slack, etc.). Esto se hace una sola vez por servicio. Después, Arcade gestiona la renovación de tokens automáticamente.

Si tienes configurada la habilidad de preparación de reuniones y Google Calendar / Gmail conectados a través de Arcade, recibirás un resumen estructurado directamente en WhatsApp.

De un usuario a muchos: qué cambia en la arquitectura

Todo lo anterior funciona para un solo usuario. Una instancia de Claude Code, un conjunto de credenciales de Arcade, un contexto de identidad. Esto es lo que falla cuando un segundo usuario le escribe al bot, y lo que hay que cambiar.

Por qué una sola instancia de Claude Code no funciona para varios usuarios

La configuración de un solo usuario tiene una suposición implícita: cada mensaje de WhatsApp es tuyo. Cuando Claude Code llama a una herramienta de Arcade como list_events, Arcade usa las credenciales que autenticaste durante la configuración. No hay identificador de usuario en la llamada.

Si el Usuario 2 le escribe al mismo bot, Claude Code sigue llamando a Arcade con tus credenciales. El Usuario 2 ve tu calendario. Peor aún, Claude Code corre en un único contexto de conversación. El resumen de reunión del Usuario 1 (términos del acuerdo, mensajes internos de Slack, cifras de ingresos) está en la ventana de contexto cuando llega el mensaje del Usuario 2. Una inyección de prompt del Usuario 2 podría exponer los datos del Usuario 1. Arcade protegió las credenciales correctamente, pero la ventana de contexto compartida rompe el aislamiento entre inquilinos.

Necesitas dos cosas: instancias de agente separadas para que el contexto nunca se mezcle entre usuarios, y enrutamiento de credenciales por usuario para que Arcade sepa de quién leer el calendario.

La arquitectura multiusuario

El servidor relay, los esquemas de herramientas MCP (reply, react, send_media) y las habilidades permanecen igual. Lo que cambia es la capa de orquestación.

La versión de un solo usuario usa el CLI de Claude Code con su función de canales integrada. Para multiusuario, construyes un orquestador personalizado con el Claude Agent SDK. El SDK no tiene soporte nativo de canales, pero ofrece sesiones, hooks, permisos de herramientas y conexiones MCP: los bloques de construcción para replicar lo que hacen los canales para un usuario, pero a escala de muchos.

El servidor relay se convierte en un enrutador. Cuando llega un mensaje de +1111, el orquestador identifica qué sesión de agente pertenece a ese número y le envía el mensaje. Cuando escribe +2222, lo dirige a otra sesión. Cada sesión tiene su propia ventana de contexto, su propia instancia del servidor MCP y su propio contexto de usuario en Arcade. Los datos nunca se cruzan.

El enrutamiento de credenciales funciona a través del parámetro user_id en las llamadas a herramientas. Cada usuario pasa por el flujo de autenticación en el navegador de Arcade una vez (el mismo paso de URL de autorización de la configuración de un solo usuario). Después, cuando el orquestador llama a una herramienta de Arcade en nombre del Usuario 2, pasa la identidad del Usuario 2. Arcade resuelve los permisos OAuth correctos, genera un token con alcance limitado para esa acción específica y ejecuta la llamada. La solicitud de calendario del Usuario 2 devuelve el calendario del Usuario 2. Para un recorrido completo de cómo funciona este modelo de autorización en distintos frameworks, consulta SSO para agentes de AI: Guía de autenticación y autorización.

La vinculación de identidades es directa. Mapea cada ID de remitente de WhatsApp a una identidad corporativa mediante un flujo de verificación único: envía un código por una Plantilla de Autenticación de WhatsApp, pide al usuario que lo confirme en un portal web y guarda el mapeo.

Arcade maneja el resto de la complejidad multiusuario: intercambio de tokens OAuth por usuario y permisos justo a tiempo para delegación de credenciales, ejecución de herramientas con alcance limitado que evita el acceso a datos entre inquilinos, un registro de herramientas con versiones que no se rompe cuando cambian las APIs externas, y registros de auditoría estructurados vinculados al usuario y la acción específicos. Son los mismos cuatro problemas de antes. Todos se complican a escala multiusuario, y Arcade los maneja de forma nativa.

Lista de verificación de preparación para producción de agentes de AI

Antes de salir del uso local, verifica estas cinco cosas:

  1. Aislamiento de credenciales. ¿Puede el LLM ver tus tokens de autenticación? Si la respuesta es sí, detente. La arquitectura necesita autorización justo a tiempo y por acción, donde el modelo nunca toca credenciales de larga duración. Los privilegios permanentes de cuenta de servicio no son una opción.
  2. Confiabilidad de herramientas. ¿Tus herramientas están optimizadas para agentes o son simples wrappers de REST? Si el modelo tiene que adivinar parámetros de payload complejos y hacer reintentos por fuerza bruta, tendrás fallas invisibles hasta que llegues a producción.
  3. Versiones y rollbacks. ¿Puedes actualizar una herramienta sin romper el asistente en ejecución? Si un cambio en una API externa tumba tu agente, necesitas un registro con versiones y períodos de deprecación seguros.
  4. Auditabilidad. ¿Puedes rastrear cada acción hasta la persona específica que la solicitó? Si no, fallas SOC2 e ISO27001. Necesitas registros inmutables con IDs de usuario, nombres de herramientas y parámetros sanitizados.
  5. Tiempo de los desarrolladores. ¿Tus ingenieros están construyendo la plomería de OAuth y la lógica de reintentos de webhooks, o están construyendo habilidades y flujos de trabajo? Si es lo primero, la arquitectura es demasiado de bajo nivel.

Siguientes pasos

Ahora tienes un asistente de WhatsApp funcional. Un relay que maneja los webhooks de Meta. Un servidor MCP que conecta con Claude Code. Una habilidad de preparación de reuniones que convierte “prepárame para mi reunión de las 2pm” en un resumen estructurado extraído de tu calendario, correo y Slack.

Lo interesante viene después. El relay y el servidor MCP son infraestructura que escribes una vez. Las habilidades son donde vive el valor continuo, y cualquier persona del equipo puede crearlas. La preparación de reuniones fue la primera que construí. Resúmenes de reportes de gastos, standups diarios, recordatorios de seguimiento con clientes: el mismo patrón, diferente archivo markdown.

Para despliegues multiusuario, el Claude Agent SDK te da los bloques para orquestar sesiones de agentes por usuario, con el relay enrutando mensajes y Arcade manejando la delegación de credenciales, el aislamiento por tenant y el registro de auditoría. Tú te enfocas en las skills, no en la infraestructura.

El código de esta guía está en GitHub. Fórkalo y construye algo útil.

FAQ

¿Qué es un asistente ejecutivo de AI siempre activo?

Un asistente siempre activo corre de forma continua e interactúa mediante canales de mensajería como WhatsApp o Slack. Mantiene el estado entre conversaciones y ejecuta acciones en herramientas de negocio de forma asíncrona, sin necesidad de tener un navegador abierto.

¿Cuáles son los riesgos de usar OpenClaw para un agente de AI?

Suelen depender de credenciales de máquina compartidas, scripts frágiles y wrappers de herramientas sin gobierno. Eso genera alto riesgo de filtración de tokens, llamadas poco confiables, context bloat y ausencia de auditoría para cumplimiento.

¿Cómo evitas que un agente tenga acceso total a los sistemas de la empresa?

Usa autorización por acción en runtime con grants de corta duración just-in-time (por ejemplo, intercambio de tokens OAuth). El agente nunca mantiene credenciales amplias ni duraderas, y cada acción se evalúa contra los permisos del usuario que la solicita.

¿Qué es Arcade y cómo protege el acceso del agente de AI a las herramientas?

Arcade es un runtime que se ubica entre un agente de AI y tus herramientas de negocio. En lugar de darle al agente credenciales almacenadas, Arcade evalúa cada llamada de herramienta contra los permisos del usuario que la solicita, genera un token just-in-time con alcance a esa acción, ejecuta la llamada y registra el resultado. También ofrece integraciones optimizadas para agentes que devuelven datos resumidos en lugar de respuestas crudas de la API. Para una descripción completa, consulta Cómo funciona Arcade.

¿Es seguro darle a un agente de AI acceso a mi Google Calendar y correo?

No si el agente guarda tokens OAuth de larga duración o API keys directamente. Una inyección de prompt o una dependencia comprometida puede filtrar esas credenciales y acceder a todo lo que el agente puede alcanzar. La alternativa segura es la autorización por acción: un runtime como Arcade genera un token de corta duración y alcance limitado para cada acción específica, y lo revoca de inmediato, reduciendo el radio de daño a una sola llamada.

¿Cómo maneja el relay server los webhooks duplicados de WhatsApp?

WhatsApp entrega eventos con semántica de al-menos-una-vez. El relay responde 200 OK de inmediato (incluso ante firmas incorrectas) para evitar tormentas de reintentos, y procesa los mensajes de forma asíncrona. Para producción, agrega un store de deduplicación como Redis con clave por ID de mensaje.

¿Qué es la ventana de mensajería de 24 horas de WhatsApp?

Las respuestas de formato libre están permitidas dentro de las 24 horas posteriores al último mensaje del usuario. Los mensajes proactivos fuera de esa ventana deben usar plantillas de mensaje preaprobadas por WhatsApp (plantillas HSM). Para un resumen matutino a las 8 AM, necesitarías una plantilla aprobada.

¿Puedo usar esta arquitectura con modelos distintos a Claude?

Sí. El relay server y el protocolo MCP son agnósticos al modelo. El relay maneja el I/O de WhatsApp y el servidor MCP define herramientas mediante un protocolo estándar. Puedes reemplazar Claude Code por cualquier runtime compatible con MCP.

¿Cómo agrego nuevas skills o flujos de trabajo a un agente de Claude Code?

Crea un nuevo directorio dentro de skills/ con un archivo SKILL.md. La descripción en el frontmatter de la skill le indica a Claude Code cuándo activarla. Las skills son solo prompts estructurados, sin necesidad de desplegar código.