Cómo crear tu propio servidor MCP para recopilar datos de sitios web: guía paso a paso para principiantes
Contenido del artículo
- Introducción: qué obtendrás al terminar esta guía
- Preparación previa: herramientas, accesos y requisitos del sistema
- Conceptos básicos: cómo funciona un servidor mcp y para qué le sirve a un agente de ia
- Paso 1: creamos el proyecto e instalamos las dependencias
- Paso 2: escribimos un servidor mcp mínimo con la primera herramienta
- Paso 3: conectamos el servidor mcp al cliente de ia
- Paso 4: agregamos herramientas de extracción de datos
- Paso 5: conectamos proxies móviles y rotación de ip
- Paso 6: hacemos el servidor confiable: reintentos, demoras, caché y límites
- Verificación del resultado: lista de control de un servidor mcp terminado
- Errores típicos al crear un servidor mcp y sus soluciones
- Funciones adicionales: bloque para avanzados
- Faq: preguntas frecuentes sobre crear un servidor mcp
- Conclusión: qué hiciste y hacia dónde seguir
Introducción: qué obtendrás al terminar esta guía
Imagina que abres un chat con un asistente de IA y escribes: «Entra a la página de un competidor, recopila los nombres y precios de todos los productos del catálogo y arma una tabla». El asistente no responde «no tengo acceso a internet», sino que realmente carga la página, extrae los datos y te entrega el resultado listo. Eso es exactamente lo que vas a construir si llegas hasta el final de esta guía. El eslabón que conecta el modelo de lenguaje con la web será tu propio servidor MCP, escrito en Python.
Aclaración importante: no vamos a analizar el Playwright MCP ya listo ni otras soluciones empaquetadas. Sobre eso hay materiales aparte en el blog. Aquí la tarea es otra: escribir un servidor desde cero para que entiendas cada línea, puedas agregar tus propias herramientas, conectar proxies móviles y adaptar la lógica a tareas concretas. Una solución propia siempre es más flexible que una ajena.
Para quién es esta guía
- Marketeros y dueños de negocios que necesitan recopilar rápido precios, reseñas, descripciones de productos y contenido de la competencia sin encargar un scraper a un desarrollador.
- Arbitrajistas que monitorean ofertas, landings y creativos y quieren delegar la rutina a un agente de IA.
- Desarrolladores que han oído hablar del protocolo MCP pero todavía no armaron su propio servidor y quieren una plantilla funcional.
- Usuarios de proxies móviles a quienes les importa que las solicitudes del agente salgan por su proxy y no directamente desde su IP doméstica.
Qué necesitas saber de antemano
La guía está pensada para principiantes. No hace falta experiencia en programación, pero sí ayuda entender qué es la línea de comandos y cómo abrir un archivo en un editor de texto. Todo el código se puede copiar tal cual, y cada parte está explicada en lenguaje sencillo. Si ya programas en Python, hay un bloque aparte con funciones avanzadas cerca del final del artículo.
Cuánto tiempo tomará
Calcula 2-3 horas para la primera pasada. Instalar las herramientas toma unos 30 minutos, un servidor MCP mínimo y funcional aparece en una hora, y el tiempo restante se va en agregar herramientas de extracción de datos, conectar el proxy y hacer pruebas. Repetir todo desde cero en otra computadora te tomará ya solo 20-30 minutos.
Preparación previa: herramientas, accesos y requisitos del sistema
Antes de escribir código, asegúrate de tener todo lo necesario. Esta sección se completa en media hora y te ahorra la mitad de los problemas típicos en las etapas siguientes.
Requisitos del sistema
- Una computadora con Windows 10/11, macOS 12 o superior, o Linux (Ubuntu 22.04 o superior). Todo lo descrito funciona en cualquiera de estos sistemas; las diferencias están solo en las rutas de los archivos.
- Mínimo 4 GB de memoria RAM y 1 GB de espacio libre en disco.
- Acceso estable a internet.
Qué instalar
- Python 3.11 o superior. En 2026 las versiones actuales son 3.12 y 3.13. Descarga el instalador desde el sitio oficial del proyecto Python. En Windows, en la primera ventana del instalador, marca obligatoriamente la casilla Add python.exe to PATH, de lo contrario el comando python no se encontrará en la terminal. En macOS es más cómodo instalar Python con Homebrew con el comando brew install python. En Ubuntu ejecuta sudo apt install python3 python3-venv python3-pip.
- Un editor de texto para código. Recomendamos Visual Studio Code. Es gratis, resalta la sintaxis y muestra los errores. También sirve cualquier otro editor, incluso el Bloc de notas, pero con VS Code te resultará más cómodo.
- Un cliente MCP, es decir, una aplicación con agente de IA a la que conectarás el servidor. La opción más simple para principiantes es Claude Desktop. También admiten MCP el editor Cursor, VS Code con la extensión GitHub Copilot y varias otras herramientas. Instala al menos una antes de empezar.
- Node.js 20 o superior. No hace falta para el servidor en sí, sino para la utilidad MCP Inspector, con la que depuraremos las herramientas. Descarga el instalador de la versión LTS desde el sitio oficial de Node.js e instálalo con las opciones por defecto.
Accesos
Para la sección de proxies necesitarás los datos de tu proxy móvil: host, puerto, usuario y contraseña, además del enlace para cambiar la dirección IP, si tu plan lo admite. Todo esto está en el panel de tu proveedor. Si aún no tienes proxy, puedes hacer la guía sin él: el servidor funcionará directamente y agregarás el proxy después con una sola línea.
Copias de seguridad
Vamos a editar el archivo de configuración del cliente MCP. Antes, cópialo a un lugar seguro, por ejemplo al escritorio con la etiqueta «backup». Si algo sale mal, simplemente devuelves la copia a su lugar. Guarda el código del servidor en una carpeta aparte y después de cada paso funcional guarda una copia del archivo o haz un commit en Git si sabes usarlo.
Consejo: Crea en el disco una carpeta aparte con una ruta corta, sin espacios ni caracteres cirílicos, por ejemplo C:/mcp-collector en Windows o ~/mcp-collector en macOS y Linux. Los espacios y las letras rusas en las rutas rompen con frecuencia el arranque de servidores desde los archivos de configuración, y terminarás perdiendo una hora buscando la causa.
Conceptos básicos: cómo funciona un servidor MCP y para qué le sirve a un agente de IA
Antes de escribir la primera línea de código, aclaremos los términos. Sin esto, la instrucción parecerá un conjunto de conjuros mágicos; con esto, cada acción tendrá lógica.
Qué es MCP
MCP (Model Context Protocol) es un protocolo abierto que describe cómo se comunica un modelo de lenguaje con herramientas externas. Antes de su aparición, cada servicio inventaba su propia forma de «darle manos a la IA». MCP lo estandarizó: si escribiste un servidor según el protocolo, lo entenderá cualquier cliente compatible, ya sea Claude Desktop, Cursor o tu propio agente. Se puede comparar MCP con un conector USB: no importa qué conectes, una memoria o un mouse, el conector es siempre el mismo.
Cliente y servidor
En la arquitectura MCP hay dos participantes. El cliente es la aplicación con IA que hace preguntas y llama a las herramientas. El servidor MCP es el programa que ofrece esas herramientas. En nuestro caso, el servidor será la habilidad de «entrar a internet y sacar datos», y el cliente será tu asistente de IA. El servidor se ejecuta localmente en tu computadora y el cliente se comunica con él directamente.
Herramientas, recursos y prompts
Un servidor MCP puede entregar al cliente tres tipos de entidades:
- Herramientas (tools) — funciones que el modelo puede llamar: «descarga la página», «extrae todos los enlaces», «cambia la IP del proxy». Es la base de nuestra guía.
- Recursos (resources) — datos que el servidor ofrece para leer, por ejemplo el contenido de un archivo de configuración o el resultado del último scraping.
- Prompts — plantillas de consulta predefinidas que el usuario puede invocar con un solo comando.
Para recopilar datos basta con las herramientas. Los recursos y los prompts los veremos en el bloque avanzado.
Cómo entiende el modelo qué llamar
Aquí hay un matiz importante. Cuando el cliente se conecta al servidor, solicita la lista de herramientas con sus nombres, descripciones y parámetros. Esas descripciones entran en el contexto del modelo. Luego el modelo decide por sí mismo qué herramienta llamar y con qué argumentos, basándose justamente en el texto de la descripción. Por eso las descripciones de las funciones en nuestro código no son un formalismo, sino una instrucción para la IA. Cuanto más claro escribas qué hace la herramienta y cuándo usarla, más preciso trabajará el agente.
Transporte: stdio y HTTP
El servidor y el cliente deben intercambiar mensajes de alguna forma. El protocolo contempla dos maneras principales. stdio — el cliente mismo lanza tu script como proceso hijo y se comunica con él a través de la entrada y salida estándar. Es la opción más simple para trabajo local, y con ella empezaremos. Streamable HTTP — el servidor funciona como un servicio web al que el cliente se conecta por una dirección. Esta opción hace falta si el servidor vive en una máquina remota o si varios clientes se conectan a él. La veremos en el bloque avanzado.
⚠️ Atención: Con el transporte stdio, toda la salida estándar del proceso está ocupada por los mensajes de servicio del protocolo. Si escribes en el código un print normal para depurar, el cliente recibirá basura en lugar de una respuesta correcta y cortará la conexión. Los mensajes de depuración solo se pueden enviar al flujo de errores stderr. Memoriza esta regla, te ahorrará mucho tiempo.
Por qué es cómodo recopilar datos vía MCP
Un scraper clásico está rígidamente definido: sabe recopilar campos concretos de un sitio concreto. Apenas cambia el maquetado, el scraper se rompe. La combinación «agente de IA más servidor MCP» funciona de otra manera: el servidor da herramientas universales (descargar, extraer texto, encontrar elementos por selector) y el modelo se encarga de entender la estructura de la página y formular el resultado. Obtienes flexibilidad sin reescribir código para cada nueva fuente.
Paso 1: Creamos el proyecto e instalamos las dependencias
Objetivo de la etapa: preparar un entorno Python aislado e instalar las bibliotecas que necesita el servidor MCP. Al final del paso tendrás una carpeta de proyecto con un entorno virtual funcional.
Para qué hace falta un entorno virtual
Un entorno virtual es una copia aparte de Python con sus propias bibliotecas dentro de la carpeta del proyecto. Hace falta para que nuestro servidor no entre en conflicto con otros programas de Python en la computadora y para que el cliente MCP sepa exactamente qué intérprete lanzar. Sin él, la mitad de los problemas del tipo «en mi terminal funciona, pero en el cliente no» están garantizados.
Instrucciones paso a paso
- Abre la terminal. En Windows presiona Win+R, escribe powershell y presiona Enter. En macOS abre la aplicación Terminal desde Spotlight (Cmd+Espacio, luego escribe Terminal). En Linux presiona Ctrl+Alt+T.
- Crea la carpeta del proyecto y entra en ella. En Windows ejecuta dos comandos: mkdir C:/mcp-collector, luego cd C:/mcp-collector. En macOS y Linux: mkdir ~/mcp-collector, luego cd ~/mcp-collector.
- Verifica la versión de Python con el comando python --version (en macOS y Linux puede hacer falta python3 --version). Deberías ver una línea del tipo Python 3.12.x. Si la versión es inferior a 3.11 o el comando no se encuentra, vuelve a la sección de preparación y reinstala Python.
- Crea el entorno virtual con el comando python -m venv .venv. En la carpeta del proyecto aparecerá una carpeta oculta .venv. Esto toma 10-20 segundos.
- Activa el entorno. En Windows en PowerShell: .venv/Scripts/Activate.ps1. Si PowerShell dice que la ejecución de scripts está prohibida, ejecuta el comando Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, confirma con la letra Y y repite la activación. En macOS y Linux: source .venv/bin/activate. Tras la activación aparecerá la marca (.venv) al inicio de la línea de la terminal.
- Actualiza el gestor de paquetes: python -m pip install --upgrade pip.
- Instala las bibliotecas con un solo comando: pip install "mcp[cli]" httpx beautifulsoup4. Aquí mcp es el SDK oficial de Python del protocolo (en 2026 la rama actual es la 1.x), httpx es una biblioteca moderna para solicitudes HTTP con soporte de proxy, beautifulsoup4 es la herramienta para parsear HTML. La instalación tomará 1-2 minutos.
- Crea un archivo vacío server.py en la carpeta del proyecto. En VS Code: abre la carpeta con File, Open Folder, luego presiona el ícono de nuevo archivo en el panel izquierdo y escribe el nombre.
Qué significan las bibliotecas
- mcp se encarga de todo el protocolo: registro de herramientas, intercambio de mensajes, descripción de parámetros. El módulo FastMCP dentro de él permite declarar una herramienta como una función normal con un decorador.
- httpx descarga las páginas. A diferencia del obsoleto requests, soporta HTTP/2, asincronía y configuración cómoda de proxy.
- beautifulsoup4 convierte el HTML en un árbol por el que es fácil buscar elementos por etiquetas y selectores CSS.
Consejo: Memoriza de inmediato la ruta completa al intérprete dentro del entorno virtual. En Windows es C:/mcp-collector/.venv/Scripts/python.exe, en macOS y Linux — /Users/nombre/mcp-collector/.venv/bin/python (o /home/nombre/... en Linux). La necesitarás al conectar con el cliente. Puedes averiguar la ruta exacta con el comando where python en Windows o which python en macOS y Linux con el entorno activado.
✅ Verificación: Ejecuta el comando pip list. En la lista deben aparecer los paquetes mcp, httpx y beautifulsoup4. También ejecuta python -c "import mcp, httpx, bs4; print('ok')" — debe aparecer la palabra ok sin errores.
Posibles problemas
- No se encuentra el comando python. En Windows reinstala Python con la casilla Add to PATH marcada. En macOS usa python3 en lugar de python.
- pip se queja de permisos de acceso. Lo más probable es que el entorno no esté activado y estés instalando paquetes en el Python del sistema. Verifica la marca (.venv) al inicio de la línea.
- Error de compilación al instalar. Actualiza pip e inténtalo de nuevo. Si no ayuda, verifica que la versión de Python no sea inferior a 3.11.
Paso 2: Escribimos un servidor MCP mínimo con la primera herramienta
Objetivo de la etapa: escribir un servidor MCP funcional con una herramienta que descarga una página por su dirección y devuelve su HTML. Es la base sobre la que iremos agregando funciones.
Código del servidor
Abre el archivo server.py y pega en él el siguiente código completo:
import sys
import httpx
from mcp.server.fastmcp import FastMCP
mcp = FastMCP('web-collector')
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
}
def log(message: str) -> None:
print(message, file=sys.stderr)
@mcp.tool()
def fetch_page(url: str, max_chars: int = 20000) -> str:
'''Скачивает страницу по указанному URL и возвращает её HTML-код.
Используй, когда нужно посмотреть исходную разметку страницы.
Параметр max_chars ограничивает длину ответа, чтобы не переполнять контекст.'''
log(f'fetch_page: {url}')
with httpx.Client(headers=HEADERS, timeout=20.0, follow_redirects=True) as client:
response = client.get(url)
response.raise_for_status()
return response.text[:max_chars]
if __name__ == '__main__':
mcp.run()Análisis del código línea por línea
- FastMCP('web-collector') crea el objeto del servidor con el nombre web-collector. El cliente mostrará este nombre en la lista de servidores conectados.
- HEADERS — los encabezados que enviamos a los sitios. Muchos sitios entregan contenido incompleto o un error si la solicitud llega sin un User-Agent habitual de navegador. El encabezado Accept-Language indica que queremos la versión de la página en ruso.
- La función log escribe mensajes en stderr. Justamente así, y no con un print normal, porque stdout está ocupado por el protocolo. Estos mensajes los verás en los logs del cliente y en MCP Inspector.
- @mcp.tool() — el decorador que convierte una función normal en una herramienta MCP. El SDK lee automáticamente el nombre de la función, los tipos de parámetros y el docstring y arma la descripción para el modelo. El valor por defecto max_chars = 20000 significa que el parámetro es opcional.
- El docstring entre triples comillas es lo que leerá la IA. Aquí explicamos qué hace la herramienta y cuándo aplicarla. Escribe estas descripciones con detalle y en el idioma en el que te comunicas con el agente.
- httpx.Client con el parámetro follow_redirects=True pasa automáticamente por las redirecciones, y timeout=20.0 evita que la solicitud quede colgada indefinidamente.
- raise_for_status() lanza un error si el sitio devuelve un código 4xx o 5xx. El SDK lo capturará y devolverá al cliente un mensaje de error comprensible en lugar de silencio.
- mcp.run() arranca el servidor con el transporte stdio por defecto. Quedará esperando comandos del cliente.
Primera verificación con MCP Inspector
Ejecutar server.py directamente no sirve de nada: esperará mensajes del cliente y no mostrará nada. Para verificar usamos MCP Inspector — una interfaz web que imita al cliente y permite llamar a las herramientas a mano.
- Asegúrate de que el entorno virtual esté activado y de estar en la carpeta del proyecto.
- Ejecuta el comando mcp dev server.py. Este comando viene incluido en el paquete mcp instalado con la extensión cli. En el primer arranque descargará Inspector a través de npx, esto tomará alrededor de un minuto.
- En la terminal aparecerá una dirección del tipo http://localhost:6274 y, en las versiones nuevas, un token de acceso. Abre la dirección en el navegador (a menudo se abre sola).
- En el panel izquierdo de Inspector verifica que esté seleccionado el transporte STDIO, el comando — python, los argumentos — server.py. Presiona el botón Connect.
- El indicador de estado se pondrá verde con la etiqueta Connected. Ve a la pestaña Tools en el menú superior y presiona List Tools.
- En la lista aparecerá la herramienta fetch_page con la descripción del docstring y dos parámetros. Haz clic en ella.
- En el campo url escribe https://example.com, deja el campo max_chars vacío o escribe 5000. Presiona Run Tool.
- A la derecha aparecerá el resultado: el código HTML de la página, comenzando con la etiqueta doctype. Abajo, en la pestaña de logs del servidor, verás la línea fetch_page: https://example.com.
✅ Verificación: Inspector muestra el estado Connected, en la lista de Tools está fetch_page, la llamada con la dirección example.com devuelve HTML sin errores. Si todo está así, tu primer servidor MCP funciona.
Posibles problemas
- mcp dev dice que no se encuentra npx. No está instalado Node.js. Instálalo y reinicia la terminal.
- Inspector se abrió pero Connect da error. Verifica que en el campo de comando esté indicado python del entorno activado. Puedes escribir la ruta completa al python.exe dentro de .venv.
- Error SyntaxError al conectar. El código se copió con pérdida de indentación. En Python la indentación es obligatoria: el cuerpo de las funciones se desplaza cuatro espacios. Revisa el archivo en el editor.
- La herramienta devuelve error 403. El sitio no aceptó la solicitud. Con example.com no pasará, pero para sitios reales volveremos a esto en el paso del proxy.
Paso 3: Conectamos el servidor MCP al cliente de IA
Objetivo de la etapa: registrar el servidor en la configuración del cliente de IA para que el agente vea tu herramienta y pueda llamarla desde un chat normal. Analizaremos la conexión a Claude Desktop como la opción más común y mostraremos brevemente las alternativas.
Conexión a Claude Desktop
- Abre Claude Desktop. Entra a la configuración: en Windows a través del menú en la esquina superior izquierda, opción Settings; en macOS a través del menú Claude, opción Settings.
- Ve a la pestaña Developer y presiona el botón Edit Config. Se abrirá la carpeta con el archivo claude_desktop_config.json. Si el archivo no existe, el cliente lo creará.
- Haz una copia de seguridad de este archivo, copiándolo al escritorio.
- Abre el archivo en VS Code u otro editor. Si el archivo está vacío, pega el contenido completo. Si ya tiene otros servidores, agrega tu bloque dentro del objeto mcpServers separado por una coma.
{
"mcpServers": {
"web-collector": {
"command": "C:/mcp-collector/.venv/Scripts/python.exe",
"args": ["C:/mcp-collector/server.py"]
}
}
}En macOS y Linux reemplaza las rutas por las tuyas, por ejemplo /Users/ivan/mcp-collector/.venv/bin/python y /Users/ivan/mcp-collector/server.py. Ojo: incluso en Windows las rutas se escriben con barras inclinadas. Así es más simple, porque las barras invertidas en JSON hay que duplicarlas, y las inclinadas Windows las entiende sin problemas.
- Guarda el archivo. Asegúrate de que no haya comas de más después del último elemento y de que todas las llaves estén cerradas. Una coma de más hace que el JSON sea inválido y el cliente ignorará la configuración en silencio.
- Cierra Claude Desktop por completo y vuelve a abrirlo. En Windows no basta con cerrar la ventana: haz clic derecho en el ícono de la bandeja del sistema y elige Quit. El cliente lee la configuración solo al arrancar.
- Tras el arranque, abre un chat nuevo. Debajo del campo de entrada busca el ícono de herramientas (el símbolo de controles deslizantes o de conector). Haz clic en él: en la lista debe estar el servidor web-collector con una herramienta fetch_page.
- Escribe en el chat: «Descarga la página https://example.com con fetch_page y dime cuál es el título de esta página». El cliente pedirá permiso para llamar a la herramienta. Presiona Allow o Allow for this chat.
- En un par de segundos el agente responderá que el título de la página es Example Domain. Hizo una solicitud real a través de tu servidor.
Conexión a Cursor y VS Code
En Cursor abre Settings, sección MCP, presiona Add new global MCP server. Se abrirá el archivo mcp.json con exactamente la misma estructura que en Claude Desktop. Pega el mismo bloque y guarda. En VS Code con Copilot crea en la raíz de la carpeta de trabajo el archivo .vscode/mcp.json, donde en lugar de la clave mcpServers se usa la clave servers, y dentro — los mismos command y args. Tras guardar, sobre el bloque del servidor aparecerá el botón Start. En todos los clientes el principio es igual: indicar el comando de arranque del intérprete y la ruta al script.
Consejo: En command indica exactamente el python del entorno virtual, y no solo la palabra python. El cliente lanza el proceso con su propio conjunto de variables de entorno, y el comando python del sistema puede resultar ser otra versión sin las bibliotecas instaladas. La ruta completa elimina este problema de una vez por todas.
✅ Verificación: En la interfaz del cliente se ve el servidor web-collector, el agente a pedido llama a fetch_page y resume correctamente el contenido de la página example.com. En los logs del cliente (en Claude Desktop es la carpeta logs junto a la configuración, el archivo mcp-server-web-collector.log) se ve la línea fetch_page: https://example.com.
Posibles problemas
- El servidor no aparece en la lista. Verifica que el JSON sea válido: pega el contenido en cualquier validador de JSON en línea o ábrelo en VS Code, que subrayará los errores. Asegúrate de que el cliente se haya reiniciado por completo.
- Junto al servidor hay un indicador rojo de error. Abre el archivo de log. Lo más común es ver ModuleNotFoundError: se indicó el python equivocado. Verifica la ruta en command.
- El agente dice que no puede acceder a internet. No vio la herramienta. Asegúrate de que las herramientas estén activadas en el panel de controles deslizantes y pídele explícitamente: «usa la herramienta fetch_page».
- Error spawn ENOENT. La ruta a python o a server.py está mal escrita. Copia la ruta desde el explorador y reemplaza las barras invertidas por inclinadas.
Paso 4: Agregamos herramientas de extracción de datos
Objetivo de la etapa: enseñar al servidor a entregar no HTML crudo, sino datos útiles: texto limpio, lista de enlaces y elementos por selector CSS. Después de esto, el agente podrá recopilar información estructurada sin gastar contexto en el maquetado.
Por qué fetch_page sola no alcanza
El HTML de una página real pesa cientos de kilobytes, y la mayor parte son scripts, estilos y maquetado de servicio. Si le entregamos todo al modelo cada vez, pronto chocará con el límite de contexto y pagarás por tokens de más. La estrategia correcta: el servidor hace la limpieza y estructuración gruesa, y el modelo trabaja ya con datos compactos. Por eso agregaremos tres herramientas especializadas.
Código actualizado
Reemplaza el contenido de server.py por la versión ampliada. La función fetch_page se mantiene, pero la lógica común de descarga se extrajo a una función aparte _get_html, que usan todas las herramientas.
import sys
from urllib.parse import urljoin
import httpx
from bs4 import BeautifulSoup
from mcp.server.fastmcp import FastMCP
mcp = FastMCP('web-collector')
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
}
def log(message: str) -> None:
print(message, file=sys.stderr)
def _get_html(url: str) -> str:
log(f'GET {url}')
with httpx.Client(headers=HEADERS, timeout=20.0, follow_redirects=True) as client:
response = client.get(url)
response.raise_for_status()
return response.text
def _clean(text: str) -> str:
return ' '.join(text.split())
@mcp.tool()
def fetch_page(url: str, max_chars: int = 20000) -> str:
'''Возвращает сырой HTML страницы. Используй только когда нужна именно разметка,
например чтобы подобрать CSS-селектор. Для чтения содержимого используй extract_text.'''
return _get_html(url)[:max_chars]
@mcp.tool()
def extract_text(url: str, max_chars: int = 15000) -> str:
'''Возвращает чистый текст страницы без скриптов, стилей и разметки.
Лучший выбор, когда нужно прочитать статью, описание товара или отзывы.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
for tag in soup(['script', 'style', 'noscript', 'svg', 'header', 'footer', 'nav']):
tag.decompose()
title = _clean(soup.title.get_text()) if soup.title else ''
body = _clean(soup.get_text(' '))
return f'Заголовок: {title}. Текст: {body}'[:max_chars]
@mcp.tool()
def extract_links(url: str, limit: int = 100, contains: str = '') -> list[dict]:
'''Возвращает список ссылок со страницы: текст ссылки и полный адр��с.
Параметр contains фильтрует ссылки, в адресе которых есть указанная подстрока,
например /product/ или /catalog/.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
result = []
seen = set()
for a in soup.find_all('a', href=True):
full = urljoin(url, a['href'])
if full in seen or (contains and contains not in full):
continue
seen.add(full)
result.append({'text': _clean(a.get_text())[:120], 'url': full})
if len(result) >= limit:
break
return result
@mcp.tool()
def select_elements(url: str, css_selector: str, limit: int = 50) -> list[str]:
'''Находит на странице элементы по CSS-селектору и возвращает их текст.
Примеры селекторов: h2, .price, div.product-card, table tr.
Используй, когда нужны конкретные повторяющиеся блоки: цены, названия, строки таблицы.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
elements = soup.select(css_selector)[:limit]
return [_clean(el.get_text(' ')) for el in elements]
if __name__ == '__main__':
mcp.run()Qué hace cada herramienta
- extract_text elimina del documento los scripts, estilos, encabezado, pie y menú, y el texto restante lo une en una sola línea con espacios simples. La función _clean a través de split y join elimina saltos de línea y tabulaciones de más. Al inicio de la respuesta se agrega el título de la página para que el agente entienda de inmediato qué tiene delante.
- extract_links recopila todas las etiquetas a, convierte las direcciones relativas en absolutas con ayuda de urljoin, elimina duplicados a través del conjunto seen y permite filtrar enlaces por subcadena. Así el agente en una sola llamada obtiene, por ejemplo, todas las tarjetas de productos del catálogo.
- select_elements es la herramienta más potente. Acepta un selector CSS y devuelve el texto de los elementos encontrados. El agente puede primero mirar un trozo de HTML con fetch_page, entender que los precios están en la clase price, y luego llamar a select_elements con el selector .price.
Fíjate en los docstrings: le indicamos explícitamente al modelo qué herramienta elegir en qué situación. Esto mejora notablemente la calidad del trabajo del agente.
Cómo verificar
- Ejecuta mcp dev server.py y conéctate en Inspector. En la lista de Tools ahora hay cuatro herramientas.
- Llama a extract_links con la url de cualquier sitio de noticias o catálogo y el parámetro contains igual a una parte de la dirección de la sección. El resultado es una lista de objetos con los campos text y url.
- Llama a select_elements con la misma dirección y el selector h2. Obtendrás una lista de encabezados.
- Reinicia Claude Desktop (no hay que cambiar la configuración, solo cambió el código) y pídele: «Recopila de la página principal de tal sitio todos los encabezados h2 y los enlaces que llevan a la sección de noticias, y arma una tabla».
Consejo: Si no sabes qué selector necesitas, abre la página en el navegador, presiona F12, elige la herramienta de selección de elemento (el ícono con la flecha en la esquina superior izquierda del panel) y haz clic en el bloque que necesitas. En el código verás su clase. Un selector con punto y nombre de clase, por ejemplo .product-title, suele funcionar. Más aún, puedes simplemente pedirle al agente: «carga el HTML y tú mismo elige el selector para los precios».
✅ Verificación: Las cuatro herramientas se ven en Inspector y en el cliente, extract_text devuelve texto legible sin etiquetas, extract_links devuelve una lista con direcciones absolutas, select_elements por el selector h2 devuelve encabezados.
Posibles problemas
- select_elements devuelve una lista vacía. O el selector es incorrecto, o el contenido se carga con JavaScript después de cargar la página. Verifica con fetch_page: si en el HTML no están los datos necesarios, el sitio los renderiza en el cliente. Para esos sitios hace falta un motor de navegador, y eso ya es tema de otro artículo.
- extract_text muestra caracteres corruptos. El sitio entrega una codificación no estándar. Agrega después de response.raise_for_status() la línea response.encoding = response.charset_encoding or 'utf-8'.
- La respuesta se corta. Aumenta max_chars en la llamada o pídele al agente que solicite la página por partes a través de varios selectores.
Paso 5: Conectamos proxies móviles y rotación de IP
Objetivo de la etapa: dirigir todas las solicitudes del servidor MCP a través de un proxy móvil, agregar la herramienta de cambio de IP y de verificación de la dirección actual. Después de esto el agente trabajará como un operador móvil, y no desde tu IP doméstica u de oficina.
Para qué le sirve un proxy móvil a quien recopila datos
Cuando recopilas datos desde una sola dirección IP, los sitios ven decenas de solicitudes idénticas seguidas y empiezan a entregar captcha, contenido recortado o error 429 «demasiadas solicitudes». El proxy móvil resuelve varias tareas a la vez. Primero, la dirección pertenece a un operador móvil real, y esas direcciones las comparten miles de abonados, por eso los sitios las tratan con más benevolencia. Segundo, puedes cambiar la IP por enlace o por temporizador, distribuyendo la carga. Tercero, separas la actividad laboral del agente de tus sesiones personales. Para un marketero es además una forma de ver el sitio tal como lo ve un usuario móvil de una región concreta.
⚠️ Atención: El proxy es una herramienta para el trabajo estable y correcto del scraper, no para violar reglas. Recopila solo datos de acceso público, respeta los términos de uso de los sitios y el archivo robots.txt, no generes carga excesiva y no recopiles datos personales sin fundamentos legales. La responsabilidad por el uso de la herramienta recae sobre ti.
Instrucciones paso a paso
- Abre el panel de tu proveedor de proxies móviles y encuentra los datos de conexión: host, puerto, usuario, contraseña. Normalmente se reúnen en una sola línea del tipo login:password@host:port. Ahí mismo copia el enlace de cambio de IP, si existe.
- En el archivo server.py agrega al inicio, después de los demás imports, la línea import os. Luego, debajo del bloque HEADERS, agrega la configuración:
PROXY_URL = os.environ.get('MOBILE_PROXY_URL', '')
ROTATE_URL = os.environ.get('PROXY_ROTATE_URL', '')
def _client() -> httpx.Client:
kwargs = {'headers': HEADERS, 'timeout': 30.0, 'follow_redirects': True}
if PROXY_URL:
kwargs['proxy'] = PROXY_URL
return httpx.Client(**kwargs)- Reemplaza en la función _get_html la línea con httpx.Client por la llamada _client(). Ahora se ve así: with _client() as client. Todas las herramientas pasarán automáticamente por el proxy.
- Agrega dos nuevas herramientas antes de la línea if __name__:
@mcp.tool()
def current_ip() -> str:
'''Показывает IP-адрес, с которого сервер сейчас выходит в интернет.
Используй, чтобы убедиться, что прокси подключён, или после смены IP.'''
with _client() as client:
return client.get('https://api.ipify.org').text.strip()
@mcp.tool()
def rotate_ip() -> str:
'''Запрашивает смену IP-адреса мобильного прокси через ссылку из личного кабинета.
Вызывай, если сайт начал отдавать ошибки 429 или капчу. После вызова подожди 5-10 секунд.'''
if not ROTATE_URL:
return 'Ссылка смены IP не настроена в переменной PROXY_ROTATE_URL'
response = httpx.get(ROTATE_URL, timeout=15.0)
log(f'rotate_ip: status {response.status_code}')
return f'Запрос смены IP отправлен, ответ прокси-сервиса: {response.status_code}'- Pasa los datos del proxy a través de variables de entorno en la configuración del cliente. A propósito no escribimos el usuario y la contraseña en el código, para no enviarlos accidentalmente a algún lado junto con el archivo. Abre claude_desktop_config.json y completa el bloque del servidor con la sección env:
{
"mcpServers": {
"web-collector": {
"command": "C:/mcp-collector/.venv/Scripts/python.exe",
"args": ["C:/mcp-collector/server.py"],
"env": {
"MOBILE_PROXY_URL": "http://login:password@proxy-host:port",
"PROXY_ROTATE_URL": "https://ссылка-смены-ip-из-кабинета"
}
}
}
}- Sustituye los valores reales en lugar de login, password, proxy-host y port. Si el proveedor entrega proxy por el protocolo SOCKS5, reemplaza http:// por socks5:// e instala un paquete adicional con el comando pip install httpx[socks].
- Guarda la configuración, reinicia el cliente por completo.
- Pídele al agente: «Llama a current_ip y dime qué dirección tenemos. Luego llama a rotate_ip, espera diez segundos y verifica la IP de nuevo». Las direcciones deben ser diferentes.
Verificación a través de Inspector con proxy
Inspector también sabe pasar variables de entorno. En el panel izquierdo despliega la sección Environment Variables, agrega MOBILE_PROXY_URL y PROXY_ROTATE_URL con tus valores, conéctate y llama a current_ip. La respuesta debe coincidir con la IP que muestra el panel de tu proveedor.
Consejo: No llames a rotate_ip antes de cada solicitud. En la mayoría de los proveedores el cambio de IP toma varios segundos, y las solicitudes demasiado frecuentes pueden chocar con el límite de cambios. Una estrategia razonable: cambiar la dirección cada 30-100 solicitudes o solo al recibir errores 429 y 403. Puedes incorporar esta lógica directamente en _get_html, lo que haremos en el siguiente paso.
✅ Verificación: La herramienta current_ip devuelve la dirección del proxy, no la tuya doméstica. Tras rotate_ip y una pausa, la dirección cambia. Las herramientas extract_text y extract_links siguen funcionando, y en los logs se ven las líneas GET con las direcciones de las páginas.
Posibles problemas
- Error 407 Proxy Authentication Required. Usuario o contraseña incorrectos, o contienen caracteres especiales. Los símbolos como @ o : en la contraseña deben codificarse: @ reemplazar por %40, : por %3A.
- Error ConnectTimeout. Host o puerto incorrectos, o tu IP no está agregada a la lista de permitidos en el panel del proveedor, si el plan tiene esa restricción.
- current_ip muestra tu propia dirección. La variable de entorno no llegó al servidor. Verifica la escritura de MOBILE_PROXY_URL en la configuración y asegúrate de que el cliente se haya reiniciado.
- rotate_ip devuelve el estado 429 o un mensaje de límite. Cambias la IP con más frecuencia de la que permite el plan. Aumenta el intervalo.
Paso 6: Hacemos el servidor confiable: reintentos, demoras, caché y límites
Objetivo de la etapa: convertir el ejemplo de estudio en una herramienta que no se cae ante el primer error de red, no bombardea los sitios con solicitudes y no desborda el contexto del modelo. Es el último paso obligatorio antes del uso pleno.
Qué agregamos y para qué
- Reintentos automáticos. Los errores de red ocurren. En lugar de devolverle el error al agente de inmediato, intentaremos la solicitud dos veces más con una pausa.
- Cambio automático de IP ante bloqueo. Si el sitio respondió 429 o 403 y el enlace de rotación está configurado, el servidor mismo cambiará la dirección y repetirá la solicitud.
- Demora entre solicitudes. Un scraper educado no envía decenas de solicitudes por segundo. Una pausa de uno a dos segundos reduce la carga sobre el sitio y el riesgo de bloqueo.
- Caché. El agente a menudo solicita la misma página varias veces con herramientas distintas. Una caché en memoria de unos minutos evitará descargas repetidas.
- Límite de tamaño. No descargaremos páginas de más de unos pocos megabytes.
Código
Agrega al inicio del archivo import time, y reemplaza la función _get_html por esta:
CACHE: dict[str, tuple[float, str]] = {}
CACHE_TTL = 300
REQUEST_DELAY = 1.5
MAX_BYTES = 3_000_000
_last_request = 0.0
def _get_html(url: str) -> str:
global _last_request
now = time.time()
cached = CACHE.get(url)
if cached and now - cached[0] < CACHE_TTL:
log(f'cache hit: {url}')
return cached[1]
last_error = None
for attempt in range(3):
wait = REQUEST_DELAY - (time.time() - _last_request)
if wait > 0:
time.sleep(wait)
try:
with _client() as client:
_last_request = time.time()
response = client.get(url)
if response.status_code in (403, 429) and ROTATE_URL:
log(f'status {response.status_code}, rotating ip')
httpx.get(ROTATE_URL, timeout=15.0)
time.sleep(8)
continue
response.raise_for_status()
if len(response.content) > MAX_BYTES:
raise ValueError(f'Страница слишком большая: {len(response.content)} байт')
html = response.text
CACHE[url] = (time.time(), html)
return html
except httpx.HTTPError as error:
last_error = error
log(f'attempt {attempt + 1} failed: {error}')
time.sleep(2 * (attempt + 1))
raise RuntimeError(f'Не удалось загрузить {url} после 3 попыток: {last_error}')Cómo funciona
- El diccionario CACHE guarda para cada dirección el momento de descarga y el HTML. Si la página se solicitó hace menos de cinco minutos, devolvemos la copia guardada sin hacer la solicitud.
- Antes de cada solicitud calculamos cuánto pasó desde la anterior y, si hace falta, agregamos una pausa hasta completar REQUEST_DELAY segundos.
- Ciclo de tres intentos. Ante respuesta 403 o 429 con la rotación configurada, el servidor cambia la IP, espera ocho segundos y prueba de nuevo. Ante errores de red espera dos, cuatro, seis segundos entre intentos.
- Si la página pesa más de tres megabytes, lo consideramos un error: esos documentos de todos modos no cabrán en el contexto.
- Tras tres fallos lanzamos un error comprensible con la dirección y la causa. El agente lo recibirá como texto y podrá avisarte o intentar otro camino.
También recomendamos agregar una herramienta para limpiar la caché, para que el agente pueda forzar la recarga de una página:
@mcp.tool()
def clear_cache() -> str:
'''Очищает кэш загруженных страниц. Вызывай, если нужно получить свежую версию страницы.'''
count = len(CACHE)
CACHE.clear()
return f'Кэш очищен, удалено записей: {count}'Consejo: Vale la pena extraer los valores de REQUEST_DELAY y CACHE_TTL a variables de entorno por analogía con el proxy, para cambiarlos sin editar el código. Para monitorear precios servirá una demora de dos a tres segundos y una caché de un minuto; para recopilar artículos, una demora de un segundo y una caché de una hora.
✅ Verificación: Llama a extract_text para la misma página dos veces seguidas. La segunda vez aparecerá la línea cache hit en los logs, y la respuesta llegará al instante. Indica un dominio inexistente: en unos segundos el agente recibirá el mensaje «Не удалось загрузить... после 3 попыток», en lugar de quedarse colgado.
Posibles problemas
- NameError: ROTATE_URL no está definido. La función _get_html está declarada antes del bloque de configuración del proxy. Mueve la configuración PROXY_URL y ROTATE_URL más arriba en el archivo.
- El agente se queja de lentitud. Es normal: las demoras y la rotación de IP toman tiempo. Si tienes prisa, reduce REQUEST_DELAY a 0.5, pero recuerda el riesgo de bloqueos.
- La memoria crece. La caché guarda todas las páginas de la sesión. Para sesiones largas, agrega la limpieza de registros más antiguos que el TTL en cada llamada o limita el tamaño del diccionario.
Verificación del resultado: lista de control de un servidor MCP terminado
Recorre la lista de control y marca cada punto. Si todos se cumplen, tu servidor MCP para recopilar datos está listo para el trabajo real.
Qué debe funcionar
- El comando mcp dev server.py arranca sin errores, Inspector se conecta y muestra el estado Connected.
- En la lista de herramientas están fetch_page, extract_text, extract_links, select_elements, current_ip, rotate_ip y clear_cache.
- El servidor web-collector se muestra en el panel de herramientas del cliente de IA sin indicador de error.
- El agente, ante un pedido en lenguaje libre, elige por sí mismo la herramienta adecuada y la llama.
- current_ip muestra la dirección del proxy móvil, y tras rotate_ip la dirección cambia.
- Una segunda solicitud de la misma página se entrega desde la caché.
- Una dirección errónea produce un mensaje de error comprensible, en lugar de colgarse.
Prueba integral
- Elige un sitio público con catálogo o listado de artículos cuyos datos esté permitido usar.
- Pídele al agente: «Abre la página principal del sitio, encuentra los enlaces a la sección de catálogo, entra a las primeras cinco tarjetas, recopila el nombre y el precio y arma una tabla con las columnas Nombre, Precio, Enlace».
- Observa la cadena de llamadas: el agente debe llamar a extract_links con filtro, luego varias veces a select_elements o extract_text, y al final formar la tabla.
- Verifica manualmente algunas filas, abriendo las tarjetas en el navegador. Los datos deben coincidir.
Indicadores de éxito
Recopilar cinco tarjetas toma no más de 30-40 segundos, considerando las demoras. En los logs del cliente no hay errores de nivel traceback. El agente no vuelve a preguntar qué herramienta usar, sino que actúa por sí mismo. Si todo está así, felicitaciones: armaste tu propio servidor MCP y conectaste un agente de IA a la web.
Errores típicos al crear un servidor MCP y sus soluciones
Aquí están reunidos los problemas con los que se topa casi todo el mundo en la primera pasada. Formato: problema, causa, solución.
1. El servidor se conecta en Inspector, pero no funciona en el cliente
Causa: en la configuración del cliente se indicó el python del sistema sin las bibliotecas instaladas o una ruta incorrecta al archivo. Solución: escribe la ruta completa al python dentro de .venv y la ruta completa a server.py, usa barras inclinadas, reinicia el cliente por completo.
2. El cliente corta la conexión justo después del arranque
Causa: en el código quedó un print normal sin file=sys.stderr, y el flujo de servicio stdout se ensució. Solución: reemplaza todos los print por la función log. Verifica también que las bibliotecas no escriban en stdout: por ejemplo, algunas barras de progreso lo hacen por defecto.
3. El agente no llama a las herramientas y responde desde sus conocimientos
Causa: las descripciones de las herramientas son demasiado cortas o vagas, y el modelo no entiende cuándo aplicarlas. Solución: amplía los docstrings, agrega frases del tipo «usa cuando...» y ejemplos. En las primeras solicitudes nombra la herramienta explícitamente.
4. Error 403 al cargar sitios reales
Causa: el sitio no acepta solicitudes sin encabezados de navegador o desde una IP sospechosa. Solución: verifica que los HEADERS se envíen, actualiza el User-Agent a una versión actual del navegador, conecta el proxy móvil y asegúrate de que la rotación funcione.
5. Resultado vacío de select_elements con un selector correcto
Causa: los datos se cargan con JavaScript después de cargar la página, y en el HTML original no están. Solución: verifica con fetch_page. Si los datos no están, intenta encontrar la API interna del sitio en la pestaña Network del navegador: a menudo las tarjetas llegan en forma de JSON por una dirección aparte que se puede solicitar directamente con el mismo extract_text.
6. Error 407 o ConnectTimeout al trabajar a través del proxy
Causa: credenciales incorrectas, caracteres especiales sin codificar en la contraseña o puerto incorrecto. Solución: copia de nuevo la cadena de conexión del panel, codifica los caracteres especiales, verifica el protocolo http o socks5.
7. La configuración JSON no se aplica
Causa: una coma de más, una comilla faltante o barras invertidas en las rutas. Solución: verifica el archivo en un validador, reemplaza las barras invertidas por inclinadas, asegúrate de que después del último elemento no haya coma.
8. El servidor funciona, pero los datos llegan en codificación incorrecta
Causa: el sitio no indica la codificación en los encabezados. Solución: define response.encoding explícitamente o usa el atributo response.content con decodificación manual a través de decode('utf-8', errors='ignore').
Funciones adicionales: bloque para avanzados
El servidor básico está listo. Si escribes Python con seguridad y quieres más, aquí van direcciones de desarrollo, cada una realizable en una tarde.
Servidor remoto a través de Streamable HTTP
Para que el servidor funcione en una máquina aparte o que se conecten varios clientes a él, reemplaza la última línea por mcp.run(transport='streamable-http'). Por defecto el servidor se levantará en el puerto 8000, y la dirección de conexión será http://dirección-de-la-máquina:8000/mcp. En la configuración del cliente, en lugar de command y args indica la clave url con esa dirección. En este modo se puede escribir en stdout, pero es mejor mantener la costumbre de loguear en stderr. Cierra obligatoriamente el puerto del mundo exterior y agrega verificación de token en el encabezado, si el servidor es accesible no solo desde la red local.
Recursos y prompts
Un recurso con la configuración actual ayudará al agente a entender el contexto de trabajo:
@mcp.resource('collector://settings')
def settings() -> str:
'''Текущие настройки сборщика.'''
return f'proxy: {"on" if PROXY_URL else "off"}, delay: {REQUEST_DELAY}, cache ttl: {CACHE_TTL}'Un prompt define un escenario listo que el usuario invoca con un solo comando:
@mcp.prompt()
def price_monitor(url: str) -> str:
'''Сценарий мониторинга цен в каталоге.'''
return f'Открой {url}, собери ссылки на карточки товаров, зайди в каждую, вытащи название и цену и составь таблицу. Если увидишь ошибку 429, вызови rotate_ip и продолжи.'Guardar resultados en un archivo
Agrega la herramienta save_csv, que acepta una lista de diccionarios y una ruta de archivo y escribe los datos a través del módulo csv. El agente podrá no solo recopilar, sino también guardar los resultados en una tabla que abrirás en Excel. Limita la ruta de guardado a una sola carpeta, para que el agente no pueda escribir en cualquier lugar del disco.
Asincronía y recopilación en paralelo
FastMCP soporta funciones asíncronas: declara la herramienta con async def y usa httpx.AsyncClient. Entonces la herramienta fetch_many podrá cargar diez páginas a la vez a través de asyncio.gather. No olvides el semáforo que limita el número de solicitudes paralelas, y que la demora entre solicitudes en paralelo debe calcularse de otra manera.
Varios proxies y rotación inteligente
Si tienes varios proxies móviles para distintas regiones, guárdalos en una variable de entorno como lista separada por comas y agrega a la herramienta el parámetro region. El servidor elegirá el proxy por región, y el agente podrá comparar precios que el sitio muestra a usuarios de distintas ciudades. Es una de las tareas más demandadas entre marketeros y arbitrajistas.
Empaquetado en Docker
Para ejecutar en un servidor, arma una imagen basada en python:3.12-slim, copia server.py y el archivo de dependencias, instala los paquetes e indica el punto de entrada con transporte HTTP. Pasa las variables del proxy al lanzar el contenedor, y no las incorpores en la imagen.
⚠️ Atención: Nunca publiques código con usuarios, contraseñas y enlaces de rotación en repositorios abiertos. Mantenlos solo en variables de entorno o en un archivo .env agregado a .gitignore. Una filtración del enlace de cambio de IP permitirá a terceros controlar tu proxy.
FAQ: preguntas frecuentes sobre crear un servidor MCP
¿Se puede escribir un servidor MCP no en Python?
Sí. Hay SDK oficiales para TypeScript, Java, Kotlin, C# y otros lenguajes. Los principios son los mismos: declarar herramientas con descripciones y arrancar el transporte. Python fue elegido en la guía por su simplicidad y su rico conjunto de bibliotecas para trabajar con HTML.
¿Hace falta un plan pago del cliente de IA para trabajar con MCP?
Claude Desktop soporta servidores MCP locales incluso en el plan gratuito, pero con límites en la cantidad de mensajes. Cursor y VS Code también permiten conectar servidores. Verifica las condiciones actuales de cada cliente.
¿Es obligatorio usar proxy?
No, el servidor funciona también directamente. El proxy hace falta cuando el volumen de solicitudes es notable, los sitios son sensibles a la frecuencia de acceso o te importa ver el contenido desde una región concreta y desde una IP móvil.
¿Cómo saber que las solicitudes realmente pasan por el proxy?
Llama a la herramienta current_ip y compara la dirección con la que muestra el panel del proveedor. Adicionalmente puedes pedirle al agente que cargue la página de un servicio de detección de IP a través de extract_text.
¿Cuántas herramientas se pueden agregar a un servidor?
Técnicamente casi no hay límites, pero cada descripción ocupa lugar en el contexto del modelo. La práctica muestra que 5-15 herramientas bien descritas funcionan mejor que 50 pequeñas. Agrupa funciones cercanas mediante parámetros.
¿Cómo actualizar el servidor sin reiniciar el cliente?
Con el transporte stdio, el cliente lanza el proceso al arrancar, por eso los cambios en el código se recogerán solo tras reiniciar el cliente. En modo de desarrollo es más cómodo revisar los cambios a través de Inspector, y reiniciar el cliente al terminar.
¿Qué hacer si el sitio entrega datos solo después de ejecutar JavaScript?
Nuestro servidor trabaja con el HTML original y no verá esos datos. Opciones: encontrar la API interna del sitio en la pestaña Network del navegador o conectar un motor de navegador. El segundo camino está descrito en otros materiales del blog; aquí lo dejamos conscientemente de lado.
¿Cómo limitar al agente para que no vaya a sitios no deseados?
Agrega en _get_html una verificación del dominio por lista blanca o negra desde una variable de entorno y devuelve un error comprensible para las direcciones prohibidas. Esto es más confiable que confiar en las instrucciones del chat.
¿Se puede usar un mismo servidor MCP desde varios clientes a la vez?
Con stdio, cada cliente lanza su propia copia del proceso, y esto es normal: no se estorban entre sí, pero la caché es separada. Para una caché común y un proxy único, pásate al transporte HTTP del bloque avanzado.
Conclusión: qué hiciste y hacia dónde seguir
Hagamos un resumen. Preparaste el entorno de Python e instalaste el SDK oficial del protocolo. Escribiste un servidor MCP desde cero y entendiste cómo el modelo comprende las herramientas a través de sus descripciones. Conectaste el servidor al cliente de IA y viste cómo el agente carga páginas por sí mismo. Agregaste herramientas de extracción de texto, enlaces y elementos por selectores. Dirigiste el tráfico a través de un proxy móvil con rotación de IP. Finalmente, hiciste el servidor resistente: reintentos, demoras, caché y límites. Esto ya no es un ejemplo de estudio, sino una herramienta de trabajo para tareas diarias.
¿Qué hacer después? Empieza a usar el servidor en escenarios reales: monitoreo de precios de la competencia, recopilación de reseñas, verificación de landings, análisis de contenido en el nicho. Sobre la marcha entenderás qué herramientas te faltan justamente a ti, y las agregarás siguiendo el modelo de las existentes. Cada herramienta nueva es una función con una descripción clara, nada más complejo.
El siguiente nivel es el bloque avanzado: servidor remoto por HTTP, recopilación en paralelo, trabajo con varios proxies por regiones y guardado de resultados en tablas. Y cuando te topes con sitios de contenido dinámico, revisa los artículos relacionados del blog sobre automatización con navegador. Lo principal ya lo hiciste: tu agente de IA salió a la web a través de tu propio servidor MCP, y tú controlas por completo cómo lo hace.