Servidor MCP
Servidor MCP
Usa FourA desde cualquier cliente Model Context Protocol (Claude Desktop, Claude Code, Cursor, Windsurf, VS Code) como cuatro herramientas nativas y seis prompts de flujo de trabajo. Sin código de integración, sin un cliente HTTP personalizado.
De código abierto en GitHub; en npm como @fouradata/mcp. Versión actual: 0.5.0.
Inicio rápido: stdio local (recomendado para Claude Desktop)
Obtén una clave en foura.ai/dashboard#api-keys (un clic, se muestra una vez al crearla, formato pk_live_...). Agrega esto en la configuración de tu cliente MCP:
{
"mcpServers": {
"foura": {
"command": "npx",
"args": ["-y", "@fouradata/mcp"],
"env": { "FOURA_API_KEY": "pk_live_..." }
}
}
}
Advertencia sobre Claude Desktop: cierra completamente Claude Desktop (
Cmd+Qen macOS) antes de editar el archivo de configuración. Si la aplicación sigue en ejecución, sobrescribirá tus ediciones con su configuración en memoria al salir.
El comando npx descarga @fouradata/mcp en el primer inicio y lo ejecuta como un subproceso de tu cliente MCP. No se necesita instalación global.
| Cliente | Dónde se encuentra la configuración |
|---|---|
| Claude Desktop (macOS) | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Claude Desktop (Windows) | %APPDATA%\Claude\claude_desktop_config.json |
| Claude Code | claude mcp add foura -- npx -y @fouradata/mcp (configura FOURA_API_KEY en env primero) |
| Cursor | ~/.cursor/mcp.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| VS Code (extensión MCP) | .vscode/mcp.json |
Reinicia el cliente. Las herramientas (foura_auto, foura_single, foura_proxy, foura_browser) y seis prompts aparecerán en tu lista de herramientas.
Inicio rápido: alojado (Streamable HTTP)
Para los clientes que soportan el transporte Streamable HTTP (Cursor, Windsurf, VS Code, Claude Code con --transport http), apúntalos al endpoint alojado en lugar de ejecutar un subproceso local:
{
"mcpServers": {
"foura": {
"url": "https://mcp.foura.ai/mcp",
"headers": {
"Authorization": "Bearer pk_live_..."
}
}
}
}
Para Claude Desktop, usa la configuración de stdio anterior o conecta el endpoint alojado a través de mcp-remote:
{
"mcpServers": {
"foura": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.foura.ai/mcp", "--header", "Authorization: Bearer pk_live_..."]
}
}
}
Referencia del endpoint alojado
| Propiedad | Valor |
|---|---|
| URL | https://mcp.foura.ai/mcp |
| Transporte | HTTP transmisible (POST /mcp, respuestas SSE) |
| Autenticación | Authorization: Bearer pk_live_... por request |
| MCP-Protocol-Version | Según @modelcontextprotocol/sdk (actualmente 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07) |
| Desafío 401 | WWW-Authenticate: Bearer realm="foura-mcp", resource_metadata="https://foura.ai/docs/mcp/server#auth" |
El servidor alojado no tiene estado. Cada request trae su propia clave, que el servidor reenvía a la API de FourA como X-API-Key. Una clave abre las cuatro herramientas.
Para protegerse contra la revinculación de DNS (CVE-2025-66414), el servidor valida el header Host (debe ser mcp.foura.ai o localhost) y el header Origin cuando está presente (lista permitida: mcp.foura.ai, claude.ai, app.cursor.sh, app.cursor.com). Las llamadas de servidor a servidor (curl, clientes MCP en modo puente stdio) no envían Origin y pasan directamente.
Herramientas
Las cuatro herramientas están anotadas como readOnlyHint: true y openWorldHint: true según la especificación MCP 2025-06-18. Los clientes que aprueban automáticamente herramientas de solo lectura confiables las llaman sin un modal de confirmación por request.
foura_auto es la opción predeterminada inteligente: dale una URL y devuelve el contenido, eligiendo el método de obtención por ti. Las otras tres son las primitivas de nivel inferior que orquesta; úsalas cuando quieras un control explícito.
foura_auto
Pásale una URL cuando quieras que FourA elija el método del request. Realiza intentos limitados a través de las rutas HTTP, proxy y de navegador disponibles. Pasa validate en objetivos protegidos para que la response deba contener contenido que identifique la página real. Si ningún intento satisface la validación, la herramienta devuelve un error en lugar de presentar una página de desafío como éxito.
La response incluye detalles de finalización en meta y, de forma predeterminada, una session reutilizable con proxy, cookies y userAgent. Para un seguimiento simple, llama a foura_single con session.proxy como proxy, serializa las cookies como un header Cookie y envía session.userAgent como el header User-Agent. Para la renderización con JavaScript, pasa los valores de sesión a los campos foura_browser coincidentes.
foura_single
Un request HTTP, y su response correspondiente. Refleja POST /api/single/ uno a uno.
Úsalo para páginas estáticas, API JSON y HTML renderizado en el servidor.
Cómo elegir qué navegador presentas
Un request presenta la versión más reciente de Google Chrome de forma predeterminada. Cuando un objetivo acepta un navegador y rechaza otro, configura browser (Chrome, Edge, Safari, Firefox o Tor), os (Windows, macOS, Android o iOS) o version, o bien pasa un id exacto profile:
{
"method": "GET",
"url": "https://example.com",
"browser": "Firefox",
"os": "Windows"
}
La versión más reciente gana cuando coinciden varios perfiles. Una combinación que no existe devuelve un error que enumera lo que está disponible, por lo que nunca se envía un request como un navegador que no elegiste. La selección necesita unblocker, que está activado por defecto. El catálogo se publica en GET /api/profiles y no necesita una clave de API.
Los mismos cuatro campos se encuentran dentro del objeto request de foura_proxy.
foura_proxy
Enruta un request HTTP a través de proxies rotativos con reintento automático. Úsalo cuando foura_single esté bloqueado o el objetivo requiera un país de salida específico.
Configura exitCountries con una lista de permitidos estricta de códigos de país de dos letras visibles para el objetivo, proporcionada por el usuario o por los requisitos del objetivo:
{
"maxTries": 5,
"exitCountries": ["CZ", "GB"],
"request": {
"method": "GET",
"url": "https://example.com/pricing",
"browser": "Chrome",
"os": "Windows"
}
}
Los valores se recortan, se pasan a mayúsculas y se deduplican. Los proxies con salidas desconocidas se excluyen y la request nunca recurre a un país no solicitado. La selección usa los últimos metadatos de país visibles por el destino, normalmente actualizados en diez minutos; no es una búsqueda de geolocalización en vivo durante la request. No deduzcas el país de servicio a partir de la dirección host del proxy.
Un éxito con scope devuelve exitCountry y el ID reusable proxy. Comprueba que exitCountry pertenece a la allowlist solicitada. Si el pool actual no tiene coincidencias, la herramienta devuelve code: "no_eligible_proxy" con el scope normalizado en details.exitCountries. Conserva ese scope y reintenta más tarde. Cámbialo o amplíalo solo cuando el usuario cambie explícitamente el requisito.
Si la página seleccionada luego necesita JavaScript, pasa el ID proxy devuelto a foura_browser.proxy para que el navegador reutilice la misma salida.
foura_browser
Sesión de navegador completa. JavaScript se ejecuta, el DOM se renderiza, las cookies regresan. Refleja POST /api/browser/.
Úsalo para apps de una sola página, contenido de carga diferida o páginas tras desafíos anti-bots que necesitan un navegador real para resolverse.
Para formas de entrada, valores por defecto y reglas de validación en cada herramienta, consulta la referencia del endpoint REST. Los esquemas de la herramienta coinciden con la API REST campo por campo, más la opción offload_large exclusiva de MCP (ver abajo).
Cuando un destino ejecuta una comprobación de bots
foura_single y foura_proxy devuelven defense cuando el destino ejecutó una comprobación de bots de camino al body. defense.solved: true significa que se cumplió la comprobación y data es la página real; false significa que el body podría ser una página de desafío. Reintenta con un navegador, os o versión diferente, o sube a foura_proxy o foura_browser, en lugar de tratar la página de desafío como contenido.
Respuestas tipadas
Toda respuesta de la herramienta incluye tanto content (resumen de texto legible por humanos) como structuredContent (JSON tipado validado contra el outputSchema de la herramienta). Cada herramienta tiene su propia forma única:
foura_auto:{ status, headers, data }de forma única másmeta({ rung, solved, attempts, credits }, siempre presente, donderunges uno decache,probe,proxy,browser,fail) y, por defecto,session({ proxy, cookies, userAgent }) para la repetición mediante las herramientas de nivel inferior. Sintotal_time.foura_single:{ status, headers, data, total_time, ... }(headers es un array, una entrada por salto de redirección)foura_proxy: igual que el único más{ proxy, total }; un éxito con scope también incluyeexitCountryfoura_browser: forma distinta{ status, headers: object, body, cookies, userAgent }(nota:bodypuede ser un string o un objeto según el content-type)
Los clientes que soportan structuredContent pueden pasar el objeto tipado directamente al LLM en lugar de exigirle que parsee el JSON desde la prosa.
Headers de response con valores múltiples
Los headers que aparecen varias veces (Set-Cookie, Link, WWW-Authenticate) regresan como arrays:
{
"headers": [
{
"result": { "version": "HTTP/2", "code": 200, "reason": "" },
"content-type": "text/html",
"set-cookie": ["a=1; Path=/", "b=2; Path=/"]
}
]
}
Esto importa para los sitios que establecen cookies de sesión + rastreo + consentimiento en una sola response (la mayoría del comercio electrónico).
Responses grandes: offload_large (por defecto: en línea)
Por defecto (desde la v0.2.0), los cuerpos completos de la response se devuelven en línea en structuredContent sin importar su tamaño. Esto funciona en cualquier cliente MCP sin configuración adicional.
Si tu cliente soporta MCP resources/read Y quieres ahorrar tokens en páginas grandes, pasa offload_large: true por cada llamada a la herramienta. Las responses >= 50 KB se escriben en el disco, se devuelven como un resource_link, y tu cliente obtiene el cuerpo solo cuando realmente lo necesita. Los payloads en caché caducan después de 1 hora.
{
"method": "GET",
"url": "https://en.wikipedia.org/wiki/Web_scraping",
"offload_large": true
}
| Cliente | offload_large: true |
|---|---|
| Claude Desktop | aún no, deja el valor predeterminado false |
| Claude Code, Cursor, Windsurf | compatible |
| Extensión MCP para VS Code | compatible |
Aislado por inquilino: cada clave de API obtiene su propio espacio de nombres (sha256(apiKey)[:16]). Solo la clave que almacenó un payload puede leerlo. Las lecturas entre diferentes inquilinos devuelven Payload not found sin revelar su existencia.
Prompts integrados
Seis plantillas de flujo de trabajo aparecen bajo /prompts en cualquier cliente MCP. Cada una acepta argumentos con nombre y devuelve un mensaje de usuario en plantilla que orquesta una o más herramientas.
| Prompt | Argumentos | Qué hace |
|---|---|---|
smart_fetch |
url, must_contain opcional, extract |
Auto fetch (elige el método, maneja la protección contra bots), y luego devuelve o extrae el contenido |
scrape_product_page |
url |
Browser fetch, y luego extrae el título del producto, precio, imagen, inventario y SKU en JSON |
extract_article |
url |
Single con proxy de respaldo, y luego elimina la navegación/anuncios y devuelve el artículo limpio en JSON |
monitor_pricing |
url, target_price opcional |
Proxy fetch, extrae el precio actual y lo compara con el objetivo |
check_endpoint_health |
url, expected_text opcional |
Single con validación estricta, devuelve accesibilidad y tiempos |
bulk_fetch_urls |
urls (separado por comas) |
Parallel single, respaldo automático a proxy por URL, devuelve solo metadatos |
Los prompts cuestan cero tokens cuando están inactivos. Solo los prompts invocados entran en el contexto del LLM.
Texto completo y prompts de respaldo manual: Recetas MCP.
Envoltorio de error
Cada error (isError: true) lleva un envoltorio structuredContent. Campos mínimos en cada error:
{
"service": "auto | single | proxy | browser",
"code": "rate_limited",
"error": "Rate limit exceeded"
}
En errores del upstream con estado HTTP, status también está presente. En errores de rate limit y capacidad, el envelope del upstream añade retryAfter, current.{concurrency, rpm} y limits.{maxConcurrency, maxRpm}. Consulta API Errors para ver la estructura REST subyacente.
Valores code estables:
| Code | HTTP | Significado | ¿Seguro reintentar? |
|---|---|---|---|
ssrf_blocked |
n/a | IP de destino en rango privado o reservado (RFC 5735, 6598, IPv6 reservado) | No, cambia la URL |
upstream_non_json |
varía | El upstream devolvió un body malformado | Quizás, investigar |
output_validation_failed |
n/a | outputSchema del servidor MCP rechazó la response del upstream (bug del servidor o estructura inesperada) |
Quizás, reportar |
bad_request |
400 | Estructura de entrada rechazada | No, corrige los argumentos |
auth_failed |
401 | Key faltante, inválida o desactivada | No, corrige la key |
forbidden |
403 | Autenticado pero no permitido | No, o cambia a foura_proxy |
not_found |
404 | Falta el destino o endpoint | No |
rate_limited |
429 | Límite de RPM alcanzado | Sí, espera retryAfter |
at_capacity |
503 | Límite de concurrencia alcanzado | Sí, espera retryAfter |
service_disabled |
503 | Ventana de mantenimiento o tu plan no incluye esta herramienta | Contactar soporte |
service_unavailable |
503 | 503 genérico | Sí, backoff corto |
upstream_error |
500+ | Upstream 5xx | Sí, backoff exponencial |
upstream_client_error |
4xx | Otro 4xx | Normalmente no |
upstream_unknown |
otro | Defensivo, no debería ocurrir en la práctica | Investigar |
no_eligible_proxy |
n/a | Ningún proxy coincide con el scope estricto exitCountries |
Reintentar luego; cambia el scope de forma explícita |
Los agentes LLM pueden leer code directamente para la lógica de reintento sin analizar texto. Guía de autenticación: Authentication.
Límites
- Body en línea por defecto. Con
offload_large: true, las responses >= 50 KB van a disco +resource_link(por inquilino, TTL de 1 hora). - Los destinos privados son rechazados (RFC 5735, RFC 6598, bloques reservados de IPv6) en la capa MCP. Solo se reenvían hosts públicos.
- Límite del body de request de 256 KB en requests
/mcpentrantes (los payloads reales de MCP son < 4 KB). - Los rate limits son aplicados por la API de FourA por servicio. Consulta Rate Limits.
Autoalojamiento
El código fuente completo del servidor es público en GitHub bajo @fouradata/mcp. Clona el repositorio, npm install, npm run build y ejecuta node dist/http.js para levantar tu propia instancia. Se ejecuta sin estado en un solo contenedor detrás de cualquier balanceador de carga.
Entorno configurable:
| Variable | Predeterminado | Propósito |
|---|---|---|
PORT |
3076 |
Puerto de escucha HTTP |
FOURA_API_BASE |
https://api.foura.ai/api |
URL base REST upstream de FourA |
FOURA_MCP_PAYLOADS_DIR |
/data/payloads |
Dónde se almacenan en caché en disco las respuestas >= 50 KB (con offload_large: true) |
FOURA_MCP_ALLOWED_HOSTS |
mcp.foura.ai,localhost,127.0.0.1,[::1] |
Lista de permitidos de hostname para el encabezado Host (defensa contra DNS-rebinding) |
FOURA_MCP_ALLOWED_ORIGINS |
https://mcp.foura.ai,https://claude.ai,https://app.cursor.sh,https://app.cursor.com |
Lista de permitidos de origin para clientes de navegador |
FOURA_MCP_RESOURCE_METADATA_URL |
https://foura.ai/docs/mcp/server#auth |
URL devuelta en WWW-Authenticate en un 401 |
El contenedor oficial se ejecuta como uid 1001 (no root). El montaje host bind de /data/payloads debe tener permisos de escritura para ese uid.
Escala horizontalmente detrás de cualquier balanceador de carga. Los clientes proporcionan su clave en cada request, por lo que no hay sticky session.