Convertir un Actor de Apify en herramienta de agente: lo que revela el JSON-RPC en crudo
Exponer un Actor al servidor MCP de Apify lleva dos minutos. Lo instructivo es lo que recibe el agente: emojis, HTML y un required vacío que ningún cliente muestra.

Convertir un Actor de Apify en herramienta para un agente es cuestión de añadir ?actors=lergassy/jobs-api a la URL del servidor MCP. Dos minutos. Lo interesante no es eso, sino lo que el servidor devuelve cuando el agente lo llama.
El autor del Actor, que tiene unos treinta publicados en la tienda de Apify, dedicó una tarde a invocar el suyo con JSON-RPC en crudo sobre HTTP, sin cliente intermedio, registrando cada respuesta. El Actor es Jobs API, que reúne ofertas de Indeed, LinkedIn y portales de empresas en un solo esquema. Nada de lo que sigue depende del sector: si tu Actor tiene más de tres entradas, te va a pasar lo mismo.
Cinco herramientas, cuatro son fontanería
El transporte es streamable HTTP: se hace POST de JSON-RPC y vuelven server-sent events. Hay dos cosas que salen bien o no funciona nada. La cabecera Accept tiene que nombrar application/json y text/event-stream a la vez, o el servidor rechaza la petición. Y el identificador de sesión llega en una cabecera de respuesta, no en el cuerpo.
Con la sesión abierta, tools/list devuelve cinco herramientas: get-actor-run, get-dataset-items, get-key-value-store-record, abort-actor-run y el propio Actor. Las otras cuatro son el andamiaje para arrancar, consultar, leer el dataset y matar una ejecución. Esa forma importa más adelante.
El esquema que lee el agente no es el que escribiste
El input_schema.json del autor tiene 23 propiedades. La definición que recibe el agente tiene 24: el servidor añade una propia.
Tres detalles le costaron tiempo. El primero, que los emojis y el HTML pasan tal cual. El icono de lupa del título y las etiquetas <code> de la descripción estaban pensados para el formulario de la consola de Apify, donde se renderizan; en una definición de herramienta son tokens que el agente paga y marcado que tiene que ignorar. Nadie los limpia. El esquema completo son 9.135 caracteres.
El segundo, que el servidor promociona el campo prefill a la descripción añadiendo Example values: [...]. Convierte una comodidad de consola en una instrucción, pero de paso convierte el relleno en documentación: los valores que el autor puso sin pensar son ahora el ejemplo que imita el modelo.
El tercero es que required está vacío, y eso es culpa suya. La definición le dice al agente que una llamada sin argumentos es válida, cuando el Actor no tiene ninguna búsqueda por defecto útil.
Un run en verde que no trajo nada
La primera llamada real devolvió SUCCEEDED en 3,297 segundos con cero elementos en el dataset. El mensaje del servidor avisaba de que los recuentos pueden ir con retraso justo al terminar. Los recuperó: items vacío, itemCount 0, exit code 0.
La causa tiene gracia. El Actor busca por defecto en el país us y el autor no lo pasó, así que buscó en el Indeed estadounidense ofertas en Berlín, y encontró las que cabía esperar. Con "country": "de", la misma llamada terminó en 7,874 segundos con 10 elementos y 44 campos disponibles.
Ahí está el problema de fondo para quien diseñe herramientas de este tipo: un run correcto y vacío es más difícil de detectar que un error. El agente no tiene forma de saber que el resultado no significa nada si el esquema no se lo dice, y el mensaje de éxito llega igual de verde en los dos casos.


