Cómo conectar Scrapeless a ChatGPT con una acción GPT personalizada
Scraping and Proxy Management Expert
TL;DR:
- ChatGPT no puede tomar un servidor MCP con clave API como conector. El MCP en modo desarrollador acepta OAuth 2.1 o sin autenticación, y la documentación de OpenAI dice que ChatGPT "no puede presentar claves API personalizadas".
- La ruta que funciona es una Acción GPT personalizada: un esquema OpenAPI más autenticación con clave API en un encabezado personalizado.
- El encabezado es
x-api-token, noAuthorization: Bearer. Establezca el tipo de autenticación en Clave API, luego Personalizado, y luego ese nombre de encabezado. - Pida Markdown, no HTML. La misma página tiene 8,676 caracteres como Markdown contra 50,403 como HTML — una reducción del 83% en el contexto que el modelo pasa en marcado.
response_typelo hace solo junto ajs_render: true. Deje fuerajs_rendery la misma solicitud devuelve 50,368 caracteres de HTML con HTTP 200.outputFormates aceptado e ignorado silenciosamente, devolviendo los 50,403 caracteres completos de HTML.- El esquema a continuación pasa
openapi-spec-validatorcontra OpenAPI 3.1.0, y la solicitud que describe se ejecutó en vivo:{code: 200, data: string}. - Obtenga una clave en el plan gratuito de Scrapeless antes de comenzar.
Pregunte a ChatGPT sobre una página que no ha visto y obtendrá un resumen de sus datos de entrenamiento o un resultado de búsqueda que no puede controlar. Una Acción cambia la disposición: le entrega al modelo una operación HTTP que puede llamar, con parámetros que usted definió, contra una API que eligió.
La primera cosa que hay que resolver es qué mecanismo aceptará realmente ChatGPT, porque la respuesta obvia es incorrecta.
Por qué Esto Es una Acción y No un Conector MCP
Cada otro cliente importante toma el servidor MCP de Scrapeless como un conector HTTP remoto con la clave en un encabezado. ChatGPT no lo hace, y vale la pena ver por qué antes de construir sobre ello.
El punto final requiere un encabezado estático. Llamado sin uno:
text
POST https://api.scrapeless.com/mcp (no auth)
-> HTTP 401
body: Unauthorized: Missing x-api-token header
www-authenticate: None
Ese encabezado www-authenticate faltante importa. Bajo el marco de autenticación HTTP, un 401 es donde un servidor anuncia cómo autenticarse, y un cliente que busca un desafío OAuth no encuentra nada a seguir. Tampoco hay metadatos de OAuth por descubrir:
text
/.well-known/oauth-protected-resource 404
/.well-known/oauth-authorization-server 404
/.well-known/oauth-protected-resource/mcp 404
La especificación del Protocolo de Contexto del Modelo permite cualquiera de los dos arreglos: un token desnudo en un encabezado es un despliegue MCP perfectamente ordinario. La restricción está del lado de ChatGPT: sus conectores en modo desarrollador soportan OAuth 2.1 o sin autenticación, y la documentación de OpenAI establece claramente que ChatGPT no puede presentar claves API personalizadas.
Así que no hay URL para pegar. El camino soportado para una API HTTP con clave es una Acción GPT, que sí soporta la autenticación con clave API con un nombre de encabezado que usted elija.
Requisitos Previos
- Un plan de ChatGPT que incluya la creación de GPTs.
- Una clave API de Scrapeless.
- Sin alojamiento, sin proxy, sin proceso local. La Acción llama a
api.scrapeless.comdirectamente.
Paso 1: El Esquema OpenAPI
Una Acción es un documento OpenAPI que describe una o más operaciones. Esta describe una sola operación: recuperar una página renderizada y devolverla como Markdown.
yaml
openapi: 3.1.0
info:
title: Scrapeless Universal Scraping API
description: Fetch a fully rendered web page and return it as Markdown or HTML.
version: "1.0.0"
servers:
- url: https://api.scrapeless.com
paths:
/api/v2/unlocker/request:
post:
operationId: scrapeWebPage
summary: Fetch a web page with JavaScript rendering and return it as Markdown
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [actor, input]
properties:
actor:
type: string
enum: [unlocker.webunlocker]
description: The Scrapeless actor to run.
input:
type: object
required: [url, js_render, response_type]
properties:
url:
type: string
format: uri
description: The page to fetch.
js_render:
type: boolean
enum: [true]
default: true
description: Must be true. response_type only takes effect when JavaScript rendering is on.
response_type:
type: string
enum: [markdown, html]
default: markdown
description: Return the page as Markdown or raw HTML.
responses:
"200":
description: The rendered page.
content:
application/json:
schema:
type: object
properties:
code:
type: integer
data:
type: string
description: The rendered page, as Markdown or HTML.
"401":
description: Missing or invalid API token.
components:
securitySchemes:
scrapelessApiKey:
type: apiKey
in: header
name: x-api-token
security:
- scrapelessApiKey: []
Tres elecciones deliberadas allí.
El actor es un enum con un valor en lugar de una cadena libre. Un modelo dado un campo de texto libre eventualmente inventará un nombre de actor; un enum hace que el único valor válido sea la única opción.
operationId es scrapeWebPage, y ese es el nombre que usted referencia en las instrucciones del GPT. Un id vago produce selección de herramientas vaga.
response_type tiene como valor predeterminado markdown, por la razón en el paso 3, y tanto él como js_render se listan como requeridos. Un valor predeterminado en el esquema es documentación: no hace que el modelo envíe el campo, y el propio valor predeterminado de la API para js_render está desactivado.
Valida antes de pegar vale los treinta segundos — la especificación OpenAPI 3.1.0 es estricta sobre la estructura, y los mensajes de error del constructor son breves:
bash
pip install openapi-spec-validator
bash
python3 -c "
from openapi_spec_validator import validate
from openapi_spec_validator.readers import read_from_filename
spec, _ = read_from_filename('scrapeless-action.yaml')
validate(spec)
print('valid')"
text
valid
Paso 2: Autenticación
En el constructor de GPT, abra el panel de autenticación de la Acción y establezca:
| Campo | Valor |
|---|---|
| Tipo de Autenticación | Clave API |
| Tipo de Autenticación | Personalizado |
| Nombre de Encabezado Personalizado | x-api-token |
| Clave API | su clave de Scrapeless |
El valor predeterminado bajo Clave API es Bearer, que envía Authorization: Bearer <key>. Scrapeless lee x-api-token y nada más, así que dejar el valor predeterminado produce un 401 que el constructor solo muestra cuando se llama a la Acción por primera vez — después de que el esquema ya se ha validado.
Nota: el constructor es una interfaz web, por lo que este paso no se ejecutó como parte de la verificación de este artículo. Cada afirmación sobre la API en sí — el esquema, el nombre del encabezado, la forma de respuesta y los tamaños a continuación — proviene de llamadas en vivo contra api.scrapeless.com.
Paso 3: Solicitar Markdown
Esta configuración única decide cuánta parte del contexto del modelo gasta el conector antes de haber leído algo, y la diferencia es medible.
La misma página de categoría, obtenida dos veces:
text
response_type=markdown 8,676 chars
default (html) 50,403 chars
Markdown es un 83% más pequeño. La respuesta de una acción GPT va al contexto del modelo, por lo que devolver HTML gasta la mayor parte de ese presupuesto en etiquetas, scripts en línea y atributos que el modelo ignorará.
Hay una trampa al lado. outputFormat parece que debería funcionar y es aceptada sin quejas:
text
input.response_type = "markdown" -> 8,676 chars (markdown)
input.outputFormat = "markdown" -> 50,403 chars (HTML)
La segunda llamada tuvo éxito, devolvió HTTP 200 y devolvió HTML silenciosamente porque outputFormat no es un parámetro que el actor lee. Una clave desconocida que se ignora en lugar de rechazarse es el tipo de error más difícil — nada falla, la salida simplemente tiene una forma incorrecta y es casi seis veces más grande de lo que presupusiste.
La segunda trampa es más silenciosa. response_type solo tiene efecto cuando la representación de JavaScript está activada, y el valor predeterminado de la API está desactivado. Envía response_type: "markdown" sin js_render: true y la llamada devuelve HTTP 200 con 50,368 caracteres de HTML, sin error y sin advertencia. El esquema anterior fija js_render en true y lo enumera como requerido exactamente por esta razón, y las instrucciones a continuación nombran ambos campos.
¿Estás construyendo esto ahora? El plan gratuito de Scrapeless cubre suficientes solicitudes para probar la acción de principio a fin.
Paso 4: Instrucciones que la llaman
El esquema le da al modelo una capacidad; las instrucciones deciden cuándo lo alcanza. Nombra la operación explícitamente:
text
When the user gives you a URL, or asks about the current contents of a
specific page, call scrapeWebPage with that URL, js_render true and
response_type "markdown". Do not answer from memory when a URL is present.
Return what the page says, and quote the exact figures it contains rather
than paraphrasing them. If scrapeWebPage reports a 401, tell the user the
API key is missing or misconfigured and stop.
El primer párrafo vincula la herramienta a un desencadenador. Sin él, un modelo con capacidad de navegación propia a veces usará eso en su lugar y producirá resultados en los que tu esquema no tuvo parte.
Lo que regresa
El sobre de respuesta son dos campos, y el esquema anterior declara ambos:
json
{
"code": 200,
"data": "- [Home](https://books.toscrape.com/index.html)\n- [Books](...)\n..."
}
Verificado contra la API en vivo con exactamente el cuerpo que el esquema describe:
text
HTTP 200
response keys : ['code', 'data']
code : 200 (int)
data : str, 50403 chars
schema match : code=integer:True data=string:True
code es el estado propio de Scrapeless, distinto del estado HTTP — ambos eran 200 aquí. data es una sola cadena, razón por la cual el modelo recibe un documento en lugar de una estructura; si quieres campos, pídelo en las instrucciones o analízalos tú mismo más adelante.
Conclusión
El conector es una operación y un encabezado. ChatGPT no aceptará un servidor MCP con clave de API — ese es un límite de plataforma, confirmado por un 401 sin desafío OAuth, tres 404 donde estarían los metadatos, y la propia declaración de OpenAI — por lo que el mecanismo es una acción, y el mecanismo no es la parte difícil.
Las dos decisiones que determinan si funciona bien son ambas pequeñas. Establece el encabezado personalizado en x-api-token, porque el valor predeterminado de Bearer falla en el momento de la llamada en lugar de en la configuración. Y establece response_type en markdown junto a js_render: true, porque 8,676 caracteres de Markdown dejan espacio para pensar donde 50,403 caracteres de HTML no lo hacen — y porque outputFormat, que parece plausible, es aceptado, ignorado y devuelve el más grande.
Para la misma API impulsada desde código en lugar de un GPT, nuestra guía de raspado web de ChatGPT cubre el patrón modelo-más-obtener, la página de API Universal de Raspado describe al actor detrás de la operación, la documentación lleva la referencia completa de parámetros, y los precios enumeran cuánto cuesta cada llamada.
¿Listo para darle a ChatGPT una obtención que controlas? Comienza con el plan gratuito de Scrapeless y pega el esquema.
FAQ
P: ¿Puede ChatGPT conectarse a un servidor MCP?
Sí, pero solo uno utilizando OAuth 2.1 o sin autenticación. Los conectores en modo desarrollador no pueden presentar una clave API estática, lo que la documentación de OpenAI afirma directamente. Un servidor como el endpoint Scrapeless MCP, que se autentica en un encabezado x-api-token y no publica metadatos de OAuth, por lo tanto, no puede ser agregado como un conector de ChatGPT: una Acción GPT es la ruta soportada para ello.
Q: ¿Por qué mi Acción GPT devuelve un 401?
La mayoría de las veces el nombre del encabezado. El tipo de autenticación de clave API predetermina a Bearer, que envía Authorization: Bearer <key>; Scrapeless lee x-api-token. Establezca el tipo de autenticación en Personalizado y el nombre del encabezado en x-api-token. El esquema se valida de cualquier manera, así que esto surge en la primera llamada en lugar de durante la configuración.
Q: ¿Qué versión de OpenAPI necesitan las Acciones GPT?
El esquema anterior es OpenAPI 3.1.0 y se valida contra esa especificación. Mantenga el documento minimalista: una URL de servidor, valores operationId explícitos y ninguna indirection $ref que no necesite, porque el analizador del constructor es más estricto y sus errores menos específicos que los de un validador dedicado.
Q: ¿Cómo puedo evitar que la Acción llene el contexto del modelo?
Devuelva Markdown. Establecer response_type en markdown, con js_render: true en la misma solicitud, redujo la misma página de 50,403 caracteres a 8,676, y la respuesta de la Acción se gasta del presupuesto de contexto de la conversación. También estreche el esquema: una operación con un pequeño conjunto de parámetros le da al modelo menos espacio para construir una llamada costosa.
Q: ¿Por qué mi parámetro outputFormat no hizo nada?
Porque no es un parámetro que el actor lea. La solicitud aún devolvió HTTP 200 y el HTML completo: 50,403 caracteres en lugar de 8,676. La clave correcta es response_type, y necesita js_render: true junto a ella. Las claves desconocidas se ignoran en lugar de ser rechazadas aquí, así que verifique el tamaño de lo que regresó cuando una configuración de formato parece no tener efecto.
Q: ¿Puede una Acción exponer más de una capacidad de Scrapeless?
Sí: agregue una ruta y un operationId por operación en el mismo documento. Mantenga cada una estrecha y mantenga las restricciones enum, ya que una única operación con un campo de actor de texto libre invita al modelo a adivinar. El menor privilegio también hace que la Acción sea más fácil de revisar más tarde.
Q: ¿Esto funciona en una conversación normal de ChatGPT o solo en un GPT personalizado?
Las Acciones pertenecen a un GPT que usted configura, por lo que la capacidad reside en ese GPT en lugar de en cada conversación. Cualquiera con quien lo comparta obtiene la operación; si proporcionan su propia clave depende de cómo configure la autenticación.
En Scrapeless, solo accedemos a datos disponibles públicamente y cumplimos estrictamente con las leyes, regulaciones y políticas de privacidad del sitio web aplicables. El contenido de este blog es sólo para fines de demostración y no implica ninguna actividad ilegal o infractora. No ofrecemos garantías y renunciamos a toda responsabilidad por el uso de la información de este blog o enlaces de terceros. Antes de realizar cualquier actividad de scraping, consulte a su asesor legal y revise los términos de servicio del sitio web de destino u obtenga los permisos necesarios.



