Skip to main content
Glama

research-mcp

Una fachada MCP sin estado que oculta una pirámide de proveedores de búsqueda/lectura detrás de un único endpoint MCP streamable-http y expone solo 3 herramientas limpias con buenos textos de ayuda en ruso. Un LLM obtiene un conjunto de herramientas simple de "buscar → leer"; detrás, varios proveedores se prueban, fusionan y cambian automáticamente.

La aplicación no hace autenticación — se publica a través de Traefik + basicAuth en el host. No mantiene estado de aplicación: lo único que se persiste es un archivo de registro en data/ (guardado en un volumen).

Tools

Tool

Qué hace

web_search(query, num_results=8, page=1, language=None)

Busca en todos los proveedores habilitados, fusiona + deduplica → lista clasificada (título, URL, fragmento). Solo búsqueda.

read_page(url)

Una página o PDF → Markdown limpio. Detecta automáticamente el tipo, recorre el pipeline de lectura (ligero → pesado) hasta que uno tenga éxito.

read_pages(urls)

Hasta 20 urls concurrentemente → lista de {url, ok, markdown|error}.

Related MCP server: serp-it

Arquitectura: tipos + instancias

Los proveedores son plugins. Separamos:

  • tipo — una clase de implementación (por ejemplo, el proveedor de búsqueda searxng), una por módulo en src/providers/, registrada con @register("type").

  • instancia — una copia configurada de un tipo con sus secretos/URL resueltos desde variables de entorno con nombre (se permiten múltiples instancias de un tipo, p. ej. tavily-1 / tavily-2 con diferentes claves).

Qué instancias existen y el orden en que cada pipeline las prueba se configura en código (src/pipeline_config.py); las claves/URLs provienen de ENV por nombre de variable.

  • Pipeline de búsqueda (searxng → brave → jina-search → serper → exa): las instancias habilitadas se ejecutan concurrentemente; los resultados se fusionan y deduplican por URL normalizada (la posición anterior en el pipeline gana). Cuando JINA_API_KEY está configurada (y SEARCH_RERANK_ENABLED no está desactivado), la lista fusionada completa se reordena con jina-reranker-v3.5 para que el recorte a num_results conserve los resultados más relevantes en lugar de un prefijo ciego por orden de pipeline; cualquier fallo de reordenamiento vuelve al orden de fusión. searxng y brave además se limitan localmente (una consulta cada 45s y cada 1.1s respectivamente, coincidiendo con un límite ascendente medido); cuando el espacio está ocupado, omiten la búsqueda actual en lugar de esperarla.

  • Pipeline de lectura (trafilatura → jina → crawl4ai → tavily-1 → tavily-2 → firecrawl): un único GET de sondeo clasifica la URL. Los PDF (Content-Type / .pdf / magia %PDF) se extraen con pypdf; para HTML, ese mismo cuerpo se entrega a trafilatura para que la ruta caliente nunca haga GET dos veces, luego las instancias restantes se prueban en orden y la primera que devuelva contenido >= FALLBACK_MIN_CHARS gana.

Transversal: un reintento transitorio (errores 5xx / de transporte) con un backoff corto; 402 (sin créditos) / 429 (límite de velocidad) se tratan como fallo del proveedor → siguiente instancia (esto es lo que hace que tavily-1 → tavily-2 falle).

Una instancia está habilitada solo si sus variables de entorno requeridas están configuradas; de lo contrario, se omite con una línea de registro. trafilatura no necesita configuración (siempre activo); jina funciona sin clave (su clave es opcional). Al inicio, el servidor requiere al menos una instancia de búsqueda y una de lectura; de lo contrario, sale con un mensaje claro.

Añadir un proveedor

  1. Escribe src/providers/<type>.py con una clase decorada con @register("<type>") que implemente SearchProvider.search(...) o ReadProvider.read(...).

  2. Importa el módulo en src/providers/__init__.py (para que el decorador se ejecute).

  3. Añade una línea Instance("name", "<type>", api_key_env="YOUR_ENV_NAME") en src/pipeline_config.py y referencia su name en SEARCH_PIPELINE / READ_PIPELINE. Usa el NOMBRE de la variable ENV, nunca un valor.

  4. Documenta la variable de entorno en .env.example.

Inicio rápido

make install                # create .venv + install dev/test deps
cp .env.example .env        # fill in the keys you have  (shortcut: make env)
make test                   # run tests
make run                    # run the server (streamable-http on MCP_HOST:MCP_PORT, endpoint /mcp)

Configuración

Toda la configuración proviene de ENV / .env (ver .env.example). Los secretos/URLs de los proveedores se leen por nombre en el cargador de instancias, no se declaran como campos de Settings. Los ajustes no secretos (todos con valores predeterminados): MCP_HOST, MCP_PORT, LOG_LEVEL, LOG_FILE, LOG_ROTATION, LOG_RETENTION, REQUEST_TIMEOUT, FALLBACK_MIN_CHARS, READ_PAGES_CONCURRENCY, RETRIES, SEARCH_RERANK_ENABLED, JINA_TOKEN_BUDGET. El límite de urls por llamada de read_pages es un 20 fijo (constante dura, que coincide con la descripción de la herramienta) — no configurable.

Variables de entorno de proveedores: SEARXNG_URL, BRAVE_API_KEY, SERPER_API_KEY, EXA_API_KEY, JINA_API_KEY (una clave habilita el lector jina en modo con clave, el proveedor jina-search y el reordenador de búsqueda; el lector solo también funciona sin clave), CRAWL4AI_URL + CRAWL4AI_TOKEN, TAVILY_1_API_KEY, TAVILY_2_API_KEY, FIRECRAWL_API_KEY.

Proxy

Cualquier instancia externa puede enrutarse a través de su propio proxy SOCKS5/HTTP configurando <INSTANCE>_PROXY — útil para una salida limpia más allá de bloqueos por IP (por ejemplo, Cloudflare frente a Exa). Soportado por instancia: EXA_PROXY, BRAVE_PROXY, SERPER_PROXY, JINA_PROXY, TAVILY_1_PROXY, TAVILY_2_PROXY, FIRECRAWL_PROXY. Las instancias internas (searxng, crawl4ai, trafilatura) no tienen proxy.

El valor se pasa directamente a httpx; socks5://host:port hace DNS del lado del proxy (el nombre de host de destino lo resuelve el proxy, como curl --socks5-hostname), y también se aceptan socks5h:// / http://host:port. Sin configurar → esa instancia va directa. El pipeline mantiene un cliente httpx agrupado por cada URL de proxy distinta (y un cliente directo), seleccionado por instancia, de modo que los proveedores con proxy y directos se ejecutan lado a lado. Necesita el extra socks (httpx[socks], ya fijado).

Registro

Además de stderr (capturado por el controlador json-file con rotación limitada de Docker), el servidor escribe un archivo de registro persistente en data/research-mcp.log (por defecto; LOG_ROTATION=20 MB, LOG_RETENTION=14 days). Vive en el volumen data/, por lo que sobrevive a reinicios de contenedor y actualizaciones de imagen. El archivo lleva una línea por solicitud por llamada de herramienta — búsqueda (query, qué instancias de proveedor realmente se ejecutaron, recuento de resultados, latencia) y lectura (url, el proveedor/nivel ganador o pdf, ok, latencia), más un resumen read_pages count=N ok=K — lo que lo hace útil para analizar cómo se distribuyen las solicitudes entre los niveles de proveedores. No se registran cuerpos de solicitud ni secretos, solo urls/consultas, nombres de proveedores, recuentos, tiempos.

Despliegue

Gitea Actions construye la imagen y la envía al registro de Gitea gitea.vvzvlad.xyz/projects/research-mcp (testbuild, etiquetas latest + sha). En producción extraemos la imagen preconstruida mediante docker-compose.yml (detrás de Traefik + basicAuth, watchtower actualiza automáticamente latest; el volumen data/ mantiene el archivo de registro entre actualizaciones) — nunca construimos en producción.

Estructura

Ruta

Propósito

src/providers/base.py

Interfaces de proveedor + SearchResult / ProviderError.

src/providers/registry.py

Decorador @registerREGISTRY.

src/providers/<type>.py

Un módulo por tipo de proveedor.

src/providers/pdf.py

Detección de PDF + extracción de texto con pypdf (usado por el pipeline).

src/pipeline_config.py

Instancias en código + orden del pipeline.

src/pipeline.py

Cargador de instancias + lógica de búsqueda/lectura.

src/rerank.py

JinaReranker — reordenamiento posterior a la fusión de resultados de búsqueda.

src/settings.py

Ajustes no secretos (pydantic-settings).

src/server.py

build_server() con las 3 definiciones de @mcp.tool.

main.py

Punto de entrada delgado: construir servidor, ejecutar streamable-http.

tests/

Suite de pytest (red simulada con respx).

F
license - not found
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    MCP server for web crawling, searching, and AI-powered content extraction, supporting single-page, batch, and full-site crawling along with text, news, image, book, and video search.
    8
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    An MCP server that aggregates web search results from multiple engines and optionally renders pages to Markdown, providing a unified search interface.
    10
    3
    ISC
  • A
    license
    A
    quality
    B
    maintenance
    An MCP server that fetches web pages and extracts clean, AI-usable context from them, enabling tools for link discovery, content search, and integrated fetch-and-search operations.
    5
    7
    1
    MIT

View all related MCP servers

Related MCP Connectors

  • Free remote MCP server for fetching public web pages through a rotating proxy pool.

  • Hosted MCP: 1404 structured web-data tools for search, maps, commerce, social, gaming & finance.

  • Federated commerce search across independent WooCommerce merchants. Keyless, read-only MCP server.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vvzvlad/research-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server