- Inicio
- Servidor MCP
Outreach por DM en TikTok desde tu LLM
El servidor MCP de Hooka da a Claude, ChatGPT, Cursor o tu propio agente 26 herramientas sobre la API de Hooka. Con ellas puede conectar cuentas de TikTok por QR, crear y lanzar campañas de DM, llevar el inbox y gestionar tu lista No contactar. Usa el servidor alojado en mcp.hooka.to (inicia sesión con OAuth o manda una API key), o ejecútalo en local por stdio con npx hooka-mcp.
¿Qué es el servidor MCP de Hooka?
El servidor MCP de Hooka es un servidor Model Context Protocol. Expone la API REST v1 de Hooka como herramientas que tu LLM puede invocar. Cada herramienta corresponde a un único endpoint de https://api.hooka.to/v1 y reenvía tu propia credencial (una API key o un token OAuth). El servidor no guarda credenciales, y se aplican los mismos límites del servidor que si llamaras a la API directamente.
Además de las llamadas a la API, el servidor hace algunas cosas por el modelo:
- Devuelve el QR de conexión como imagen, para que el asistente te lo enseñe.
- Manda una clave de idempotencia en las herramientas de escritura que la admiten, para que un reintento no cree una segunda campaña ni envíe un segundo DM.
- Convierte los errores de la API en una línea legible con el código de error, el campo culpable y el id de la petición.
Los títulos y descripciones de las herramientas, las instrucciones del servidor, los prompts, los resources y las notas y errores que genera el propio servidor (falta la clave, timeout, error de red) están en español. Elegir un prompt añade un mensaje en español a la conversación. Los errores que devuelve la API de Hooka llegan tal cual, en inglés, igual que los de validación del esquema (-32602).
¿Cómo conecto Hooka a Claude, ChatGPT o Cursor?
Hay tres formas de conectarlo. Todas dan acceso a las mismas 26 herramientas:
| Opción | Dónde se ejecuta | Credencial | Clientes habituales |
|---|---|---|---|
| Alojado + OAuth | https://mcp.hooka.to/mcp (Streamable HTTP) | Inicias sesión en Hooka y apruebas el acceso | Claude.ai, Claude Desktop (conectores), ChatGPT |
| Alojado + API key | https://mcp.hooka.to/mcp (Streamable HTTP) | Cabecera Authorization: Bearer hk_live_… | Claude Code, Cursor, agentes propios |
| Local | Tu máquina, por stdio (npx hooka-mcp, Node.js 20+) | Variable de entorno HOOKA_API_KEY | Fichero de config de Claude Desktop, Cursor, cualquier cliente stdio |
Alojado, con OAuth (Claude.ai, Claude Desktop, ChatGPT)
Añade Hooka como conector personalizado y pega esta URL. No hay nada que instalar ni clave que copiar:
https://mcp.hooka.to/mcp
El cliente descubre el servidor de autorización de Hooka, se registra y te lleva a Hooka para iniciar sesión y aprobar el acceso (OAuth 2.1, con PKCE S256 obligatorio). Después aparecen las herramientas. Conviene saber algunos detalles:
- La aprobación da acceso completo a tu workspace, igual que una API key live. La única excepción es la gestión de API keys, que los tokens OAuth no pueden hacer.
- Los tokens de acceso duran 30 minutos. El cliente los renueva con un refresh token, que dura 60 días y rota en cada uso.
- La pantalla de inicio de sesión y consentimiento está solo en español.
Alojado, con API key (Claude Code, Cursor, agentes propios)
Los clientes que pueden mandar cabeceras HTTP pueden saltarse OAuth y mandar tu clave. En Claude Code:
claude mcp add --transport http hooka https://mcp.hooka.to/mcp --header "Authorization: Bearer hk_live_..."
En Cursor (mcp.json) y otros clientes que usan el formato url + headers:
{
"mcpServers": {
"hooka": {
"url": "https://mcp.hooka.to/mcp",
"headers": { "Authorization": "Bearer hk_live_..." }
}
}
}
El servidor alojado no comprueba la clave al conectar. Con una clave inválida o revocada, las herramientas aparecen igual, y luego cada llamada devuelve 401 authentication_error/invalid_api_key. Para comprobar la configuración, pide al asistente que llame a get_workspace.
En local, por stdio (npx)
El paquete npm hooka-mcp ejecuta el mismo servidor en tu máquina, por stdio. Añade esto a la config MCP de tu cliente:
{
"mcpServers": {
"hooka": {
"command": "npx",
"args": ["-y", "hooka-mcp"],
"env": { "HOOKA_API_KEY": "hk_live_..." }
}
}
}
En Claude Desktop va en claude_desktop_config.json. Ese fichero solo carga servidores locales, así que para la URL alojada usa un conector. En Cursor, usa el mismo command, args y env. Necesita Node.js 20 o superior. El servidor local lee estas variables de entorno:
HOOKA_API_KEY(obligatoria): tu clave. Sin ella el servidor arranca, pero cada herramienta devuelve un error pidiéndola.HOOKA_API_BASE(opcional): la URL base de la API. Por defecto,https://api.hooka.to.HOOKA_API_TIMEOUT_MS(opcional): el timeout de cada llamada a la API. Por defecto,30000.
Esta página documenta hooka-mcp 0.3.0, la versión del servidor alojado. Las versiones 0.1.x anteriores tienen 23 herramientas y no traen el QR como imagen, la herramienta de verificación ni el comportamiento de reintentos que se describe aquí. Antes de ejecutarlo en local, comprueba qué versión va a bajar npx con npm view hooka-mcp version. Si sale una 0.1.x, la 0.2.0 aún no está en npm: usa el servidor alojado hasta que lo esté. Al conectar, el servidor también comunica su versión a tu cliente (serverInfo).
¿Qué credencial debe usar el agente?
| Credencial | Cómo se obtiene | Qué puede hacer el agente |
|---|---|---|
hk_live_… | La página Developers de tu panel de Hooka (siempre crea claves live), o POST /v1/api_keys | Leer y escribir: acciones reales sobre tus cuentas reales de TikTok |
hk_test_… | POST /v1/api_keys con {"mode":"test"}, autenticado con una clave live | Solo lectura: toda herramienta que escribe devuelve 403 permission_error/test_key_read_only |
| Token OAuth | Se emite al aprobar el conector (solo servidor alojado) | Leer y escribir, como una clave live. No puede gestionar API keys. |
No hay sandbox. Una clave de prueba lee tu workspace real; no simula envíos. Va bien cuando el agente solo debe mirar: informes, resúmenes del inbox, stats de campañas. Para crear una, llama a la API con una clave live:
curl https://api.hooka.to/v1/api_keys \
-H "Authorization: Bearer hk_live_..." \
-H "Content-Type: application/json" \
-d '{"mode":"test","label":"agente solo lectura"}'
{
"id": "key_6a1e…",
"object": "api_key",
"mode": "test",
"prefix": "hk_test_1a2b3c",
"secret": "hk_test_1a2b3c…"
}
El secret se muestra una sola vez. Con una clave de prueba funcionan las lecturas, incluida get_workspace. Toda escritura falla igual, sea cual sea la herramienta:
403 permission_error/test_key_read_only: Test keys (hk_test_) are read-only: Hooka has no sandbox, so any write would act on your real TikTok accounts. Use an hk_live_ key to create, start or send. [request_id req_…]
Todas las claves y tokens OAuth de un workspace comparten su límite de 300 peticiones a la API por minuto, junto con el tráfico directo a la API.
¿Qué puede hacer el agente? Las 26 herramientas
Cada herramienta llama a un endpoint de la API v1 de Hooka. Las de lectura llevan la anotación MCP readOnlyHint. Las marcadas como destructivas llevan destructiveHint porque envían DMs reales, cortan conexiones o vuelven a permitir el contacto. Los clientes que respetan las anotaciones pueden preguntarte antes de ejecutarlas.
| Herramienta | Qué hace | Llamada a la API | Tipo |
|---|---|---|---|
| Senders (cuentas de TikTok) · 7 | |||
list_senders | Todas las cuentas de TikTok (senders) del workspace, en cualquier estado, con status_reason, health, daily_limit y sent_today. Filtro status opcional. | GET /v1/senders | lectura |
get_sender | Un sender. Es la herramienta que se consulta durante una conexión: mientras connection.status es requires_scan, el QR llega como imagen. | GET /v1/senders/{id} | lectura |
create_sender | Inicia la conexión de una cuenta de TikTok por QR (sin contraseña). country es el país de la cuenta: recibe su propia IP residencial dedicada de allí, y el país no se puede cambiar después. Devuelve el sender en awaiting_scan, todavía sin QR. Ocupa una plaza y cancela cualquier otra conexión en curso del workspace. | POST /v1/senders | destructiva |
refresh_sender_connection | Un intento de conexión nuevo (QR nuevo) para un sender que no está conectado: caducado, desconectado, en cooldown o baneado. Conserva la IP propia del sender. | POST /v1/senders/{id}/connection/refresh | destructiva |
verify_sender_connection | Completa el paso "Verifica que eres tú" que TikTok pide tras escanear: elige correo o teléfono, manda el código o pide otro. | POST /v1/senders/{id}/connection/verify | escritura |
update_sender | Cambia la etiqueta de un sender, el único campo que la API puede editar. | PATCH /v1/senders/{id} | escritura |
delete_sender | Desconecta una cuenta. El sender sigue en la lista como disconnected y libera su plaza. También cancela una conexión por QR en curso de ese sender. Las campañas running que se quedan sin ningún sender conectado se pausan, y los seguimientos pendientes que solo podía enviar esta cuenta se omiten (sender_unavailable). | DELETE /v1/senders/{id} | destructiva |
| Campañas · 8 | |||
list_campaigns | Campañas, de la más nueva a la más antigua. Las archivadas no aparecen. | GET /v1/campaigns | lectura |
get_campaign | Una campaña con stats en vivo: pending, processing, sent, failed, skipped, replied, reply_rate. | GET /v1/campaigns/{id} | lectura |
create_campaign | Crea un borrador. Admite un mensaje o hasta 20 variantes, hasta 10 seguimientos, hasta 1.000 destinatarios, hasta 10 senders y ajustes de ritmo. No envía nada. | POST /v1/campaigns | escritura |
add_targets | Añade hasta 1.000 destinatarios por llamada. En una campaña running empiezan a recibir DMs en segundos. Una campaña completed se reabre (resumed: true) si alguno de sus senders está conectado. Si no hay ninguno, la respuesta trae resume_blocked_reason: "no_connected_sender": reconecta un sender y llama a start_campaign o resume_campaign. | POST /v1/campaigns/{id}/targets | destructiva |
list_targets | Destinatarios en orden de alta, con su estado y un código error estable si falló o se omitió. Filtro status opcional. | GET /v1/campaigns/{id}/targets | lectura |
start_campaign | Arranca el envío de DMs reales. Vale para un borrador (draft), una campaña paused o una completed que aún tiene destinatarios pendientes. | POST /v1/campaigns/{id}/start | destructiva |
pause_campaign | Pausa una campaña running. Un DM que ya se está enviando puede llegar a salir. | POST /v1/campaigns/{id}/pause | escritura |
resume_campaign | Reanuda el envío de una campaña paused, o de una completed que aún tiene destinatarios pendientes. | POST /v1/campaigns/{id}/resume | destructiva |
| Inbox · 4 | |||
list_conversations | Conversaciones por actividad más reciente. Filtros status y sender_id opcionales. | GET /v1/conversations | lectura |
get_conversation | Una conversación: qué sender, la otra persona, estado, no leídos y último mensaje. | GET /v1/conversations/{id} | lectura |
get_messages | Los mensajes de una conversación, del más antiguo al más nuevo (in = la otra persona, out = tú). | GET /v1/conversations/{id}/messages | lectura |
send_reply | Encola una respuesta de 1 a 2.000 caracteres. Sale como DM real desde el sender de la conversación en segundos. | POST /v1/conversations/{id}/messages | destructiva |
| Lista No contactar · 3 | |||
list_suppressions | Los usernames a los que nunca se debe escribir, con su reason (manual, opt_out…). | GET /v1/suppressions | lectura |
add_suppressions | Añade de 1 a 1.000 usernames. Sus destinatarios pendientes en todas las campañas se omiten en el acto. | POST /v1/suppressions | escritura |
remove_suppression | Quita un username. Eso puede volver a permitir DMs a alguien que pidió que no le escribieran. | DELETE /v1/suppressions/{username} | destructiva |
| Eventos, webhooks y workspace · 4 | |||
list_events | Eventos del workspace, los mismos que llegan por webhook, guardados 30 días. Recórrelos del más nuevo al más antiguo, o consulta los nuevos con after. | GET /v1/events | lectura |
list_webhook_endpoints | Tus endpoints de webhook, sin sus secrets. | GET /v1/webhook_endpoints | lectura |
create_webhook_endpoint | Crea un endpoint (URL https:// pública). Devuelve el secret de firma whsec_… una sola vez. | POST /v1/webhook_endpoints | escritura |
get_workspace | Whoami: id del workspace, país por defecto de las cuentas nuevas (exit_ip.region) y plazas. | GET /v1/workspace | lectura |
Las listas paginadas admiten limit (1-100, por defecto 50) y starting_after (el next_cursor de la página anterior). Pásalo mientras has_more sea true. list_webhook_endpoints no pagina.
Ejemplos
Conectar una cuenta de TikTok
Dices: "Conecta mi cuenta de TikTok y ponle la etiqueta Tienda ES." El agente sigue estos pasos:
get_workspace: comprueba que queda una plaza libre (seats.used < seats.limit; unlimitnullsignifica sin tope) y lee el país por defecto (exit_ip.region). Si la cuenta es de otro país, el agente te lo pregunta.create_sender {"label":"Tienda ES","country":"ES"}: el sender vuelve enawaiting_scanconconnection.status"pending"y todavía sin QR. La cuenta recibe su propia IP residencial dedicada de ese país; mientras se prepara,exit_ip.statuses"provisioning".get_sendercada 3-5 segundos.connection.statuspasa porpending,requires_scan,scanned, a vecesverification_required, y termina con el senderconnected.- En
requires_scan, el resultado de la herramienta trae el QR como imagen y lo escaneas con la app de TikTok. El QR se renueva solo; el agente te enseña siempre el último. - En
verification_required, te pregunta dónde quieres recibir el código y cuál es. Luego llama averify_sender_connection, por ejemplo{"id":"snd_…","action":"submit_code","code":"482913"}.
Así se ve un resultado de get_sender con el QR listo (resumido):
{
"content": [
{ "type": "text", "text": "{ \"id\": \"snd_…\", \"object\": \"sender\", \"status\": \"awaiting_scan\", \"connection\": { \"status\": \"requires_scan\", \"qr_code\": \"[QR adjunto como imagen en esta respuesta: …]\", … } }" },
{ "type": "image", "data": "iVBORw0KGgo…", "mimeType": "image/png" }
]
}
El intento ha fallado si connection.status pasa a expired o failed (connection.error dice por qué), o si el sender pasa a disconnected (status_reason dice por qué). El agente deja de consultar y puede ofrecer refresh_sender_connection para un QR nuevo. Conecta las cuentas de una en una, porque cada intento nuevo cancela el que esté en curso.
Crear una campaña y arrancarla solo cuando confirmes
Dices: "Prepara una campaña para estos dos creadores con un seguimiento a los 3 días, 90 segundos entre DMs y como mucho 40 al día." El agente llama a:
{
"name": "create_campaign",
"arguments": {
"name": "Creadores ES - octubre",
"message": {
"variants": [
"Hola {{first_name}}, me encantó tu último vídeo. ¿Te interesa una colaboración pagada?",
"Hola {{first_name}}, buscamos creadores como tú. ¿Te lo cuento?"
]
},
"follow_ups": [
{ "wait_days": 3, "variants": ["{{first_name}}, ¿pudiste ver mi mensaje?"] }
],
"targets": [
{ "username": "@maria.ugc", "variables": { "first_name": "María" } },
{ "username": "@leo_creates", "variables": { "first_name": "Leo" } }
],
"settings": { "rate_limit_seconds": 90, "daily_limit": 40 }
}
}
El resultado es la campaña con "status": "draft", más targets_accepted, target_ids y targets_skipped. En este punto no se ha enviado nada. Algunas notas sobre los argumentos:
- Sin
settings.sender_ids, la campaña usa hasta 10 de los senders conectados más antiguos del workspace. daily_limitlimita la campaña entera por día. Cada cuenta mantiene además su propio tope diario.- Los seguimientos salen desde la misma cuenta que envió el primer DM y se paran cuando la persona responde.
Después, el agente te enseña un resumen y te pregunta antes de llamar a start_campaign {"id":"cmp_…"}. Se lo piden tanto las instrucciones del servidor como el prompt launch_campaign.
Triar el inbox con una clave de solo lectura
Con una clave hk_test_, el agente puede usar list_conversations {"status":"open"} y get_messages, clasificar las respuestas en interesado, pregunta, no interesado o spam, y redactarte respuestas. No puede enviarlas: send_reply devuelve 403 test_key_read_only. Tú revisas los borradores y los envías, o cambias a una clave live.
Ver qué pasó durante la noche
"¿Qué ha pasado en mis campañas desde ayer?" El agente lee list_events, por ejemplo con type igual a target.replied o sender.status_changed, y get_campaign para las stats. El resource hooka://event-types explica qué significa cada tipo de evento.
Prompts, resources e instrucciones del servidor
Prompts (flujos guiados que el usuario puede elegir en los clientes que los admiten):
launch_campaign(argumento opcionalgoal). Comprueba que hay una cuenta conectada, propone un mensaje con 2-3 variantes y seguimientos, crea el borrador y te pide confirmación explícita antes destart_campaign.triage_inbox. Recorre las conversaciones abiertas, las clasifica y redacta respuestas breves. Espera tu OK antes de cualquiersend_reply.connect_account(argumento opcionallabel). Sigue el flujo de QR de arriba, incluido el paso de verificación de TikTok.
Resources (texto de solo lectura; no llaman a la API, así que funcionan con cualquier clave):
hooka://event-typesrecoge los 12 tipos de evento de webhook másping, con lo que significa cada uno.hooka://api-referencecubre la URL base, los prefijos de id, la paginación, la idempotencia, el formato de error y el límite de peticiones.
Las instrucciones del servidor se envían en initialize. Cubren lo siguiente: que las claves de prueba son de solo lectura, qué herramientas envían DMs reales y necesitan tu confirmación, el flujo de conexión, la paginación, la idempotencia y el formato de error.
¿Qué no puede hacer el agente?
El servidor MCP solo puede hacer lo que permite la API. Algunas cosas son solo del panel o no están expuestas:
- Pago, plan y país por defecto. La suscripción y el país por defecto se cambian en el panel;
get_workspacesolo los lee. El país de cada cuenta se fija concreate_sendery no se puede cambiar después (soporte de Hooka puede moverla). - Tope diario por cuenta y calentamiento. Solo se cambian en el panel. El tope es de 30 DMs al día por cuenta por defecto (ajustable hasta 100). El
daily_limitde una campaña no puede subirlo. - Editar campañas. Ningún endpoint edita, archiva ni borra una campaña. Por la API, el mensaje, los seguimientos y los senders de una campaña no cambian después de crearla (el editor de campañas del panel sí puede cambiarlos).
- Estado de las conversaciones.
open,interestedy los demás estados son de solo lectura por la API. - Mantenimiento de webhooks. Probar, editar o borrar un endpoint, y leer un evento suelto por id, existen en la API pero no como herramientas.
- API keys. No hay herramienta para ellas. Los tokens OAuth reciben
403 oauth_token_not_alloweden las rutas de claves. - Automatizaciones de comentario a DM. Se gestionan en el panel y no están expuestas por la API.
- Ajustes que no existen.
create_campaign.settingses estricto, así quesender_pool,stop_on_replyo cualquier otra clave desconocida da un error de validación. Los seguimientos siempre se paran cuando la persona responde. - Otras plataformas. Solo TikTok.
- Notificaciones push. El servidor alojado no guarda estado y no envía notificaciones. Consulta
list_eventso crea un endpoint de webhook para tu backend.
Qué significa "enviado". send_reply responde {"id":"rpl_…","object":"message","status":"queued"}, y el DM sale en segundos. Un destinatario cuenta como sent cuando TikTok aceptó el mensaje y no mostró ningún aviso de "no entregado" en los segundos siguientes. No prueba que la persona lo haya leído. Si el envío no se puede confirmar, el destinatario queda failed con send_unconfirmed y no se reintenta nunca, para no duplicar el DM.
¿Es seguro dejar que una IA mande DMs?
Cuatro acciones envían DMs reales e irreversibles: start_campaign, resume_campaign, send_reply, y add_targets sobre una campaña running o completed. Las instrucciones del servidor piden al modelo tu confirmación explícita antes de cada una.
Ocho herramientas llevan la anotación destructiveHint:
- las cuatro anteriores;
create_senderyrefresh_sender_connection, que cancelan otras conexiones en curso;delete_sender;remove_suppression, que puede volver a permitir el contacto con quien pidió la baja.
Que el cliente pregunte antes de una herramienta destructiva depende del cliente y de tu configuración.
Hooka aplica los mismos límites a cualquiera que lo use, sea el panel, la API o el MCP:
- Un tope diario por cuenta.
- Espaciado entre DMs de la misma cuenta:
rate_limit_seconds, 30-3600, 60 por defecto. - Un tope diario opcional por campaña.
- Seguimientos que se paran cuando la persona responde.
- Deduplicación entre campañas (activada por defecto).
- La lista No contactar.
Las cuentas se conectan por QR; Hooka nunca pide tu contraseña de TikTok.
Nota honesta: automatizar DMs en TikTok opera fuera de la API oficial de TikTok y tiene un riesgo real; ninguna herramienta puede prometer cero bans. El servidor MCP no cambia eso. Le da a tu LLM una forma estructurada de manejar Hooka con tu confirmación. Usa cuentas dedicadas al outreach y empieza con volúmenes bajos.
Reintentos, idempotencia y errores
Estas 10 herramientas de escritura aceptan un idempotency_key opcional y mandan siempre una cabecera Idempotency-Key:
create_sender,refresh_sender_connection,verify_sender_connectioncreate_campaign,add_targets,start_campaign,pause_campaign,resume_campaignsend_reply,create_webhook_endpoint
Cómo funciona la clave:
- Clave derivada. Sin
idempotency_key, la clave sale del nombre de la herramienta, los argumentos y la ventana fija de 10 minutos del reloj en curso (12:00-12:10, 12:10-12:20…). Una llamada idéntica en la misma ventana devuelve el resultado guardado con una nota en vez de ejecutarse otra vez. En la ventana siguiente se ejecuta de nuevo, aunque sea segundos después. Hay dos excepciones, en las que el MCP pasa a la siguiente clave de la serie (hasta 5 por ventana) y la llamada se ejecuta otra vez: que el resultado guardado fuera un error 4xx o, encreate_senderyrefresh_sender_connection, que aquel intento de conexión ya haya terminado (el sender ya no está enawaiting_scan, oconnection.statusesexpiredofailed). Así, repetir la misma llamada acreate_senderen la misma ventana, para otra cuenta después de que la primera se conectara, sí empieza una conexión nueva. Con unidempotency_keyexplícito no hay excepciones. - Timeouts y errores de red. El texto del error trae la clave exacta que se mandó, así que la llamada se puede reintentar con
idempotency_keyigual a esa clave: si la original terminó, recibes su resultado guardado en vez de una segunda ejecución; si sigue en curso, recibes409 idempotency_key_in_use(espera y reintenta con la misma clave). Una petición atascada más de 5 minutos se da por muerta y se ejecuta de nuevo. Hooka guarda las claves 24 horas. 409 idempotency_key_in_use. La petición original sigue en curso. Espera unos segundos y reintenta con la misma clave.- Repetir a propósito. Para pausar otra vez tras reanudar, o para pedir otro código de verificación, pasa un
idempotency_keynuevo. - Herramientas sin clave.
add_suppressions(idempotente por naturaleza),update_sender,delete_senderyremove_suppressionno mandan ninguna.
Los errores de las herramientas llegan con isError: true y una sola línea de texto:
<status> <type>/<code>: <message> (param: <field>) [request_id req_…]
409 conflict_error/invalid_campaign_state: Cannot start a campaign that is running. [request_id req_…]
400 invalid_request_error/no_sender_available: Cannot start this campaign: none of its senders is connected. Reconnect one (POST /v1/senders/{id}/connection/refresh) and retry. [request_id req_…]
429 rate_limit_error/rate_limited: Too many requests. Retry in 7 s. (Retry-After: 7 s) [request_id req_…]
El servidor valida los argumentos contra el esquema de cada herramienta antes de llamar a la API. Un argumento incorrecto devuelve MCP error -32602: Input validation error: …. Los argumentos desconocidos de primer nivel se descartan sin avisar. create_campaign.settings es la excepción: ahí una clave desconocida es un error. Cada llamada a la API tiene un timeout de 30 segundos, y en ese caso el error dice que la acción pudo aplicarse o no.
¿Puedo llamar al servidor alojado desde mi propio código?
Sí. https://mcp.hooka.to/mcp habla MCP Streamable HTTP en modo sin estado (stateless). Sigue estas reglas:
- Manda JSON-RPC con
POST /mcp.GETyDELETEdan 405, y no hayMcp-Session-Id. - Manda
Accept: application/json, text/event-stream. Sin los dos tipos, recibes 406. - Las respuestas llegan como server-sent events.
- Manda siempre un objeto
arguments, aunque esté vacío: untools/callsin él no pasa la validación.
curl -N https://mcp.hooka.to/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer hk_live_..." \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_workspace","arguments":{}}}'
event: message
data: {"result":{"content":[{"type":"text","text":"{\n \"id\": \"ws_…\",\n \"object\": \"workspace\",\n \"name\": \"Default\",\n \"created\": 1790726400,\n \"exit_ip\": {\n \"status\": \"ready\",\n \"region\": \"ES\",\n \"suggested_region\": null,\n \"per_sender\": true\n },\n \"seats\": {\n \"limit\": 3,\n \"used\": 1\n }\n}"}]},"jsonrpc":"2.0","id":1}
El resultado de una herramienta es un elemento de texto con el JSON de la API (con sangría), más un elemento de imagen cuando va un QR. Cuando la API no devuelve cuerpo, el texto es OK. En una llamada repetida (la misma llamada idempotente otra vez dentro de la ventana de 10 minutos de su clave, o un idempotency_key ya usado), el primer elemento de texto es una línea NOTA: …, el JSON va en el siguiente elemento de texto y no se adjunta la imagen del QR. En create_sender, refresh_sender_connection, verify_sender_connection, start_campaign, pause_campaign y resume_campaign, esa nota trae además el estado actual (Estado ACTUAL: …). Busca el elemento con el JSON en vez de dar por hecho que es content[0]. No hay structuredContent. Un cliente real suele llamar antes a initialize, para recibir las instrucciones del servidor.
Otros endpoints del servidor alojado:
GET https://mcp.hooka.to/healthdevuelve{"ok":true,"service":"hooka-mcp","version":"0.3.0","transport":"streamable-http"}.- Los clientes OAuth descubren el servidor de autorización en
/.well-known/oauth-protected-resource/mcp. El servidor de autorización eshttps://api.hooka.to. Admite registro dinámico de clientes y exige PKCE S256, y el recurso eshttps://mcp.hooka.to/mcp.
Si solo necesitas HTTP, puedes saltarte el MCP y llamar directamente a la API REST. Referencia completa: app.hooka.to/docs.html.
Preguntas frecuentes
¿Qué es el servidor MCP de Hooka?
Un servidor Model Context Protocol que expone la API v1 de Hooka como 26 herramientas, para que Claude, ChatGPT, Cursor o tu propio agente conecten cuentas de TikTok, creen y lancen campañas de DM, lleven el inbox y gestionen la lista No contactar en lenguaje natural. Cada herramienta llama a un endpoint de la API de Hooka con tu credencial, y el servidor no guarda credenciales. Esta página documenta la versión 0.2.0 (licencia MIT); las 0.1.x anteriores de npm tienen 23 herramientas.
¿Cómo conecto Hooka a Claude, ChatGPT o Cursor?
Alojado: añade https://mcp.hooka.to/mcp como conector personalizado en Claude.ai, Claude Desktop o ChatGPT e inicia sesión en Hooka (OAuth 2.1). En clientes que mandan cabeceras, como Claude Code y Cursor, usa la misma URL con Authorization: Bearer hk_live_.... En local: ejecuta npx -y hooka-mcp por stdio con HOOKA_API_KEY y tu clave (Node.js 20+). Las 26 herramientas necesitan hooka-mcp 0.2.0 o posterior: compruébalo con npm view hooka-mcp version.
¿Necesito una API key?
Con el conector OAuth, no: inicias sesión en Hooka y apruebas el acceso. La opción con cabecera y el servidor local sí necesitan una: crea una clave hk_live_ en la página Developers de tu panel. Las claves hk_test_ son de solo lectura: toda herramienta que escribe devuelve 403 permission_error/test_key_read_only.
¿Puedo probarlo sin enviar DMs reales?
No hay sandbox. Una clave hk_test_ deja al agente leer tu workspace real sin cambiar nada. Con una clave live, create_campaign solo crea un borrador y no se envía nada hasta start_campaign. Las herramientas que envían DMs reales son start_campaign, resume_campaign, send_reply, y add_targets sobre una campaña en marcha o terminada.
¿Es seguro dejar que una IA mande DMs en TikTok?
El servidor marca 8 herramientas como destructivas (envían DMs, cortan conexiones o vuelven a permitir el contacto), así que los clientes que respetan las anotaciones MCP pueden preguntarte antes, y sus instrucciones piden al modelo tu confirmación explícita antes de enviar. Hooka aplica los mismos límites a cualquiera que lo use: un tope diario por cuenta, espaciado entre DMs, seguimientos que se paran cuando la persona responde y la lista No contactar. Automatizar TikTok siempre tiene algún riesgo, así que revisa cada acción antes de confirmarla.
¿Puede el agente enseñarme el QR para conectar una cuenta?
Sí. create_sender inicia la conexión y el agente consulta get_sender cada 3-5 segundos. Cuando connection.status es requires_scan, el QR llega como imagen en el resultado de la herramienta y lo escaneas con la app de TikTok. Si después TikTok pide verificar que eres tú, el agente completa ese paso con verify_sender_connection y el código que recibes.
¿Cuánto cuesta?
El servidor MCP es gratis (licencia MIT). Para conectar cuentas de TikTok y enviar DMs hace falta una suscripción activa de Hooka, con precio por cuenta de TikTok conectada. Sin ella, create_sender devuelve 403 permission_error/no_active_subscription.
Sigue leyendo
La API REST detrás de cada herramienta: senders, campañas, destinatarios, inbox y webhooks.
docsReferencia completa de la APICada endpoint, campo, código de error y evento de webhook, con ejemplos.
preciosPrecios de HookaPor cuenta de TikTok conectada al mes. El servidor MCP es gratis.
Deja que tu LLM haga el outreach
Cancela cuando quieras. No pedimos tu contraseña de TikTok. Pago seguro con Stripe.