Skip to main content
Glama

Web Speed

Web Speed resuelve el problema de señal-ruido para agentes de IA. Mientras que la web moderna está optimizada para ojos humanos (HTML desordenado, diseños complejos, interfaces cargadas de JS), Web Speed traduce ese caos en un mapa estructural determinista y eficiente en tokens, diseñado para flotas de agentes de alto rendimiento.

Sin IA integrada. Sin anthropic, sin openai, sin dependencia de LLM de ningún tipo. Toda la interpretación reside en el agente que realiza la llamada.


Por qué existe

Problema

Solución de Web Speed

El HTML sin procesar tiene más de 150,000 caracteres de scripts, estilos y ruido SVG

Elimina todo lo que no sea estructural → hasta un 97% de reducción de tokens

Los LLM alucinan IDs de elementos y pierden puntos de interacción en el DOM sin procesar

Devuelve un mapa estructural congelado — lo que está ahí, está ahí, no se inventa nada

Los scrapers personalizados se rompen por sitio

Protocolo determinista — la misma forma JSON para cada sitio en la web

El agente tiene que redescubrir páginas en un viaje de ida y vuelta a la vez

site_map rastrea un dominio completo en una sola llamada


Related MCP server: Delta-MCP

Herramientas

Herramienta

Descripción

interpret_page

Mapa estructurado completo: encabezados, navegación, enlaces de contenido, formularios, tablas, texto, metadatos

submit_form

Envía un formulario (GET o POST), devuelve el mapa de la página resultante

site_map

Rastrea desde una URL raíz, devuelve un mapa combinado de todas las páginas

inspect_element

Datos estructurales profundos para nodos que coinciden con un selector CSS

page_type

Clasificación instantánea de página — login, listing, article, form, navigation, other

invalidate_cache

Elimina un mapa en caché para que la siguiente llamada obtenga uno nuevo


Instalación

Mac / Linux

cd web-interpreter
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Windows

cd web-interpreter
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt

Ejecución

Para desarrollo local con el inspector MCP:

mcp dev server.py

Para ejecutar directamente sobre stdio (cómo lo lanzan los clientes MCP):

python server.py

Registrar con Claude / Cowork

Agrégalo a ~/Library/Application Support/Claude/claude_desktop_config.json (Mac) o el equivalente en Windows:

{
  "mcpServers": {
    "web-speed": {
      "command": "/absolute/path/to/web-interpreter/venv/bin/python",
      "args": ["/absolute/path/to/web-interpreter/server.py"]
    }
  }
}

Luego cierra y reinicia Claude Desktop / Cowork. Las seis herramientas aparecerán bajo el servidor MCP web-speed.


Esquemas de salida

interpret_page

{
  "url": "https://example.com/",
  "fetched_at": "2025-01-01T12:00:00Z",
  "page_type": "other",
  "title": "Example Domain",
  "description": "",
  "headings": [
    { "level": 1, "text": "Example Domain" }
  ],
  "navigation": [
    { "label": "Home", "url": "https://example.com/", "location": "header" }
  ],
  "content_links": {
    "total": 47,
    "truncated": false,
    "items": [
      { "label": "More information...", "url": "https://www.iana.org/domains/example" }
    ]
  },
  "forms": [
    {
      "id": "search",
      "action": "https://example.com/search",
      "method": "GET",
      "fields": [
        {
          "name": "q",
          "type": "text",
          "label": "Search",
          "placeholder": "Search...",
          "required": false,
          "value": ""
        },
        {
          "name": "_csrf",
          "type": "hidden",
          "label": "",
          "placeholder": "",
          "required": false,
          "value": "abc123"
        }
      ]
    }
  ],
  "tables": [
    {
      "id": "results",
      "headers": ["Name", "Price", "Stock"],
      "rows": [["Widget A", "$9.99", "In stock"]]
    }
  ],
  "text_blocks": [
    { "tag": "p", "text": "This domain is for use in illustrative examples." }
  ],
  "metadata": {
    "lang": "en",
    "canonical": "",
    "open_graph": { "title": "", "description": "", "image": "" }
  }
}

Campos clave:

  • navigation — enlaces dentro de elementos semánticos nav/header/footer (cromo del sitio, menús). Limitado a 60.

  • content_links — enlaces dentro del cuerpo de la página (artículos, resultados de búsqueda, listados). Siempre incluye total para que sepas el conteo real incluso cuando se trunca a 60.

  • forms — cada formulario con cada campo, tokens CSRF preservados textualmente en el value del campo oculto.

  • page_type — inferido de la estructura: campo de contraseña → login, muchos elementos/enlaces → listing, <article> con párrafos → article, formularios → form, mayormente enlaces → navigation.


page_type

Ligero — devuelve solo la clasificación. Instantáneo cuando la página está en caché.

{
  "url": "https://example.com/login",
  "fetched_at": "2025-01-01T12:00:00Z",
  "page_type": "login",
  "title": "Sign In"
}

submit_form

La misma forma de salida que interpret_page, para la página en la que aterriza el servidor después del envío.

{
  "url": "https://example.com/login",
  "method": "POST",
  "fields": {
    "email": "user@example.com",
    "password": "hunter2",
    "_csrf": "abc123"
  }
}

Los tokens CSRF van en fields textualmente — extráelos de los campos ocultos en el array forms de la llamada interpret_page anterior.


inspect_element

Datos estructurales profundos para nodos que coinciden con un selector CSS. Limitado a 25 elementos.

{
  "url": "https://example.com/shop",
  "selector": ".product-card",
  "matched": 48,
  "truncated": true,
  "elements": [
    {
      "tag": "div",
      "id": "product-42",
      "classes": ["product-card", "featured"],
      "text": "Widget Pro $49.99 Add to cart",
      "attributes": { "id": "product-42" },
      "links": [{ "label": "Add to cart", "url": "https://example.com/cart/add/42" }],
      "fields": [],
      "children": [
        { "tag": "h3", "text": "Widget Pro" },
        { "tag": "span", "text": "$49.99" },
        { "tag": "a", "text": "Add to cart", "href": "https://example.com/cart/add/42" }
      ]
    }
  ]
}

Selectores de ejemplo: #login-form, .product-card, table.results tbody tr, nav a, [data-testid="price"]


site_map

{
  "root_url": "https://example.com",
  "crawled_at": "2025-01-01T12:00:00Z",
  "total_pages": 8,
  "pages": [
    {
      "url": "https://example.com",
      "title": "Home",
      "page_type": "navigation",
      "depth": 0,
      "links_to": ["https://example.com/about", "https://example.com/contact"]
    }
  ],
  "all_forms": [
    {
      "found_on": "https://example.com/contact",
      "id": "contact",
      "action": "https://example.com/contact/submit",
      "method": "POST",
      "fields": [
        { "name": "email", "type": "email", "label": "Your email", "placeholder": "", "required": true, "value": "" },
        { "name": "message", "type": "textarea", "label": "Message", "placeholder": "", "required": true, "value": "" }
      ]
    }
  ],
  "all_navigation": [
    { "label": "About", "url": "https://example.com/about" },
    { "label": "Contact", "url": "https://example.com/contact" }
  ]
}

invalidate_cache

{ "url": "https://example.com", "invalidated": true }

Errores

Las herramientas nunca lanzan excepciones. En caso de fallo:

{
  "error": true,
  "code": "FETCH_FAILED | PARSE_FAILED | TIMEOUT | NOT_HTML",
  "message": "human-readable explanation",
  "url": "https://example.com/broken"
}

Cómo debe usar el agente la salida

Navegar por un sitio: Lee navigation para el cromo del sitio (menús, encabezado, pie de página) y content_links para los enlaces del cuerpo de la página. content_links.total te indica cuántos existen incluso si la lista está truncada. Elige el enlace que coincida con tu objetivo y llama a interpret_page.

Enviar un formulario: Lee forms. Cada campo tiene name (qué enviar), type (qué datos espera), label/placeholder (para qué sirve), required y value. Los campos ocultos (type: "hidden") llevan tokens CSRF — pasa su value de vuelta textualmente. Construye un diccionario plano name → value y llama a submit_form.

Clasificar antes de comprometerse: Llama a page_type primero cuando necesites ramificar la lógica (p. ej., ¿es esta una página de inicio de sesión o un panel de control?) sin pagar por un interpret_page completo.

Profundizar en un componente: ¿Viste una tabla en el mapa pero quieres las filas individuales? ¿Un listado de productos pero quieres el enlace y precio de cada tarjeta? Llama a inspect_element con un selector CSS para obtener detalles estructurados sobre esos nodos específicos sin recargar toda la página.

Planificar previamente un flujo de trabajo de varios pasos: Llama a site_map antes de empezar. Obtienes el título, tipo, profundidad y enlaces salientes de cada página, además de cada formulario en todo el sitio — puedes planificar todo el flujo de trabajo (encontrar el formulario de inicio de sesión, encontrar la página de entrada de datos, encontrar el endpoint de envío) sin un solo viaje de ida y vuelta.

page_type es una señal, no una garantía: La clasificación es heurística. Las SPA renderizadas por JS que sirven shells HTML vacíos a menudo serán other — el campo de contraseña no está en el HTML hasta que se ejecuta JavaScript. Trata page_type como un filtro rápido, luego verifica contra los forms y headings reales.


Sincronización de registro compartido

Por defecto, cada mapa de página nuevo que construye tu servidor OSS se aporta de forma asíncrona al registro compartido de Web Speed en api.getwebspeed.io. Este es el volante de crowdsourcing: cada agente que obtiene una URL la añade a la caché global, por lo que el siguiente agente en cualquier lugar obtiene una respuesta instantánea.

Esto es opt-out, no opt-in. El valor predeterminado está activado porque cuantos más colaboradores haya, más rápido funcionarán los agentes de todos.

Qué se comparte

Solo datos estructurales de la página:

  • Tipo de página, título, descripción

  • Encabezados, enlaces de navegación, enlaces de contenido

  • Nombres de campos de formulario, tipos y etiquetas (sin valores)

  • Tablas, bloques de texto

  • Metadatos Open Graph

Nunca se comparte: cookies, tokens de sesión, valores de formulario, mapas renderizados por JS (que pueden contener estado de inicio de sesión específico de la sesión).

Desactivar la sincronización

Establece la variable de entorno antes de iniciar el servidor:

WEB_SPEED_REGISTRY_SYNC=false python server.py

O en la configuración de tu cliente MCP:

{
  "mcpServers": {
    "web-speed": {
      "command": "/path/to/venv/bin/python",
      "args": ["/path/to/server.py"],
      "env": {
        "WEB_SPEED_REGISTRY_SYNC": "false"
      }
    }
  }
}

Apuntar a un registro autohospedado

Si estás ejecutando tu propia instancia alojada, apunta la sincronización allí:

WEB_SPEED_REGISTRY_URL=https://your-instance.example.com python server.py

Comportamiento de sincronización

  • Fire-and-forget: la contribución se envía en segundo plano. La solicitud de tu agente se completa a toda velocidad independientemente de si el ping tiene éxito.

  • Solo en MISS de caché: los mapas que ya están en tu caché de disco local de 24 horas no se vuelven a enviar.

  • Los fallos son silenciosos: los errores de red, tiempos de espera y rechazos del servidor se registran solo en el nivel DEBUG y nunca aparecen ante el agente.


Arquitectura

URL  ──▶  fetcher.py         (httpx: 10s timeout, 5 redirects, Chrome UA
                ▼             OR Playwright headless Chromium for js=true)
          cleaner.py         (BeautifulSoup/lxml: strip noise, split nav vs content
                ▼             links, filter layout tables, deduplicate text blocks,
          structured map      infer page_type, detect auth_gated)
                ▼
          cache.py           (24h TTL, MD5 keyed JSON files in ./cache/)
                ▼
          registry_sync.py   (fire-and-forget POST to api.getwebspeed.io/v1/contribute)
                ▼
          server.py          (FastMCP: 8 tools over stdio)

Sin IA. Sin interpretación. El agente es el cerebro.


Limitaciones conocidas

  • SPA renderizadas por JS: Las páginas que cargan contenido mediante JavaScript (React, Vue, Angular) devuelven solo el shell HTML de pre-renderizado. Los campos de contraseña, resultados de búsqueda y navegación que son inyectados por JS faltarán. Usa inspect_element en lo que sea visible y combínalo con una herramienta de automatización de navegador para objetivos con mucha carga de SPA.

  • Heurísticas de page_type: La clasificación es estructural y rápida, pero no infalible. Una página de marketing con muchos enlaces internos podría ser listing; una página con un campo de correo electrónico y sin contraseña no será login.

  • La caché es disco local: El directorio ./cache/ es local. En un despliegue multiproceso o distribuido, las entradas de caché no se compartirán entre instancias. Para el almacenamiento en caché compartido, reemplaza cache.py con un backend de Redis o Memcached.

  • Límites de tasa no aplicados: Web Speed no limita las solicitudes salientes. Para flotas de agentes de alto volumen, coloca un proxy de limitación de tasa (p. ej., Cloudflare, nginx) frente al servidor.

Related MCP Connectors

Related MCP Servers