Saltar a contenido

Referencia del servidor MCP

El servidor MCP de Scrapling ofrece diecisiete herramientas para extraer datos e interactuar con el navegador mediante Model Context Protocol (MCP). Integra Scrapling en asistentes y agentes de IA para extraer datos mediante conversaciones, con funciones para evitar la detección de bots.

Inicia el servidor MCP con este comando:

scrapling mcp

O importa la clase del servidor directamente:

from scrapling.core.ai import ScraplingMCPServer

server = ScraplingMCPServer()
server.serve(http=False, host="127.0.0.1", port=8000)

Para usar tu propio ejecutable de navegador compatible con Chromium, pasa executable_path:

server = ScraplingMCPServer(executable_path="/path/to/chromium")

Modelo de respuesta

Las herramientas de obtención de páginas y solicitudes HTTP devuelven esta estructura, con una respuesta por llamada. Las herramientas de gestión de sesiones usan los modelos siguientes. browser_screenshot devuelve una imagen de la página o de un elemento, junto con la URL actual, como bloques de imagen y texto. browser_extract y browser_actions devuelven texto plano. Las dos herramientas de red devuelven JSON estructurado mediante los modelos siguientes. browser_evaluate devuelve el resultado como JSON dentro de un bloque de texto.

scrapling.core.ai.server.ResponseModel

Clases base: BaseModel


              flowchart TD
              scrapling.core.ai.server.ResponseModel[ResponseModel]

              

              click scrapling.core.ai.server.ResponseModel href "" "scrapling.core.ai.server.ResponseModel"
            

Estructura con la información de la respuesta a una solicitud.

status class-attribute instance-attribute

status = Field(
    description="The status code returned by the website."
)

content class-attribute instance-attribute

content = Field(
    description="The page content as Markdown, HTML, text, or an AI ARIA snapshot."
)

url class-attribute instance-attribute

url = Field(
    description="The URL given by the user that resulted in this response."
)

Modelos de solicitudes de red

browser_network_requests devuelve NetworkRequestsModel con requests, next_cursor, has_more y dropped_count. Cada NetworkRequestInfo contiene id, url, method, resource_type y status. Para continuar, pasa next_cursor como after_id. has_more indica si hay más coincidencias en el historial actual.

browser_network_request devuelve NetworkRequestModel con request_id, part, data y note. Los resúmenes y las cabeceras son objetos. El contenido completo guardado se devuelve como una cadena, incluso si la respuesta contiene JSON. note explica si faltan datos del contenido o si las cabeceras están incompletas.

scrapling.core.ai._network_formatting.NetworkRequestInfo

Clases base: BaseModel


              flowchart TD
              scrapling.core.ai._network_formatting.NetworkRequestInfo[NetworkRequestInfo]

              

              click scrapling.core.ai._network_formatting.NetworkRequestInfo href "" "scrapling.core.ai._network_formatting.NetworkRequestInfo"
            

Resumen de una solicitud guardada del navegador.

model_config class-attribute instance-attribute

model_config = {'populate_by_name': True}

id class-attribute instance-attribute

id = Field(validation_alias=AliasPath("meta", "network_id"))

url instance-attribute

url

method instance-attribute

method

resource_type class-attribute instance-attribute

resource_type = Field(
    validation_alias=AliasPath("meta", "resource_type")
)

status instance-attribute

status

scrapling.core.ai.server.NetworkRequestsModel

Clases base: BaseModel


              flowchart TD
              scrapling.core.ai.server.NetworkRequestsModel[NetworkRequestsModel]

              

              click scrapling.core.ai.server.NetworkRequestsModel href "" "scrapling.core.ai.server.NetworkRequestsModel"
            

Resúmenes de solicitudes guardadas y datos de paginación.

requests instance-attribute

requests

next_cursor instance-attribute

next_cursor

has_more instance-attribute

has_more

dropped_count instance-attribute

dropped_count

scrapling.core.ai._network_formatting.NetworkRequestModel

Clases base: BaseModel


              flowchart TD
              scrapling.core.ai._network_formatting.NetworkRequestModel[NetworkRequestModel]

              

              click scrapling.core.ai._network_formatting.NetworkRequestModel href "" "scrapling.core.ai._network_formatting.NetworkRequestModel"
            

Una parte completa de una solicitud guardada, con una nota opcional.

request_id instance-attribute

request_id

part instance-attribute

part

data class-attribute instance-attribute

data = None

note class-attribute instance-attribute

note = None

Modelos de sesiones

Clases de modelos para gestionar sesiones:

scrapling.core.ai.server.SessionInfo

Clases base: SessionCreatedModel


              flowchart TD
              scrapling.core.ai.server.SessionInfo[SessionInfo]
              scrapling.core.ai.server.SessionCreatedModel[SessionCreatedModel]

                              scrapling.core.ai.server.SessionCreatedModel --> scrapling.core.ai.server.SessionInfo
                


              click scrapling.core.ai.server.SessionInfo href "" "scrapling.core.ai.server.SessionInfo"
              click scrapling.core.ai.server.SessionCreatedModel href "" "scrapling.core.ai.server.SessionCreatedModel"
            

Información de una sesión de navegador abierta.

created_at class-attribute instance-attribute

created_at = Field(
    description="ISO timestamp of when the session was created."
)

is_alive class-attribute instance-attribute

is_alive = Field(
    description="Whether the session is still alive and usable."
)

settings class-attribute instance-attribute

settings = Field(
    default_factory=dict,
    description="The effective settings this session was created with.",
)

session_id class-attribute instance-attribute

session_id = Field(
    description="The unique identifier of the session."
)

session_type class-attribute instance-attribute

session_type = Field(
    description="The type of the session: 'stealthy' or 'static'."
)

scrapling.core.ai.server.SessionCreatedModel

Clases base: BaseModel


              flowchart TD
              scrapling.core.ai.server.SessionCreatedModel[SessionCreatedModel]

              

              click scrapling.core.ai.server.SessionCreatedModel href "" "scrapling.core.ai.server.SessionCreatedModel"
            

Respuesta que se devuelve al crear una sesión.

session_id class-attribute instance-attribute

session_id = Field(
    description="The unique identifier of the session."
)

session_type class-attribute instance-attribute

session_type = Field(
    description="The type of the session: 'stealthy' or 'static'."
)

scrapling.core.ai.server.SessionClosedModel

Clases base: BaseModel


              flowchart TD
              scrapling.core.ai.server.SessionClosedModel[SessionClosedModel]

              

              click scrapling.core.ai.server.SessionClosedModel href "" "scrapling.core.ai.server.SessionClosedModel"
            

Respuesta que se devuelve al cerrar una sesión.

session_id class-attribute instance-attribute

session_id = Field(
    description="The unique identifier of the closed session."
)

message class-attribute instance-attribute

message = Field(description='A confirmation message.')

Clase del servidor MCP

La clase principal del servidor MCP ofrece las siguientes herramientas:

  • make_request: Obtiene una URL por HTTP con imitación de navegador y cierre automático del cliente. Admite GET, POST, PUT y DELETE.
  • browser_fetch_once: Obtiene una URL con un navegador sigiloso, ejecuta JavaScript, gestiona Cloudflare y cierra el navegador. Usa una sesión persistente si necesitas realizar acciones después o consultar el historial de red.

  • browser_extract: Lee la página actual o un elemento como una instantánea para IA, HTML, Markdown o texto, sin recargar. Conserva los resultados de formularios y acciones. Las instantáneas incluyen roles, nombres, referencias, posiciones y tamaños de los elementos. La búsqueda con expresiones regulares devuelve las líneas coincidentes, el contexto cercano y los nodos padre.

  • browser_actions: Encadena movimientos del ratón, acciones al pasar el cursor, clics, desplazamientos, llenado de campos, atajos de teclado, respuestas a diálogos y esperas en una llamada. Acepta o descarta alertas y confirmaciones, o escribe en diálogos de entrada. Puedes llenar una búsqueda, enviarla, esperar y abrir un resultado sin una llamada por paso.

    Los movimientos y clics admiten selectores, referencias de instantáneas o coordenadas. La herramienta espera a los elementos y los lleva a la vista. Admite movimientos por pasos, clics izquierdo, derecho y central, doble clic y desplazamiento en paneles anidados.

    Mantén pulsado un botón del ratón para arrastrar elementos o mover controles deslizantes. La IA puede revisar la página mientras mantiene el botón pulsado, ajustar la posición con más movimientos y soltarlo al llegar al destino.

    Selecciona campos mediante selectores o referencias de instantáneas. Escribe texto, marca o desmarca casillas, selecciona botones de opción y elige una o varias opciones de listas nativas por su etiqueta. Sustituye o borra el texto, o escribe en la posición del cursor. Los atajos usan el foco actual. El modo lento añade pausas aleatorias entre los caracteres y las acciones.

    Espera al contenido o a que desaparezcan los indicadores de carga mediante selectores o referencias de instantáneas. También puedes esperar a eventos de carga, a que termine la actividad de red o durante un tiempo fijo.

  • browser_evaluate: Ejecuta JavaScript en la página actual para extraer datos personalizados, calcular resultados, leer el estado de la aplicación o modificar el contenido. Admite scripts asíncronos y devuelve sus resultados como JSON.

  • browser_observe: Ayuda al agente a entender el movimiento y los cambios mediante una breve secuencia de imágenes de la página actual.
  • browser_network_requests: Busca solicitudes de navegador completadas entre pestañas, navegaciones y acciones. Encuentra llamadas API, errores HTTP y redirecciones guardadas. Oculta los recursos estáticos de forma predeterminada para reducir los resultados. Omite las solicitudes fallidas o incompletas. Devuelve datos estructurados con paginación.
  • browser_network_request: Lee el resumen, las cabeceras, los datos enviados o el contenido de texto de una solicitud guardada como JSON estructurado, sin repetirla. Devuelve la parte elegida completa. Las respuestas guardadas siguen disponibles después de cambiar de página, incluidas las respuestas HTTP 4xx y 5xx. Las entradas aparecen cuando termina la captura. Consultar el historial o cerrar la sesión no espera a las capturas pendientes, que pueden perderse al navegar o cerrar. Los bytes proceden de Playwright y pueden ser distintos de los enviados por el servidor. El texto usa la decodificación UTF-8 de Playwright cuando es válida; en otro caso, usa el charset declarado. Solo se lee y guarda el contenido con un Content-Type de texto compatible. Para los tipos binarios, ausentes o desconocidos, se conservan los metadatos y las cabeceras sin leer el contenido. Esto no cambia la carga de la página. El historial tiene límites de tamaño. Una nota opcional explica si el contenido no es texto, es demasiado grande o no se puede leer. Lee los datos que necesitas antes de cerrar la sesión MCP.
  • browser_fetch: Obtiene una página mediante una sesión de navegador sigiloso abierta y extrae HTML, Markdown, texto o una instantánea estructurada. Las instantáneas pueden cubrir toda la página o un elemento, e incluyen referencias, posiciones y tamaños para interactuar después.

scrapling.core.ai.server.ScraplingMCPServer

ScraplingMCPServer(executable_path=None, auth_token=None)

Crea un servidor MCP de Scrapling.

PARÁMETRO DESCRIPCIÓN
executable_path

Ruta global opcional a un ejecutable compatible con Chromium para las herramientas de navegador. Si no se indica, se usa la variable de entorno SCRAPLING_EXECUTABLE_PATH cuando está definida.

TIPO: Optional[str] PREDETERMINADO: None

auth_token

Token compartido opcional que los clientes deben enviar como Authorization: Bearer <token>. Si no se indica, se usa SCRAPLING_MCP_AUTH_TOKEN cuando está definida. Solo se aplica al transporte streamable-http.

TIPO: Optional[str] PREDETERMINADO: None

Código fuente en scrapling/core/ai/server.py
def __init__(self, executable_path: Optional[str] = None, auth_token: Optional[str] = None):
    """Create a Scrapling MCP server.

    :param executable_path: Optional global Chromium-compatible browser executable path for browser tools.
        If omitted, the SCRAPLING_EXECUTABLE_PATH environment variable is used when set.
    :param auth_token: Optional shared token that clients must send as `Authorization: Bearer <token>`.
        If omitted, the SCRAPLING_MCP_AUTH_TOKEN environment variable is used when set. It only applies
        to the streamable-http transport.
    """
    self._sessions: Dict[str, _SessionEntry] = {}
    self._executable_path = executable_path or environ.get(MCP_EXECUTABLE_PATH_ENV) or None
    self._auth_token = auth_token or environ.get(MCP_AUTH_TOKEN_ENV) or None

browser_open async

browser_open(
    session_id=None,
    headless=True,
    real_chrome=False,
    timezone_id=None,
    locale=None,
    useragent=None,
    proxy=None,
    cdp_url=None,
    new_context=True,
    executable_path=None,
    cookies=None,
    hide_canvas=False,
    block_webrtc=False,
    allow_webgl=True,
    additional_args=None,
)

Open a reusable local or remote browser session. Pass per-request options to browser_fetch.

Código fuente en scrapling/core/ai/server.py
async def browser_open(
    self,
    session_id: Annotated[
        Optional[str], Field(description="Custom ID; a random 12-character hex ID if omitted.")
    ] = None,
    headless: Annotated[bool, Field(description="Hide the browser window.")] = True,
    real_chrome: Annotated[bool, Field(description="Use locally installed Chrome.")] = False,
    timezone_id: Annotated[
        str | None, Field(description="Browser timezone; uses the system timezone if omitted.")
    ] = None,
    locale: Annotated[
        str | None,
        Field(description="Browser language, Accept-Language, and formatting locale; system default if omitted."),
    ] = None,
    useragent: Annotated[
        Optional[str],
        Field(description="User-Agent override; otherwise generated in headless mode, native in headful mode."),
    ] = None,
    proxy: Annotated[
        Optional[str | Dict[str, str]],
        Field(description="Proxy URL, or dictionary with server and optional username/password."),
    ] = None,
    cdp_url: Annotated[
        Optional[str],
        Field(
            description="Connect to an existing Chromium browser over CDP; browser launch settings do not apply."
        ),
    ] = None,
    new_context: Annotated[
        bool,
        Field(
            description="With cdp_url, create and close a separate context. False reuses and preserves the default context, ignoring useragent, locale, timezone_id, proxy and additional_args."
        ),
    ] = True,
    executable_path: Annotated[
        Optional[str],
        Field(description="Absolute Chromium-compatible executable path; overrides the server default."),
    ] = None,
    cookies: Annotated[
        Sequence[SetCookieParam] | None, Field(description="Initial cookies as Playwright cookie dictionaries.")
    ] = None,
    hide_canvas: Annotated[bool, Field(description="Add noise to canvas operations.")] = False,
    block_webrtc: Annotated[bool, Field(description="Disable non-proxied WebRTC UDP to reduce IP leaks.")] = False,
    allow_webgl: Annotated[bool, Field(description="Enable WebGL; disabling it can trigger bot detection.")] = True,
    additional_args: Annotated[
        Optional[Dict], Field(description="Browser context options that override Scrapling settings.")
    ] = None,
) -> SessionCreatedModel:
    """Open a reusable local or remote browser session. Pass per-request options to `browser_fetch`."""
    session_id = self._new_session_id(session_id)
    options: Dict[str, Any] = dict(
        proxy=proxy,
        locale=locale,
        cookies=cookies,
        block_ads=True,
        record_requests=True,
        useragent=useragent,
        timezone_id=timezone_id,
        additional_args=additional_args,
    )
    session = (
        AsyncRemoteSession(cdp_url, new_context=new_context, **options)
        if cdp_url is not None
        else AsyncStealthySession(
            headless=headless,
            real_chrome=real_chrome,
            executable_path=self._resolve_executable_path(executable_path),
            hide_canvas=hide_canvas,
            block_webrtc=block_webrtc,
            allow_webgl=allow_webgl,
            **options,
        )
    )
    await session.start()
    return self._register_session(session_id, session, "stealthy")

browser_save_state async

browser_save_state(session_id, path)

Guarda las cookies del navegador, el almacenamiento local e IndexedDB como JSON compatible con Playwright. No incluye sessionStorage.

Código fuente en scrapling/core/ai/server.py
async def browser_save_state(
    self,
    session_id: Annotated[str, Field(description="Browser session ID.")],
    path: Annotated[
        NonEmptyString,
        Field(
            description="File on the MCP server host; relative to its working directory. Overwrites the file; parent must exist."
        ),
    ],
) -> str:
    """Save browser cookies, local storage and IndexedDB as Playwright-compatible JSON. Excludes sessionStorage."""
    await self._get_session(session_id, ["stealthy"]).session.save_state(path)
    return "State saved."

browser_load_state async

browser_load_state(session_id, path)

Sustituye las cookies del navegador, el almacenamiento local e IndexedDB por los datos de un archivo JSON compatible con Playwright.

No cambia sessionStorage ni las pestañas abiertas. Carga o recarga las páginas para usar el inicio de sesión restaurado.

Código fuente en scrapling/core/ai/server.py
async def browser_load_state(
    self,
    session_id: Annotated[str, Field(description="Browser session ID.")],
    path: Annotated[
        NonEmptyString, Field(description="File on the MCP server host; relative to its working directory.")
    ],
) -> str:
    """Replace browser cookies, local storage and IndexedDB from a Playwright-compatible JSON file.

    Leaves sessionStorage and open tabs unchanged. Fetch or reload pages to use the restored login."""
    await self._get_session(session_id, ["stealthy"]).session.load_state(path)
    return "State loaded."

open_request_session async

open_request_session(
    session_id=None, impersonate="chrome", proxy=None
)

Abre una sesión HTTP reutilizable para session_make_request y conserva las cookies, las conexiones y la configuración de las solicitudes.

Código fuente en scrapling/core/ai/server.py
async def open_request_session(
    self,
    session_id: Annotated[
        Optional[str], Field(description="Custom ID; a random 12-character hex ID if omitted.")
    ] = None,
    impersonate: Annotated[
        _MCPImpersonateType,
        Field(
            description='Browser/version to impersonate; "chrome" uses the latest supported Chrome profile. Lists pick randomly per attempt; None disables impersonation.'
        ),
    ] = "chrome",
    proxy: Annotated[
        Optional[str], Field(description="Proxy URL for all session requests, optionally including credentials.")
    ] = None,
) -> SessionCreatedModel:
    """Open a reusable HTTP session for `session_make_request`, keeping cookies, connections, and request settings."""
    session_id = self._new_session_id(session_id)
    session = FetcherSession(impersonate=impersonate, proxy=proxy)
    await session.__aenter__()
    return self._register_session(session_id, session, "static")

close_session async

close_session(session_id)

Cierra una sesión y libera sus recursos.

Código fuente en scrapling/core/ai/server.py
async def close_session(
    self,
    session_id: Annotated[str, Field(description="Session ID to close.")],
) -> SessionClosedModel:
    """Close a session and free its resources."""
    entry = self._sessions.pop(session_id, None)
    if entry is None:
        raise ValueError(f"Session '{session_id}' not found. Use list_sessions to see active sessions.")

    if entry.session_type == "static":
        await entry.session.__aexit__(None, None, None)
    else:
        await entry.session.close()
    return SessionClosedModel(
        session_id=session_id,
        message=f"Session '{session_id}' closed successfully.",
    )

list_sessions async

list_sessions()

Muestra las sesiones registradas, su estado y su configuración activa.

Código fuente en scrapling/core/ai/server.py
async def list_sessions(self) -> List[SessionInfo]:
    """List registered sessions, their status, and effective settings."""
    return [
        SessionInfo(
            session_id=sid,
            session_type=entry.session_type,
            created_at=entry.created_at,
            is_alive=entry.session._is_alive,
            settings=_session_settings(entry.session),
        )
        for sid, entry in self._sessions.items()
    ]

browser_network_requests async

browser_network_requests(
    session_id,
    url_pattern=None,
    include_static=False,
    after_id=0,
    limit=50,
)

List completed requests across page changes, with IDs and pagination. Recording starts when the browser session opens and closing does not wait for running captures.

Código fuente en scrapling/core/ai/server.py
async def browser_network_requests(
    self,
    session_id: Annotated[str, Field(description="Browser session ID.")],
    url_pattern: Annotated[Optional[str], Field(description="Filter URLs by regular expression.")] = None,
    include_static: Annotated[bool, Field(description="Include successful non-API requests too.")] = False,
    after_id: Annotated[
        int, Field(ge=0, description="Return requests with a higher ID; use next_cursor for more.")
    ] = 0,
    limit: Annotated[int, Field(ge=1, le=200, description="Maximum requests to return.")] = 50,
) -> NetworkRequestsModel:
    """List completed requests across page changes, with IDs and pagination. Recording starts when the browser session opens and closing does not wait for running captures."""
    network = self._get_session(session_id, ["stealthy"]).session.network
    records = network.search(
        url_pattern=url_pattern, include_static=include_static, after_id=after_id, limit=limit + 1
    )
    shown = records[:limit]
    return NetworkRequestsModel(
        requests=[NetworkRequestInfo.model_validate(record, from_attributes=True) for record in shown],
        next_cursor=shown[-1].meta["network_id"] if shown else max(after_id, network.last_id),
        has_more=len(records) > limit,
        dropped_count=network.dropped_count,
    )

browser_network_request async

browser_network_request(
    session_id, request_id, part="summary"
)

Lee una parte completa de una solicitud guardada sin volver a enviarla, con datos estructurados y notas sobre su disponibilidad.

Código fuente en scrapling/core/ai/server.py
async def browser_network_request(
    self,
    session_id: Annotated[str, Field(description="Browser session ID.")],
    request_id: Annotated[int, Field(ge=1, description="ID from `browser_network_requests`.")],
    part: Annotated[
        NetworkPart, Field(description="Request summary, headers, or text body; incomplete headers are marked.")
    ] = "summary",
) -> NetworkRequestModel:
    """Read a complete saved request part without resending it, with structured data and availability notes."""
    network = self._get_session(session_id, ["stealthy"]).session.network
    record = network.get(request_id)
    if record is None:
        raise ValueError(
            f"Request {request_id} was not found or is no longer retained. Use browser_network_requests."
        )
    return _request_details(record, part)

browser_extract async

browser_extract(
    session_id,
    extraction_type="snapshot",
    target=None,
    depth=None,
    boxes=True,
    search=None,
    main_content_only=True,
)

Lee la página actual o un elemento como snapshot, HTML, Markdown o texto, sin navegar. Devuelve texto simple. La búsqueda en snapshots conserva las referencias, las rutas de antecesores y tres líneas de contexto cercano.

Código fuente en scrapling/core/ai/server.py
async def browser_extract(
    self,
    session_id: Annotated[str, Field(description="Browser session ID")],
    extraction_type: Annotated[
        SessionExtractionType, Field(description="Output format; defaults to an AI ARIA snapshot.")
    ] = "snapshot",
    target: Annotated[
        Optional[NonEmptyString],
        Field(description="Playwright selector or aria-ref=<ref> matching one element; omitted reads the page."),
    ] = None,
    depth: Annotated[
        Optional[int],
        Field(description="Snapshot depth before search; unlimited if omitted. Ignored for other formats."),
    ] = None,
    boxes: Annotated[
        bool, Field(description="Include viewport bounding boxes in snapshots; ignored for other formats.")
    ] = True,
    search: Annotated[
        Optional[NonEmptyString],
        Field(description="Snapshot-only Python regex; case-sensitive unless (?i). No matches returns empty text."),
    ] = None,
    main_content_only: Annotated[
        bool, Field(description="Clean body/target content for AI; ignored for snapshots.")
    ] = True,
) -> str:
    """Read the current page or one element as snapshot, HTML, Markdown, or text without navigating.
    Return plain text; snapshot search keeps refs, ancestor paths and three lines of nearby context."""
    pattern = None
    if search is not None:
        if extraction_type != "snapshot":
            raise ValueError("search requires snapshot output.")
        try:
            pattern = re.compile(search)
        except re.error as error:
            raise ValueError(f"Invalid search regex: {error}") from error
    if extraction_type == "snapshot":
        snapshot = await self._browser_snapshot(session_id, css_selector=target, depth=depth, boxes=boxes)
        return _search_snapshot(snapshot, pattern) if pattern is not None else snapshot
    with self._browser_page(session_id) as (_, page):
        content = (
            await page.locator(target).evaluate("(element) => element.outerHTML")
            if target is not None
            else await ResponseFactory._get_async_page_content(page)
        )
        return _CONTROL_CHARS_PATTERN.sub(
            "",
            "".join(
                Convertor._extract_content(
                    Selector(content=content, url=page.url),
                    extraction_type=extraction_type,
                    main_content_only=main_content_only,
                )
            ),
        )

browser_actions async

browser_actions(session_id, actions, slowly=False)

Chain all kinds of browser actions. Do actions without multiple calls or plan ahead to execute a sequence of actions. Run mouse, field, key, dialog, and wait actions on the current page in order. Load waits observe the current document; wait for a result element for delayed navigation. Stops on the first error, identifying its action; partial effects remain. No retries. Element mouse targets auto-wait and scroll into view; coordinates and wheel do not wait for navigation or scrolling. mouse_down holds across calls for observation and further moves; mouse_up releases, including after errors. For drag and drop, move over the target twice before releasing. Cancelled/timed-out clicks attempt release.

Código fuente en scrapling/core/ai/server.py
async def browser_actions(
    self,
    session_id: Annotated[str, Field(description="Browser session ID")],
    actions: Annotated[
        List[BrowserAction],
        Field(
            min_length=1,
            description="Ordered actions; fields need target; move/click need target or viewport (x, y); mouse_down/mouse_up act at the current pointer.",
        ),
    ],
    slowly: Annotated[
        bool,
        Field(
            description="Fresh random delays: 50-150 ms per character, 100-300 ms between all actions, including waits."
        ),
    ] = False,
) -> str:
    """Chain all kinds of browser actions. Do actions without multiple calls or plan ahead to execute a sequence of actions.
    Run mouse, field, key, dialog, and wait actions on the current page in order.
    Load waits observe the current document; wait for a result element for delayed navigation.
    Stops on the first error, identifying its action; partial effects remain. No retries.
    Element mouse targets auto-wait and scroll into view; coordinates and wheel do not wait for navigation or scrolling.
    mouse_down holds across calls for observation and further moves; mouse_up releases, including after errors.
    For drag and drop, move over the target twice before releasing. Cancelled/timed-out clicks attempt release."""
    _validate_actions(actions)
    with self._browser_page(session_id) as (_, page):
        await _run_actions(page, actions, slowly)
    return "Actions completed."

browser_evaluate async

browser_evaluate(
    session_id, expression, arg=None, isolated_context=True
)

Ejecuta JavaScript en la página actual, espera las promesas y devuelve texto JSON sin snapshot. Devuelve valores compatibles con JSON; null y undefined se convierten en null. Si hay un fallo, no se deshacen los cambios del script. Cancelar detiene la espera, pero puede que no detenga el script.

Código fuente en scrapling/core/ai/server.py
async def browser_evaluate(
    self,
    session_id: Annotated[str, Field(description="Browser session ID")],
    expression: Annotated[NonEmptyString, Field(description="JavaScript expression or function to invoke.")],
    arg: Annotated[
        Optional[Dict[str, Any]],
        Field(description="JSON object passed to the function; use properties for scalar or array values."),
    ] = None,
    isolated_context: Annotated[
        bool,
        Field(
            description="False accesses the page's own JS variables; True uses a separate context with the same DOM."
        ),
    ] = True,
) -> str:
    """Run JavaScript on the current page, await promises, and return JSON text without a snapshot.
    Return JSON-compatible values; null/undefined become null. Script effects are not undone on failure.
    Cancellation stops waiting, but may not stop the script."""
    with self._browser_page(session_id) as (_, page):
        return dumps(
            await page.evaluate(expression, arg=arg, isolated_context=isolated_context),
            ensure_ascii=False,
            allow_nan=False,
            separators=(",", ":"),
        )

browser_screenshot async

browser_screenshot(
    session_id,
    image_type="png",
    full_page=False,
    quality=None,
    timeout=30000,
    selector=None,
    ref=None,
)

Captura la página actual o un elemento sin navegar y devuelve la imagen y la URL actual. Al capturar un elemento, espera a que esté disponible y lo desplaza a la vista. Usa browser_actions para otras esperas antes de la captura.

Código fuente en scrapling/core/ai/server.py
async def browser_screenshot(
    self,
    session_id: Annotated[str, Field(description="Browser session ID")],
    image_type: Annotated[ScreenshotType, Field(description="Image format.")] = "png",
    full_page: Annotated[
        bool, Field(description="Capture the full scrollable page; incompatible with selector/ref.")
    ] = False,
    quality: Annotated[
        Optional[Annotated[int, Field(ge=0, le=100)]], Field(description="JPEG quality, 0-100; invalid for PNG.")
    ] = None,
    timeout: Annotated[
        NonNegativeFiniteFloat, Field(description="Capture limit in milliseconds; 0 disables it.")
    ] = 30000,
    selector: Annotated[
        Optional[NonEmptyString],
        Field(description="Playwright selector matching one element; omit when using ref."),
    ] = None,
    ref: Annotated[
        Optional[NonEmptyString],
        Field(description="Current snapshot element reference; omit both targets for page capture."),
    ] = None,
) -> List[ImageContent | TextContent]:
    """Capture the current page or one element without navigating; return the image and current URL.
    Element capture waits and scrolls into view. Use browser_actions for other waits before capture."""
    if quality is not None and image_type != "jpeg":
        raise ValueError("'quality' is only valid when 'image_type' is 'jpeg'.")
    if selector is not None and ref is not None:
        raise ValueError("Provide either 'selector' or 'ref', not both.")
    if full_page and (selector is not None or ref is not None):
        raise ValueError("'full_page' cannot be combined with 'selector' or 'ref'.")

    with self._browser_page(session_id) as (_, page):
        options: Dict[str, Any] = {"type": image_type, "quality": quality, "timeout": timeout}
        if selector is not None or ref is not None:
            started = monotonic()
            element = await page.locator(selector or f"aria-ref={ref}").element_handle(timeout=timeout)
            try:
                options["timeout"] = max(1, timeout - (monotonic() - started) * 1000) if timeout else 0
                data = await element.screenshot(**options)
            except BaseException as exc:
                try:
                    with CancelScope(shield=True):
                        await element.dispose()
                except Exception as cleanup_error:
                    raise exc from cleanup_error
                raise
            with CancelScope(shield=True):
                await element.dispose()
        else:
            data = await page.screenshot(full_page=full_page, **options)
        return [Image(data=data, format=image_type).to_image_content(), TextContent(type="text", text=page.url)]

browser_observe async

browser_observe(
    session_id, duration_ms=1500, max_frames=12
)

Inspect browser page motion through a short sequence of timestamped viewport images. The page keeps running during and after capture. Use this tool when you get any challenge that require timed actions like games, appearing/disappearing CAPTCHAs, or interacting with any moving elements.

Código fuente en scrapling/core/ai/server.py
async def browser_observe(
    self,
    session_id: Annotated[str, Field(description="Browser session ID")],
    duration_ms: Annotated[int, Field(ge=100, le=5000, description="Observation window in milliseconds.")] = 1500,
    max_frames: Annotated[int, Field(ge=2, le=20, description="Maximum number of sampled frames.")] = 12,
) -> List[ImageContent | TextContent]:
    """Inspect browser page motion through a short sequence of timestamped viewport images. The page keeps running during and after capture.
    Use this tool when you get any challenge that require timed actions like games, appearing/disappearing CAPTCHAs, or interacting with any moving elements.
    """
    with self._browser_page(session_id) as (_, page):
        frames: Dict[int, Dict[str, Any]] = {}
        started = monotonic()

        def capture(frame: Dict[str, Any]) -> None:
            elapsed = (monotonic() - started) * 1000
            if elapsed < duration_ms:
                frames[int(elapsed * max_frames / duration_ms)] = frame

        try:
            await page.screencast.start(on_frame=capture, quality=60, size={"width": 800, "height": 800})
            await sleep(max(0, duration_ms / 1000 - (monotonic() - started)))
        except BaseException as error:
            try:
                await _stop_screencast(page)
            except Exception as cleanup_error:
                raise error from cleanup_error
            raise
        await _stop_screencast(page)
        if not frames:
            raise RuntimeError("No frames were captured. Try browser_screenshot or a longer observation window.")
        return [
            content
            for frame in frames.values()
            for content in (
                TextContent(
                    type="text",
                    text=dumps(
                        {
                            "timestamp_ms": frame["timestamp"],
                            "viewport_width": frame["viewportWidth"],
                            "viewport_height": frame["viewportHeight"],
                        },
                        separators=(",", ":"),
                    ),
                ),
                Image(data=frame["data"], format="jpeg").to_image_content(),
            )
        ]

make_request async staticmethod

make_request(
    url,
    method="GET",
    impersonate="chrome",
    extraction_type="markdown",
    css_selector=None,
    main_content_only=True,
    params=None,
    data=None,
    json=None,
    headers=None,
    cookies=None,
    timeout=30,
    follow_redirects="safe",
    max_redirects=30,
    retries=3,
    retry_delay=1,
    proxy=None,
    proxy_auth=None,
    auth=None,
    verify=True,
    http3=False,
    stealthy_headers=True,
)

Realiza una solicitud HTTP sin JavaScript. Sirve para sitios con protección baja o media.

Código fuente en scrapling/core/ai/server.py
@staticmethod
async def make_request(
    url: Annotated[str, Field(description="URL to fetch.")],
    method: Annotated[SUPPORTED_HTTP_METHODS, Field(description="HTTP method.")] = "GET",
    impersonate: Annotated[
        _MCPImpersonateType,
        Field(
            description='Browser/version to impersonate; "chrome" uses the latest supported Chrome profile. Lists pick randomly per attempt; None disables impersonation.'
        ),
    ] = "chrome",
    extraction_type: Annotated[extraction_types, Field(description="Content output format.")] = "markdown",
    css_selector: Annotated[
        Optional[str], Field(description="Select matching elements after `main_content_only` filtering.")
    ] = None,
    main_content_only: Annotated[
        bool, Field(description="Sanitize <body> content before selection; False uses the full document.")
    ] = True,
    params: Annotated[Optional[Dict], Field(description="Query parameters.")] = None,
    data: Annotated[Optional[Dict[str, str] | str], Field(description="Form or raw body; ignored for GET.")] = None,
    json: Annotated[Optional[Dict | List], Field(description="JSON body; ignored for GET.")] = None,
    headers: Annotated[Optional[Mapping[str, Optional[str]]], Field(description="Request headers.")] = None,
    cookies: Annotated[Optional[Dict[str, str]], Field(description="Request cookies.")] = None,
    timeout: Annotated[Optional[int | float], Field(description="Timeout in seconds.")] = 30,
    follow_redirects: Annotated[
        FollowRedirects,
        Field(
            description='"safe" blocks redirects to private/internal IPs; True allows all; False disables redirects.'
        ),
    ] = "safe",
    max_redirects: Annotated[int, Field(description="Redirect limit; -1 means unlimited.")] = 30,
    retries: Annotated[
        Optional[int], Field(description="Maximum attempts, including the first; None or values below 1 send once.")
    ] = 3,
    retry_delay: Annotated[Optional[int], Field(description="Seconds between retries.")] = 1,
    proxy: Annotated[Optional[str], Field(description="Proxy URL, optionally including credentials.")] = None,
    proxy_auth: Annotated[
        Optional[Dict[str, str]], Field(description='Proxy basic auth: {"username": ..., "password": ...}.')
    ] = None,
    auth: Annotated[
        Optional[Dict[str, str]], Field(description='Basic auth: {"username": ..., "password": ...}.')
    ] = None,
    verify: Annotated[Optional[bool], Field(description="Verify TLS certificates.")] = True,
    http3: Annotated[
        Optional[bool], Field(description="Use HTTP/3; may conflict with browser impersonation.")
    ] = False,
    stealthy_headers: Annotated[
        Optional[bool],
        Field(description="Fill missing browser headers and use a Google referer if none was supplied."),
    ] = True,
) -> ResponseModel:
    """Make an HTTP request without JavaScript. Suitable for low-to-mid protection."""
    normalized_proxy_auth = _normalize_credentials(proxy_auth)
    normalized_auth = _normalize_credentials(auth)

    request_kwargs: Dict[str, Any] = dict(
        auth=normalized_auth,
        proxy=proxy,
        http3=http3,
        verify=verify,
        params=params,
        headers=headers,
        cookies=cookies,
        timeout=timeout,
        retries=retries,
        proxy_auth=normalized_proxy_auth,
        retry_delay=retry_delay,
        impersonate=impersonate,
        max_redirects=max_redirects,
        follow_redirects=follow_redirects,
        stealthy_headers=stealthy_headers,
    )
    if method != "GET":
        request_kwargs.update(data=data, json=json)

    async with FetcherSession() as session:
        page = await getattr(session, method.lower())(url, **request_kwargs)
        return _translate_response(page, extraction_type, css_selector, main_content_only)

browser_fetch_once async

browser_fetch_once(
    url,
    extraction_type="markdown",
    css_selector=None,
    main_content_only=True,
    headless=True,
    google_search=True,
    real_chrome=False,
    wait=0,
    proxy=None,
    timezone_id=None,
    locale=None,
    extra_headers=None,
    useragent=None,
    hide_canvas=False,
    executable_path=None,
    timeout=30000,
    disable_resources=False,
    wait_selector=None,
    cookies=None,
    network_idle=False,
    wait_selector_state="attached",
    block_webrtc=False,
    allow_webgl=True,
    solve_cloudflare=False,
    additional_args=None,
    pierce_shadow=False,
)

Obtiene una página con un navegador con protección contra detección y ejecución de JavaScript.

Código fuente en scrapling/core/ai/server.py
async def browser_fetch_once(
    self,
    url: Annotated[str, Field(description="URL to fetch.")],
    extraction_type: Annotated[extraction_types, Field(description="Content output format.")] = "markdown",
    css_selector: Annotated[
        Optional[str], Field(description="Select matching elements after `main_content_only` filtering.")
    ] = None,
    main_content_only: Annotated[
        bool, Field(description="Sanitize <body> content before selection; False uses the full document.")
    ] = True,
    headless: Annotated[bool, Field(description="Hide the browser window.")] = True,
    google_search: Annotated[
        bool, Field(description="Set a Google referer, overriding any supplied referer.")
    ] = True,
    real_chrome: Annotated[bool, Field(description="Use locally installed Chrome.")] = False,
    wait: Annotated[
        int | float, Field(description="Extra milliseconds after the page is ready, before returning.")
    ] = 0,
    proxy: Annotated[
        Optional[str | Dict[str, str]],
        Field(description="Proxy URL, or dictionary with server and optional username/password."),
    ] = None,
    timezone_id: Annotated[
        str | None, Field(description="Browser timezone; uses the system timezone if omitted.")
    ] = None,
    locale: Annotated[
        str | None,
        Field(description="Browser language, Accept-Language, and formatting locale; system default if omitted."),
    ] = None,
    extra_headers: Annotated[Optional[Dict[str, str]], Field(description="Additional request headers.")] = None,
    useragent: Annotated[
        Optional[str],
        Field(description="User-Agent override; otherwise generated in headless mode, native in headful mode."),
    ] = None,
    hide_canvas: Annotated[bool, Field(description="Add noise to canvas operations.")] = False,
    executable_path: Annotated[
        Optional[str],
        Field(description="Absolute Chromium-compatible executable path; overrides the server default."),
    ] = None,
    timeout: Annotated[
        int | float, Field(description="Navigation and page-operation timeout in milliseconds.")
    ] = 30000,
    disable_resources: Annotated[
        bool,
        Field(
            description="Block font, image, media, beacon, object, imageset, texttrack, websocket, csp_report, and stylesheet requests."
        ),
    ] = False,
    wait_selector: Annotated[
        Optional[str], Field(description="Wait for the first CSS match; continue if the wait fails.")
    ] = None,
    cookies: Annotated[
        Sequence[SetCookieParam] | None, Field(description="Initial cookies as Playwright cookie dictionaries.")
    ] = None,
    network_idle: Annotated[
        bool, Field(description="Try to wait for 500 ms without network activity; continue if the wait fails.")
    ] = False,
    wait_selector_state: Annotated[
        SelectorWaitStates, Field(description="Target state of `wait_selector`.")
    ] = "attached",
    block_webrtc: Annotated[bool, Field(description="Disable non-proxied WebRTC UDP to reduce IP leaks.")] = False,
    allow_webgl: Annotated[bool, Field(description="Enable WebGL; disabling it can trigger bot detection.")] = True,
    solve_cloudflare: Annotated[
        bool, Field(description="Attempt to solve Cloudflare Turnstile/interstitial challenges before returning.")
    ] = False,
    additional_args: Annotated[
        Optional[Dict], Field(description="Browser context options that override Scrapling settings.")
    ] = None,
    pierce_shadow: Annotated[bool, Field(description="Include open Shadow DOM content.")] = False,
) -> ResponseModel:
    """Fetch a page with a stealth browser and JavaScript rendering."""
    async with AsyncStealthySession(
        wait=wait,
        proxy=proxy,
        locale=locale,
        timeout=timeout,
        cookies=cookies,
        headless=headless,
        block_ads=True,
        max_pages=1,
        useragent=useragent,
        timezone_id=timezone_id,
        real_chrome=real_chrome,
        hide_canvas=hide_canvas,
        allow_webgl=allow_webgl,
        network_idle=network_idle,
        pierce_shadow=pierce_shadow,
        block_webrtc=block_webrtc,
        wait_selector=wait_selector,
        google_search=google_search,
        extra_headers=extra_headers,
        executable_path=self._resolve_executable_path(executable_path),
        additional_args=additional_args,
        solve_cloudflare=solve_cloudflare,
        disable_resources=disable_resources,
        wait_selector_state=wait_selector_state,
    ) as session:
        page = await session.fetch(url)

    return _translate_response(page, extraction_type, css_selector, main_content_only)

browser_fetch async

browser_fetch(
    url,
    session_id,
    extraction_type="markdown",
    css_selector=None,
    main_content_only=True,
    wait=0,
    timeout=30000,
    google_search=True,
    network_idle=False,
    load_dom=True,
    disable_resources=False,
    wait_selector=None,
    wait_selector_state="attached",
    extra_headers=None,
    blocked_domains=None,
    solve_cloudflare=False,
    pierce_shadow=False,
)

Obtiene una URL en una sesión abierta de navegador con protección contra detección. Las opciones solo se aplican a esta solicitud.

Código fuente en scrapling/core/ai/server.py
async def browser_fetch(
    self,
    url: Annotated[str, Field(description="URL to fetch.")],
    session_id: Annotated[str, Field(description="Browser session ID.")],
    extraction_type: Annotated[
        SessionExtractionType, Field(description="Content output format; snapshots include element bounding boxes.")
    ] = "markdown",
    css_selector: Annotated[
        Optional[str],
        Field(description="Select after `main_content_only` filtering; snapshots require exactly one match."),
    ] = None,
    main_content_only: Annotated[
        bool,
        Field(description="Sanitize <body> before selection; False uses the full document. Ignored for snapshots."),
    ] = True,
    wait: Annotated[
        int | float, Field(description="Extra milliseconds after the page is ready, before returning.")
    ] = 0,
    timeout: Annotated[
        int | float, Field(description="Navigation and page-operation timeout in milliseconds.")
    ] = 30000,
    google_search: Annotated[
        bool, Field(description="Set a Google referer, overriding any supplied referer.")
    ] = True,
    network_idle: Annotated[
        bool, Field(description="Try to wait for 500 ms without network activity; continue if the wait fails.")
    ] = False,
    load_dom: Annotated[bool, Field(description="Wait for DOMContentLoaded.")] = True,
    disable_resources: Annotated[
        bool,
        Field(
            description="Block font, image, media, beacon, object, imageset, texttrack, websocket, csp_report, and stylesheet requests."
        ),
    ] = False,
    wait_selector: Annotated[
        Optional[str], Field(description="Wait for the first CSS match; continue if the wait fails.")
    ] = None,
    wait_selector_state: Annotated[
        SelectorWaitStates, Field(description="Target state of `wait_selector`.")
    ] = "attached",
    extra_headers: Annotated[Optional[Dict[str, str]], Field(description="Additional request headers.")] = None,
    blocked_domains: Annotated[
        Optional[Set[str]], Field(description="Block requests to these domains and their subdomains.")
    ] = None,
    solve_cloudflare: Annotated[
        bool, Field(description="Attempt to solve Cloudflare Turnstile/interstitial challenges.")
    ] = False,
    pierce_shadow: Annotated[
        bool, Field(description="Include open Shadow DOM content; ignored for snapshots.")
    ] = False,
) -> ResponseModel:
    """Fetch a URL in an open stealthy browser session. Options apply only to this request."""
    entry = self._get_session(session_id, expected_type=["stealthy"])
    fetch_params = dict(
        wait=wait,
        timeout=timeout,
        google_search=google_search,
        network_idle=network_idle,
        pierce_shadow=pierce_shadow,
        load_dom=load_dom,
        disable_resources=disable_resources,
        wait_selector=wait_selector,
        wait_selector_state=wait_selector_state,
        extra_headers=extra_headers,
        blocked_domains=blocked_domains,
        solve_cloudflare=solve_cloudflare,
    )
    page = await entry.session.fetch(
        url, **{name: value for name, value in fetch_params.items() if name in _STEALTH_FETCH_KEYS}
    )
    if extraction_type == "snapshot":
        return ResponseModel(
            status=page.status, content=[await self._browser_snapshot(session_id, css_selector)], url=page.url
        )
    return _translate_response(page, extraction_type, css_selector, main_content_only)

session_make_request async

session_make_request(
    url,
    session_id,
    method="GET",
    extraction_type="markdown",
    css_selector=None,
    main_content_only=True,
    params=None,
    data=None,
    json=None,
    headers=None,
    cookies=None,
    timeout=30,
    follow_redirects="safe",
    max_redirects=30,
    retries=3,
    retry_delay=1,
    auth=None,
    verify=True,
    http3=False,
    stealthy_headers=True,
)

Realiza una solicitud HTTP con las cookies, conexiones, identidad de navegador y proxy de la sesión. Las opciones se aplican a esta solicitud.

Código fuente en scrapling/core/ai/server.py
async def session_make_request(
    self,
    url: Annotated[str, Field(description="URL to fetch.")],
    session_id: Annotated[str, Field(description="HTTP session ID from `open_request_session`.")],
    method: Annotated[SUPPORTED_HTTP_METHODS, Field(description="HTTP method.")] = "GET",
    extraction_type: Annotated[extraction_types, Field(description="Content output format.")] = "markdown",
    css_selector: Annotated[
        Optional[str], Field(description="Select matching elements after `main_content_only` filtering.")
    ] = None,
    main_content_only: Annotated[
        bool, Field(description="Sanitize <body> content before selection; False uses the full document.")
    ] = True,
    params: Annotated[Optional[Dict], Field(description="Query parameters.")] = None,
    data: Annotated[Optional[Dict[str, str] | str], Field(description="Form or raw body; ignored for GET.")] = None,
    json: Annotated[Optional[Dict | List], Field(description="JSON body; ignored for GET.")] = None,
    headers: Annotated[Optional[Mapping[str, Optional[str]]], Field(description="Request headers.")] = None,
    cookies: Annotated[Optional[Dict[str, str]], Field(description="Request cookies.")] = None,
    timeout: Annotated[Optional[int | float], Field(description="Timeout in seconds.")] = 30,
    follow_redirects: Annotated[
        FollowRedirects,
        Field(
            description='"safe" blocks redirects to private/internal IPs; True allows all; False disables redirects.'
        ),
    ] = "safe",
    max_redirects: Annotated[int, Field(description="Redirect limit; -1 means unlimited.")] = 30,
    retries: Annotated[
        Optional[int], Field(description="Maximum attempts, including the first; None or values below 1 send once.")
    ] = 3,
    retry_delay: Annotated[Optional[int], Field(description="Seconds between retries.")] = 1,
    auth: Annotated[
        Optional[Dict[str, str]], Field(description='Basic auth: {"username": ..., "password": ...}.')
    ] = None,
    verify: Annotated[Optional[bool], Field(description="Verify TLS certificates.")] = True,
    http3: Annotated[
        Optional[bool], Field(description="Use HTTP/3; may conflict with browser impersonation.")
    ] = False,
    stealthy_headers: Annotated[
        Optional[bool],
        Field(description="Fill missing browser headers and use a Google referer if none was supplied."),
    ] = True,
) -> ResponseModel:
    """Make an HTTP request using the session's cookies, connections, impersonation, and proxy. Options apply to this request."""
    entry = self._get_session(session_id, expected_type=["static"])

    request_kwargs: Dict[str, Any] = dict(
        auth=_normalize_credentials(auth),
        http3=http3,
        verify=verify,
        params=params,
        headers=headers,
        cookies=cookies,
        timeout=timeout,
        retries=retries,
        retry_delay=retry_delay,
        max_redirects=max_redirects,
        follow_redirects=follow_redirects,
        stealthy_headers=stealthy_headers,
    )
    if method != "GET":
        request_kwargs.update(data=data, json=json)

    page = await getattr(entry.session._client, method.lower())(url, **request_kwargs)
    return _translate_response(page, extraction_type, css_selector, main_content_only)

serve

serve(
    http,
    host,
    port,
    allowed_hosts=(),
    allow_unauthenticated=False,
)

Inicia el servidor MCP.

PARÁMETRO DESCRIPCIÓN
http

Usa el transporte streamable-http en lugar de stdio.

TIPO: bool

host

Host en el que escucha cuando http está activo.

TIPO: str

port

Puerto en el que escucha cuando http está activo.

TIPO: int

allowed_hosts

Nombres de host que se aceptan. Activa la protección contra DNS rebinding.

TIPO: Sequence[str] PREDETERMINADO: ()

allow_unauthenticated

Inicia el transporte streamable-http sin token. De forma predeterminada requiere autenticación; esta opción la desactiva de forma explícita.

TIPO: bool PREDETERMINADO: False

Código fuente en scrapling/core/ai/server.py
def serve(
    self,
    http: bool,
    host: str,
    port: int,
    allowed_hosts: Sequence[str] = (),
    allow_unauthenticated: bool = False,
):
    """Serve the MCP server.

    :param http: Serve over the streamable-http transport instead of stdio.
    :param host: The host to bind to when `http` is enabled.
    :param port: The port to bind to when `http` is enabled.
    :param allowed_hosts: Host names to accept, which turns on DNS-rebinding protection.
    :param allow_unauthenticated: Start the streamable-http transport without a token. The transport
        requires authentication by default, so this is the explicit opt-out.
    """
    if not http:
        if self._auth_token:
            log.warning(
                "The authentication token only applies to the streamable-http transport, so it's ignored with stdio."
            )
    elif self._auth_token:
        if allow_unauthenticated:
            log.warning(
                "An authentication token was given, so it takes precedence and the server still requires it."
            )
    elif not allow_unauthenticated:
        raise ValueError(
            f"Refusing to serve the MCP server over HTTP without authentication because anyone who can reach "
            f"{host}:{port} would be able to use every tool, including fetching arbitrary URLs from this machine. "
            f"Pass `--auth-token` (or set the {MCP_AUTH_TOKEN_ENV} environment variable) to require a bearer "
            f"token, or `--no-auth` to serve it unauthenticated anyway."
        )
    else:
        log.warning(
            f"The MCP server is running over HTTP without authentication, so anyone who can reach "
            f"{host}:{port} can use every tool, including fetching arbitrary URLs from this machine."
        )

    server = self._build_server(host, port)
    if http:
        server.run(
            transport="streamable-http",
            host=host,
            port=port,
            transport_security=self._transport_security(allowed_hosts),
        )
    else:
        server.run()