exray
exray es un servidor MCP remoto que renderiza páginas web y te permite registrar tu propio código TypeScript de scraping y extracción como herramientas reutilizables con nombre.
No ejecutas ni instalas exray. Es un servicio alojado en https://mcp.exray.dev/mcp. El usuario proporciona un token bearer; tú llamas a las herramientas a través de MCP.
Antes que nada: ¿está conectado?
Si las herramientas de exray no están en tu lista de herramientas, el servidor MCP no está configurado. Indica al usuario que:
- Se registre en
https://app.exray.dev/sign-in— la página/welcomeemite un token (mostrado una sola vez) - Añada el servidor a su cliente — la configuración está en https://docs.exray.dev/docs/mcp-clients
- Reinicie el cliente — la configuración MCP se lee al iniciar
No intentes solucionar la falta de conexión haciendo scraping con fetch o herramientas de shell. Di qué falta y detente.
Elegir una herramienta
| Situación | Herramienta |
|---|---|
| Una página, quieres el contenido | scrape |
| Una página, quieres campos específicos | extract con un esquema plano |
| Muchas páginas bajo un sitio | crawl, luego get_crawl_results |
| La misma extracción repetidamente, o lógica demasiado compleja para un esquema plano | escribe un define_extractor |
| La página necesita clics/scroll antes de renderizarse | escribe un define_fetcher |
| El usuario quiere ver los resultados | escribe un define_handler (página de resultados) |
Usa scrape / extract primero. Solo escribe código cuando una herramienta integrada no pueda expresar lo que se necesita — un activo registrado es algo que el usuario luego debe mantener.
Solo esquemas planos
extract acepta exactamente cuatro tipos: string, number, boolean, string[]. Sin anidamiento.
{ "title": "string", "price": "number", "tags": "string[]" }
Las formas anidadas o condicionales requieren un define_extractor.
Escribir activos de código
Tres tipos, todos TypeScript, todos validados estáticamente antes de ser aceptados:
- fetcher — entrada
fetch(ctx), controla el navegador, devuelve unPageSnapshot - extractor — entrada
extract(snapshot, ctx?), convierte una instantánea en JSON - handler — entrada
handle(request, ctx), sirve una página web pública
Restricciones estrictas — el código que las vulnera es rechazado al registrarse:
- La única importación permitida es
import typedesde@exray/exray-api. Sin importaciones en tiempo de ejecución. Si necesitas consultar el DOM, trabaja desdesnapshot.htmlcon manipulación de cadenas, o haz el trabajo DOM en un fetcher mediantectx.page.evaluate(). - No uses
eval/new Function, ni efectos secundarios de nivel superior. - Sin acceso a la red desde dentro del sandbox.
El registro deja el activo en estado draft; no puede ejecutarse aún. Llama a publish_definition antes de intentar usarlo. Esto confunde constantemente a los usuarios; no informes éxito solo después de define_*.
Páginas de resultados — lee next_action y actúa en consecuencia
Cuando publicas un handler, la respuesta incluye un objeto site. Publicar con éxito no significa que la página sea accesible. Siempre lee site.next_action e informa al usuario sobre lo que aún falta:
next_action | Qué decir al usuario |
|---|---|
set_username | "Establece un nombre de usuario en app.exray.dev/settings/profile — la dirección será <username>-<project>.exray.app" |
enable_site | "Tu página estará en <site.url>. Actívala: exray site enable, o en el panel de control." |
shorten_slug | "<username>-<slug> supera los 63 bytes. Usa un slug de proyecto más corto." |
contact_support | Un problema de configuración del lado del servidor; repórtalo como tal. |
null | Está activa en site.url — dale el enlace. |
Nunca finalices una publicación de handler sin decir dónde está la página o qué la bloquea. El usuario no tiene otra forma de saberlo, y "publicado con éxito" se interpreta como "está listo".
Lo que un handler puede y no puede hacer:
- Puede leer los datos de trabajos de este proyecto mediante
ctx.data(listar trabajos, obtener un resultado), devolver HTML o JSON, enrutar por ruta. - No puede almacenar nada, acceder a la red, aceptar envíos de formularios ni leer datos de otros proyectos.
Es una capa de presentación, no un backend.
Enlaces de almacenamiento
El código del agente no tiene persistencia por defecto. Si el proyecto tiene enlaces habilitados, los fetchers obtienen ctx.kv / ctx.db / ctx.storage; los extractors solo obtienen ctx.kv; los handlers obtienen los tres solo lectura.
Si una llamada lanza binding_not_enabled, el enlace no está activado; eso requiere un token de administrador (exray bindings set --kv on). Informa al usuario; tú no puedes activarlo.
Errores que vale la pena reconocer
| Error | Significado |
|---|---|
403 forbidden | El token carece de un ámbito. La ejecución necesita tools.execute, el registro necesita tools.define, la publicación necesita tools.publish, las acciones de cuenta necesitan admin. |
402 | Cuota mensual agotada. Detente e informa al usuario. |
definition_incompatible_api | El activo fue compilado contra una versión mayor diferente de @exray/exray-api. Vuelve a registrarlo. |
extractor_invalid / fetcher_invalid | La validación estática rechazó el código — normalmente una importación en tiempo de ejecución o un efecto secundario de nivel superior. |
binding_not_enabled | Ver enlaces de almacenamiento más arriba. |
concurrent_exceeded | Demasiadas llamadas en curso. Espera; no reintentes en un bucle cerrado. |
Ante budget_exceeded o 402, detente. Reintentar consume la cuota del usuario sin progreso.
Ámbitos
Un flujo de trabajo de primer scraping solo necesita tools.read + tools.execute. Registrar y publicar necesita tools.define / tools.publish. Cualquier cosa relacionada con la cuenta — emitir tokens, habilitar páginas de resultados, activar enlaces — necesita admin y es tarea del usuario, no tuya.
Documentación completa
https://docs.exray.dev — guía de inicio rápido, configuraciones de cliente, referencia de CLI, páginas de resultados, parámetros de herramientas y el contrato del extractor.