Un agente que lee la web solo es tan útil como la peor respuesta que le devuelven sus herramientas. Una página que vuelve medio vacía, un error que culpa a lo que no es o un enlace citado que nadie descargó cuentan igual. Entre el 29 de septiembre y el 22 de octubre publicamos 24 versiones de CrawlForge MCP, de la v6.12.1 a la v6.24.0, y casi ninguna añadió una función que pondrías en una landing page. Todas iban de una sola cosa: hacer de CrawlForge un servidor MCP de web scraping confiable, uno cuya salida un agente pueda usar sin que una persona la revise.
La mayoría de las correcciones salieron de dos barridos en vivo de las 31 herramientas contra sitios reales. El primero hizo unas 470 llamadas sobre la v6.21.1, y cada defecto lo reprodujo un segundo tester antes de corregirlo. El segundo cubrió la v6.22.3, con al menos tres sitios en vivo por herramienta. Este post es el registro de lo que cambió, agrupado según lo que cambia para ti.
Tabla de contenidos
- Qué se publicó, versión a versión
- Las llamadas fallidas no se cobran, en ningún sitio
- Una caché de páginas para lecturas repetidas
- Dos barridos en vivo hacia un servidor MCP de web scraping confiable
- Respuestas del agente que puedes comprobar
- Estado incrustado de más frameworks
- Automatización de navegador que espera a la página
- Seguridad: cada salto pasa por la guarda
- La búsqueda pasó a la Brave Search API
- Cambios incompatibles que revisar antes de actualizar
- Cómo actualizar
Qué se publicó, versión a versión
| Versión | Fecha | La versión en una línea |
|---|---|---|
| v6.12.1 | 2026-09-29 | Reintentos de scrape_with_actions desactivados por defecto; los bytes de las capturas de pantalla quedan fuera de los resultados inline |
| v6.13.0 | 2026-09-29 | Los snapshots esperan a que la página se renderice; las llamadas por encima del límite de navegadores hacen cola en vez de fallar |
| v6.14.0 | 2026-09-29 | Los snapshots ven dentro de shadow roots e iframes; consent: "reject" responde a los banners de cookies |
| v6.15.0 | 2026-09-29 | extract_embedded_state recibe escalate, keys_only, window_state y handles de resultado |
| v6.16.0 | 2026-10-03 | Estado de Nuxt 3, SvelteKit, YouTube, Remix, Inertia y Shopify; find; cada salto de redirección pasa el filtro |
| v6.17.0–6.17.1 | 2026-10-03 | Cada navegación de una cadena de acciones se revisa en busca de muros; AWS WAF identificado; credenciales de proxy ocultas |
| v6.18.0–6.18.1 | 2026-10-03 | extract_text y extract_links reciben la escalera de escalado; los fallos silenciosos pasan a ser errores |
| v6.19.0–6.19.2 | 2026-10-04 | Calidad de salida en las herramientas de texto; pistas de error según la causa; serp_rank con profundidad 30 |
| v6.20.0–6.20.1 | 2026-10-06 a 10-11 | Las rutas de archivos locales quedan fuera de los informes de uso; los clics respetan el Crawl-delay; npm audit limpio |
| v6.21.0–6.21.1 | 2026-10-19 | Búsqueda web sobre la Brave Search API; serp_rank marca los resultados señuelo; PDFs corregidos en el bundle .mcpb |
| v6.22.0–6.22.3 | 2026-10-19 | Primer barrido de las 31 herramientas: toda llamada fallida es gratis; agent debe tener fuente para las URLs que cita |
| v6.23.0–6.23.2 | 2026-10-21 | Segundo barrido y una nueva revisión de seguridad: tráfico del navegador a través de un proxy de guarda; MCP SDK 2.3.1 |
| v6.24.0 | 2026-10-22 | Caché de páginas por sesión, maxAge y fallos de ruta de extract_embedded_state con indicaciones precisas |
No se añadió ni renombró ninguna herramienta, y ningún precio de lista cambió. Cada línea de arriba sale del changelog del servidor, y el changelog del sitio web recoge las mismas entradas.
Las llamadas fallidas no se cobran, en ningún sitio
La mayoría de las APIs de scraping responden a la pregunta "¿se cobran las peticiones fallidas?" con una lista de códigos de estado. La respuesta de CrawlForge desde la v6.22.0 es más corta: una llamada fallida cuesta 0 credits, en el MCP server y en la API REST.
Antes de la v6.22.0, el MCP server cobraba la mitad del precio cuando había un error. Tres herramientas tenían además un problema más discreto: extract_structured, extract_with_llm y summarize_content devolvían success: false sin marcar el resultado como error, así que esas llamadas se facturaban completas y se registraban como éxitos. Ahora un fallo es cualquiera de estas tres cosas, y ninguna se factura:
- un resultado con
isErroractivado - un error lanzado
- un cuerpo con
success: falseen el nivel superior
Los rechazos ya eran gratis y lo siguen siendo. Un disallow de robots.txt, un host en la lista de bloqueo, un rechazo por SSRF o un muro anti-bot que frena todos los peldaños de un escalado no cuestan nada. Desde la v6.16.0 eso cubre también las cadenas de scrape_with_actions y browser_session que nuestro propio filtro de cumplimiento detuvo a mitad de camino. El bloque _cost, que informa de lo que se cobró por una llamada, aparece ahora también en structuredContent en las herramientas que declaran un esquema de salida, no solo en el resultado de texto, así que un agente puede leer su propio gasto sin analizar prosa.
Una caché de páginas para lecturas repetidas
Los agentes vuelven a leer páginas. Un modelo hace scraping de una página para obtener markdown, decide que necesita los metadatos y luego pide un solo valor del JSON incrustado, y eso son tres descargas de la misma URL. La v6.24.0 añade una caché de páginas por sesión para que la segunda y la tercera lectura cuesten menos y dejen tranquilo al sitio.
Una petición repetida de la misma página en menos de 10 minutos reutiliza la copia ya descargada y cuesta 1 credit, pida lo que pida esta vez: otros formatos, otra ruta JSON, otros selectores. Las llamadas en paralelo para una misma página comparten una sola petición. Cubre nueve herramientas: fetch_url, scrape, extract_metadata, extract_text, extract_links, scrape_structured, extract_embedded_state, extract_structured y extract_with_llm.
Lo que nunca se guarda en caché importa tanto como lo que sí:
- respuestas que no son 2xx, muros anti-bot y páginas de desafío
- respuestas marcadas con
Cache-Control: no-store - peticiones que llevan cabeceras
AuthorizationoCookie
Un acierto de caché sigue pasando las comprobaciones de la lista de bloqueo y de robots.txt, así que una página en caché nunca es una forma de saltarse las reglas de un sitio. El tamaño de la caché está limitado (CRAWLFORGE_PAGE_CACHE_MB, 64 por defecto; 0 la desactiva). Solo funciona en una instalación MCP local: está desactivada con --http y para las peticiones a través de la API REST.
Cuando necesites la página en vivo, dilo con maxAge (milisegundos). maxAge: 0 fuerza una descarga nueva:
{
"name": "scrape",
"arguments": {
"url": "https://example.com/pricing",
"formats": ["markdown"],
"maxAge": 0
}
}Cada resultado de esas nueve herramientas lleva cache: { state, fetchedAt, ageMs, note }, así que el agente sabe si está mirando una copia de hace 3 segundos o una recién descargada.
Dos barridos en vivo hacia un servidor MCP de web scraping confiable
Las correcciones de scrape y crawl_
Texto que se lee como la página
- Las páginas de listas conservan su texto. Readability tomaba al autor de un elemento de la lista por la firma del artículo, así que quotes.toscrape.com perdía "by Albert Einstein". Una página de lista en la que la extracción del contenido principal conserva menos del 60% del texto visible ahora recurre a la página completa. Esto llega a
scrape,extract_content,batch_scrape,crawl_deepyscrape_with_actions. - Los bloques ya no se sueldan entre sí. Un único aplanador de texto compartido sustituyó a varios, así que "July 2023If you…" se lee como dos líneas, y los enlaces escritos uno detrás de otro tienen cada uno su propia línea.
- Los bloques de código salen delimitados, con su lenguaje. El código de Sphinx en docs.python.org volvía como prosa escapada.
- Wikipedia conserva los encabezados de sus secciones y descarta los enlaces "[edit]".
Rastreos que terminan y cuentan con honestidad
crawl_deepresuelve los enlaces respecto a la página en la que terminó. docs.python.org/3/tutorial redirige a /3/tutorial/, y cada enlace a un capítulo se resolvía un nivel por encima y devolvía 404.- El análisis de enlaces ya no bloquea el servidor. En una página de 7.3 MB con 16 766 enlaces tardaba 50 segundos y dejaba sin recursos a todas las demás llamadas. Ahora tarda 0.5 segundos.
crawl_deepse detiene enmax_pages. Antes vaciaba primero todos los enlaces en cola: 232 segundos para 3 páginas en un sitio.map_siteincluye la URL de inicio, así que un sitio de una sola página devuelve 1 URL, no 0.
Extracción que dice lo que no pudo encontrar
extract_structureddevuelve todos los campos que pediste. Un valor que no encuentra esnully aparece en un nuevo arraymissing_fields, en lugar de que el campo desaparezca sin avisar.analyze_contentdeja de puntuar otros idiomas con fórmulas del inglés. Un texto en español había puntuado una queja clara con −0.08. El sentimiento usa ahora el léxico AFINN-165 con negación para el inglés, y devuelvenot_applicablepara otros idiomas, como ya hacía la legibilidad.summarize_contentintenta por defecto un resumen abstractivo de longitud media cuando hay un LLM disponible, y elimina las líneas de cookies y los menús de navegación antes de resumir.
Errores que nombran la causa
Un fallo de DNS se leía como un escueto fetch failed, y la pista del siguiente paso sugería stealth_mode, mandando al agente a un navegador stealth para descargar una errata. Ahora los errores llevan la causa (ENOTFOUND, ECONNREFUSED), y la pista dice que revises la URL. Un selector que no coincide con nada se informa como un fallo de selector que nombra el selector, no como un sitio lento. Las propias pistas dependen ahora de la clase de error (robots, lista de bloqueo, SSRF, 404, timeout, validación) en lugar de una pista genérica por herramienta.
Respuestas del agente que puedes comprobar
La herramienta agent responde a una pregunta a partir de la web abierta. Sus correcciones en este ciclo tratan de la procedencia, porque una respuesta solo es útil si puedes ver de dónde salió.
- Una URL citada debe venir de una fuente. Desde la v6.22.1, cada URL de una respuesta tiene que ser una página que el agente descargó, un enlace de una de ellas o algo escrito en su texto fuente. La que no lo es recibe una reescritura correctiva. La que sobrevive a la reescritura aparece en
provenance.unverified_urlsy en un aviso dentro de la respuesta. Antes, una respuesta con el título correcto de Hacker News y un enlace a una noticia de 2021 pasaba como verificada. - El agente puede enlazar el elemento exacto. Cada fuente aporta ahora hasta ocho de sus enlaces a la síntesis, así que "la noticia más destacada de hoy" llega con la URL de esa noticia.
- La fuente oficial gana los empates. Un empate en la votación de dominios promovía antes al sitio mejor posicionado, a menudo Wikipedia.
- "Última actualización" no es una fecha de lanzamiento. Una respuesta que da la fecha de actualización de una página como fecha de lanzamiento se corrige o se marca, en
provenance.update_dates. - Se ciñe a su límite de 120 segundos. Una ejecución del barrido había tardado 183 segundos. Una ejecución que llega al límite devuelve ahora
degraded: truecon la evidencia que tiene.
El precio no cambia: 8 credits, más 5 por cada reintento stealth que consigue su página, 18 como máximo.
Estado incrustado de más frameworks
Muchos sitios envían sus datos como JSON dentro del HTML, para que el framework de front-end los hidrate. extract_
- El
__NUXT_DATA__de Nuxt 3, decodificado en objetos comonuxt_data(antes volvía como un array de índices) - Los datos de SvelteKit como
sveltekit_data, y eldata-pagede Inertia comoinertia_page ytInitialDatayytInitialPlayerResponsede YouTube, así que una página de video devuelvevideoDetailscon una petición simple- Remix, el JSON de producto y los meta de analítica de Shopify, y las variables globales asignadas a un literal de JavaScript en lugar de JSON, leídas por un evaluador estático sin ejecutar código de la página
Tres parámetros hacen manejables los payloads grandes. find devuelve todas las propiedades con un nombre de clave dado, cada una con la ruta que puedes volver a pasar tal cual. keys_only devuelve dos niveles de claves con sus tipos en lugar de los datos. Por encima de max_inline_chars, el resultado es una vista previa más un handle que lees con read_
{
"name": "extract_embedded_state",
"arguments": {
"url": "https://shop.example.com/products/widget",
"find": "price"
}
}Una página con muro se puede volver a leer en el navegador stealth con escalate: true, que proyecta 7 credits y cobra 2 cuando la petición simple consiguió la página. Desde la v6.24.0, un path que no se resuelve devuelve las claves dos niveles por debajo del punto donde se detuvo, con un siguiente paso construido a partir de ellas. Antes, le decía al agente que volviera a leer el payload entero.
Automatización de navegador que espera a la página
scrape_
- Los snapshots esperan a que la página se asiente:
load(hasta 5 segundos) y luego una ventana tranquila sin cambios en el DOM durante 300 ms y sin peticiones en curso durante 500 ms (hasta 3 segundos). El snapshot de la página de inicio de Amazon pasó de 0 nodos a 236, cuadro de búsqueda incluido. - Los snapshots ven dentro de shadow roots e iframes, incluidos los de otro origen, gracias al snapshot de accesibilidad nativo de Playwright.
- Un elemento reemplazado se vuelve a encontrar. Cuando una página cambia un elemento después del snapshot (el cuadro de búsqueda de Wikipedia lo hace), la ref se busca una vez más por rol y nombre en lugar de fallar como desconectada.
- Los banners de cookies se responden por ti.
browserOptions.consent: "reject"ejecuta el rechazo de autoconsent de DuckDuckGo después de cada navegación. El diálogo de Sourcepoint de The Guardian tardó alrededor de un segundo. - Una ráfaga de llamadas hace cola en vez de fallar. "Maximum concurrent sessions (3) reached" desapareció. Las llamadas esperan hasta 60 segundos a que haya un navegador libre e informan de
queued_ms. - Los fallos cuestan menos tiempo.
maxRetriesvale ahora 0 por defecto, así que un clic sobre un selector inexistente con un timeout de 4 segundos falla en unos 4 segundos en lugar de 20.8. Los clics stealth en Camoufox pasaron de 12.5–20 segundos a 1.4.
Ahora se revisa cada navegación de una cadena en busca de muros anti-bot, no solo la página final. El resultado enumera cada una en navigations, con AWS WAF y F5 identificados junto a Cloudflare, DataDome y los demás. Para saber qué pasa después de un muro, el post de la v6.
Seguridad: cada salto pasa por la guarda
Un servidor de scraping descarga URLs que eligió un modelo, y ese modelo puede haberlas leído en una página hostil. La guarda SSRF existe desde la v5. Este ciclo cerró los caminos que la rodeaban:
- El tráfico del navegador pasa por un proxy de guarda. Desde la v6.23.0, cada contexto de navegador se conecta a través de un proxy de reenvío local que revisa cada conexión (saltos de redirección, iframes, subrecursos, fetch, XHR y WebSockets) y se conecta a la dirección que revisó, así que el DNS rebinding ya no se cuela por la ruta del navegador. Antes, una página que redirigía a 127.0.0.1 llegaba a ella antes de que se informara del bloqueo.
[::]está bloqueada. La dirección IPv6 no especificada llega al host local, igual que0.0.0.0.- Cada salto de redirección pasa el filtro como una primera petición. Desde la v6.16.0, la lista de bloqueo y robots.txt se vuelven a comprobar antes de cada salto, y cada salto respeta el
Crawl-delaydel host. Una redirección a una ruta no permitida nunca se solicita. - Las lecturas de archivos locales están limitadas.
process_documentcon una ruta local acepta ahora solo tipos de archivo de documento y rechaza los directorios que empiezan por punto, como~/.ssh. DefineCRAWLFORGE_ALLOWED_DIRSpara restringir las lecturas a los directorios que indiques. - Tus rutas y credenciales se quedan en tu máquina. Una ruta de archivo local ya no llega al informe de uso. Las credenciales de proxy se ocultan en los resultados, los mensajes de error y los informes de uso, y las credenciales en URLs se ocultan en el registro de auditoría de cumplimiento.
- MCP SDK 2.3.1, por tres avisos de seguridad en el transporte HTTP y la gestión de autenticación del SDK.
La búsqueda pasó a la Brave Search API
El 19 de octubre, la API de CrawlForge pasó search_provider.backend indica qué backend atendió la llamada. total_results es null porque Brave no informa de un total, y un 0 se leería como "sin resultados". La paginación es exacta: un offset que no es múltiplo del tamaño de página devuelve ahora la ventana que pediste.
serp_suspect: true e indica cuántos lo hacían. La profundidad por defecto es ahora 30 tanto en el MCP server como en la API REST, y sigue costando 5 credits.
Cambios incompatibles que revisar antes de actualizar
La mayoría de las 24 versiones no cambian nada de lo que llamas. Estas sí:
| Cambio | Desde | Qué hacer |
|---|---|---|
read_result json_path empieza en el resultado almacenado completo | v6.23.0 | Antepón body. a las rutas de fetch_url (body.items[0]) |
Los registros de extract_links pierden is_external | v6.18.0 | Lee type: internal, external u other |
scrape acepta un formato highlights y uno question | v6.20.0 | Haz una segunda llamada para una segunda consulta |
maxRetries de scrape_with_actions vale 0 por defecto | v6.12.1 | Defínelo explícitamente si quieres la repetición |
enable/disable de stealth_mode eliminados; waited_for_render_ms sustituido | v6.19.0, v6.23.0 | Pasa la configuración en cada llamada; lee waited_ms y render_grace_ms |
Los valores @href/@src de scrape_structured son absolutos | v6.23.0 | Elimina tu propia resolución de URLs |
serp_rank revisa 30 resultados por defecto | v6.19.2 | Pasa depth (hasta 200) para objetivos más profundos |
Las peticiones HTTP de la era 2026-07-28 necesitan MCP-Protocol-Version | v6.23.1 | El cliente oficial del SDK ya lo envía |
Cómo actualizar
npm install -g crawlforge-mcp-server@latest
crawlforge --version # 6.24.0
# Optional: size the session page cache in MB (default 64), or 0 to turn it off
export CRAWLFORGE_PAGE_CACHE_MB=64Un cliente MCP que arranca el servidor con npx coge la v6.24.0 en el siguiente reinicio. Si instalaste las Agent Skills, actualízalas con crawlforge install-skills --target claude-code --force para que sus notas sobre las herramientas coincidan con el servidor.
¿Quieres ver la diferencia en las páginas que lee tu agente? Empieza gratis con 1._cost. Las llamadas fallidas mostrarán 0. Los precios de cada herramienta están en la página de precios.