keyless-web-search-mcp
keyless-web-search-mcp
Servidor MCP stdio independiente: dos herramientas sin clave — web_search sobre un grupo de motores autooperados (Bing, 360, Baidu, Google, Naver, Yandex, DuckDuckGo) y web_fetch (lector de páginas HTTP(S) anónimo). Cada búsqueda mantiene como máximo dos motores utilizables, enruta las prioridades por defecto según el idioma de la consulta, rellena motores fallidos o irrelevantes dentro de un presupuesto de intentos limitado, ordena los resultados por relevancia, los fusiona y elimina duplicados por URL canónica. Directorio autocontenido, sin paso de compilación, no forma parte del sistema de paquetes del harness — se puede mover a cualquier lugar.
Por qué existe esto
El web_search integrado del harness (proveedor DeepSeek) necesita DEEPSEEK_API_KEY y envía cada consulta a la nube de DeepSeek. Este servidor es la alternativa amigable para modelos locales: sin claves, sin API de búsqueda de proveedor, funciona en redes de China continental y HK (Bing/360/Baidu desde líneas continentales, Bing/360/Naver/Yandex desde la línea HK probada; DuckDuckGo no es accesible desde ninguna de ellas).
web_fetch existe por la misma razón en el lado de lectura: el perfil web monta un proveedor de búsqueda pero ningún proveedor de fetch, por lo que la herramienta integrada web_fetch (incluso cuando un ajuste preestablecido la habilita) falla en cada llamada con WEB_PROVIDER_UNAVAILABLE. Esta herramienta lee el contenido completo de la página a través del mismo servidor sin claves.
Related MCP server: web-search-mcp
Ejecutar
npm install --cache ./.npm-cache # deps: @modelcontextprotocol/sdk, zod
node index.js # speaks MCP over stdio
npm test # run deterministic ranking/fallback testsPrueba rápida sin cliente:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0.0.1"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| node index.jsInstalar en Claude Code
Instálalo para el usuario actual para que todos los proyectos de Claude Code puedan usarlo. Resuelve ambas rutas al registrar el servidor; esto evita depender del directorio de trabajo del shell o del PATH más adelante:
claude mcp add --transport stdio --scope user web-search-self -- "$(command -v node)" "/absolute/path/to/keyless-web-search-mcp/index.js"
claude mcp get web-search-selfUsa --scope local en su lugar para mantenerlo privado al proyecto actual, o --scope project para escribir un .mcp.json compartible. Claude Code guarda los registros de usuario/local en ~/.claude.json; las definiciones de servidor MCP no pertenecen a settings.json.
Después del registro, claude mcp list debería informar que web-search-self está conectado. Las herramientas aparecen como mcp__web-search-self__web_search y mcp__web-search-self__web_fetch.
Herramientas
web_search
web_search({ query, count?, maxSources?, engines? })
Parámetro | Por defecto | Significado |
| — | Consulta de búsqueda, en cualquier idioma |
|
| Máximo de resultados combinados (1–20) |
|
| Máximo de motores utilizables por búsqueda (límite máximo 2; los intentos de respaldo están limitados) |
| depende del idioma de la consulta | Lista opcional explícita del pool en orden de prioridad; cuando se omite, las consultas en chino/coreano/japonés/ruso usan prioridades apropiadas para la región |
Política de dos fuentes. El pool se enruta según el idioma de la consulta cuando se omite engines: el chino comienza con 360/Baidu/Bing; el inglés comienza con Bing/Google/Naver/360, de modo que el presupuesto de cuatro intentos conserve respaldos funcionales en las líneas probadas (continental y HK). Una lista explícita de engines sigue siendo autoritativa. Los motores se ejecutan en rondas paralelas limitadas; un motor consume un espacio de fuente solo después de que produce resultados parseables que pasan un filtro léxico conservador de relevancia. Los motores fallidos, vacíos o irrelevantes se rellenan hasta el presupuesto de intentos, y se muestran diagnósticos en una línea "Nota del motor". Los resultados se clasifican por superposición con la consulta con un pequeño ajuste de calidad de fuente: las señales de granjas de contenido o re-publicación obvias se penalizan, mientras que las señales de GitHub/educación/docs se favorecen sin bloquear duro las páginas normales. La fusión sigue siendo entrelazada round-robin (1.º del motor A, 1.º del motor B, 2.º del A, ...), y la deduplicación por URL canónica elimina fragmentos, parámetros de seguimiento comunes y diferencias seguras de www..
Resultados numerados como lista de título [motor] — URL — fragmento. Limpieza de enlaces por motor: los enlaces de seguimiento de Bing se decodifican (parámetro u en base64); 360 lee el atributo data-mdurl; Baidu lee el data-url del bloque (URL directa, con un único GET de mejor esfuerzo solo para envoltorios heredados link?url=); Naver y Yandex llevan la URL directa en el ancla; los enlaces /url?q= de Google se desempaquetan; los rastreadores /l/?uddg= de DuckDuckGo se desempaquetan. Presupuestos de sondeo por motor: 10 s (Bing, Baidu), 8 s (360, Naver, Yandex), 5 s (Google, DuckDuckGo) — todos se ejecutan en paralelo, por lo que la ronda es tan lenta como su miembro más lento.
web_fetch
web_fetch({ url, maxChars? })
Parámetro | Por defecto | Significado |
| — | URL absoluta |
|
| Máximo de caracteres devueltos (1000–100000) |
Lectura anónima de la web pública: User-Agent de navegador, como máximo cinco redirecciones, 20 s de tiempo de pared que cubren cabecera y cuerpo, el cuerpo de la respuesta se corta exactamente en 5 MB. Cada objetivo inicial y de redirección se comprueba después de la resolución DNS; se rechazan loopback, direcciones privadas, link-local, NAT de operador, reservadas, multicast y nombres de host locales para prevenir SSRF hacia la máquina o metadatos en la nube. El texto visible se extrae (se eliminan script/style/noscript/svg, los límites de bloque se convierten en saltos de línea, se descartan los formularios); se conservan los tipos textuales, JSON y XML decodificados con su charset declarado, mientras que los tipos binarios se descartan. La cabecera devuelve status, url final, content-type y truncamiento, seguidos del contenido. Los errores de red se informan con un código de estado legible y una breve nota, nunca una página fabricada.
Motores y líneas
Probes:
Bing: accesible desde líneas continentales y HK; a veces devuelve
406a agentes no estándar — los resultados aún se procesan con una antología sintética de enlaces.360: accesible desde líneas continentales y HK (el enrutamiento cambia según el nodo); la página de resultados es HTML mixto con
wappalyzeral final; su selector de resultados es más frágil.Baidu: requiere proxies de red desde las líneas probadas; el HTML de resultados declara
gb2312. Sin JavaScript, la primera página suele carecer del bloque de resultados y necesita consultas con número de página.Naver: afficione a las líneas HK; a veces devuelve una página de consentimiento de cookies. Cuando lo hace, el selector de resultados encuentra solo la cabecera de la página — el motor se descarta como "no utilizable".
Google: requiere proxy (y a menudo consentimiento); la salida está envuelta en
/url?q=y&sa=; los resultados suelen aparecer según la región.Yandex: accesible desde líneas HK; bloquea por captcha, a menudo con
captchaen la URL de redirección. Cuando el captcha se activa (respuesta 403), la salida sin JavaScript aún contiene enlaces reales (fragmento bajo el título, lista de resultados), por lo que el proxy de búsqueda rara vez falla por completo.DuckDuckGo: html.duckduckgo.com — en las redes probadas no es alcanzable desde líneas continentales o HK; la página de resultados carece de
data-testiden resultados repetidos.
Notas de implementación
Sin dependencias de red: solo
node:httpy módulos integrados; sinfetchde Node, sin paquetes npm.Sin JavaScript: todos los motores se consultan con HTML estático. Los motores que sirven resultados dinámicamente (por ejemplo, mediante EJS o JS) se consideran no utilizables.
Recuperación: cada motor tiene un temporizador de 5–10 s; los tiempos de espera se consideran fallos. El presupuesto de intentos (por defecto 4) se agota solo cuando un motor no produce resultados utilizables.
Sin caché persistente: cada búsqueda construye los resultados desde cero; ninguna configuración, cero archivos de estado.
Solo node: dependencia única
@modelcontextprotocol/sdk(tiempo de ejecución Node ≥ 18).
Comportamiento
Enrutado inteligente de motores: el pool se elige por idioma de la consulta; los motores que fallan, devuelven vacío o son irrelevantes se reemplazan con presupuesto disponible.
Sin clave de API: por diseño.
Límites estrictos: cada motor como máximo 5 resultados;
countmáximo 10; por defecto 5.Sin seguimiento de estado: invocaciones sin estado, seguras para llamadas concurrentes.
Motor | Endpoint | Estado desde estas redes |
|
| ✅ ~10 bloques orgánicos en ambas líneas. Según la línea, |
|
| ✅ 200 limpio; los bloques orgánicos llevan la URL real en |
|
| Alcanzable (200) pero este cliente/IP no es de confianza para SERPs en HTML plano: el cuerpo es un muro |
|
| ✅ en las líneas de Shanghái y Hong Kong: el control de riesgos filtra las solicitudes con forma de script (redirecciones 302 solo con UA a la captcha de imagen |
|
| ✅ en la línea de Hong Kong (200, ~10 bloques orgánicos |
|
| ✅ en la línea de Hong Kong: misma lección de firma de navegación que Baidu — las solicitudes con forma de script reciben la casilla SmartCaptcha "no robot", pero con la firma completa de cabeceras de navegación de documento más la sesión de cookie de la página principal (yandexuid et al.) se sirve el SERP en HTML plano (~50 bloques |
|
| ❌ TCP inalcanzable en todas las líneas probadas (incluida Hong Kong); motor de último recurso para redes donde funciona |
Deliberadamente fuera del grupo: Sogou — redirige con 302 a sogou.com/antispider/, la misma clase de muro por IP que cubre Baidu. También analizado y rechazado desde la línea de Hong Kong: Mojeek (sirve una página de captcha), Ecosia (403 "Ecosia Firewall"), MetaGer (redirige a una página sin resultados), y Yahoo/Brave/Qwant/Startpage/goo.ne.jp (TCP inalcanzables desde las líneas de la China continental y de Hong Kong).
El muro de Google: qué se probó
La respuesta 200 desde esta IP no es un bloqueo sino un desafío de JavaScript interstitial (~90 KB de JavaScript ofuscado/cifrado; la ruta sin JavaScript es un meta-refresco a un callejón sin salida). El muro resulta tener dos capas:
Desafío JS (computacional) — al decodificarlo, calcula un valor de prueba y establece una cookie
SG_SS(caducidad de 5 minutos), luego recarga. Esta capa es resoluble fuera del navegador: ejecutar los scripts de la página en Node.js plano con un simulador ligero de DOM (cookie jar,navigator,Image,document) completó el cálculo, y la cookieSG_SSresultante fue aceptada una vez — Google respondió 200 y emitió las cookies de confianzaNID/AECque de otro modo nunca envía a esta IP.Capa de sesión (conductual) — las solicitudes HTTP planas posteriores, incluida una réplica exacta del flujo de recarga del propio script (
emsg=SG_REL+seicoincidente, cookies fusionadas del jar, cabeceras de navegador), escalan al muro de anomalías 429 degoogle.com/sorry. Esta capa juzga toda la sesión (huella TLS/HTTP2, ritmo de solicitudes, mezcla de métodos), que la pila de OpenSSL/undici de Node no iguala.
Palancas del lado del cliente que se probaron y no cambiaron la respuesta de la capa 1: el parámetro gbv=1, calentamiento de cookies, cabeceras completas de huella de navegador, el flujo retry/enablejs, la entrada /m, UAs de navegador de texto/teléfono básico/IE6/Android antiguo, un UA falsificado de Googlebot (Google lo valida), cookies CONSENT, envío por POST (405), TLD alternativos, y el enlace "haz clic aquí" emsg=SG_REL sin la cookie. Alternativas de proxy de Google también eran inalcanzables o amuralladas desde esta red: Startpage y Qwant agotan el tiempo de espera, Mojeek sirve una página de captcha, Ecosia da 403.
Conclusión: la capa 1 es resoluble en Node (demostrado); la capa 2 no lo es, desde una pila de red que no es de navegador. Los únicos caminos fiables a Google desde esta máquina son un proxy con IP limpia o un contexto de navegador real (Chromium sin interfaz); ambos están en la misma capa de IP/patrón de tráfico que un raspador no puede superar honestamente, y las pruebas repetidas arriesgan ampliar la ventana de anomalía de la IP — así que este servidor no lo intenta. Google permanece como motor de respaldo que se activa en redes donde sirve un SERP en HTML plano.
Montaje en el arnés de DeepSeek
Añade a tu cordis.yml (el puente MCP recarga en caliente esta entrada):
- id: mcp-search
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: search
transport: stdio
command: node
args: ['/absolute/path/to/keyless-web-search-mcp/index.js']El modelo entonces ve las herramientas como mcp__search__web_search y mcp__search__web_fetch.
Limitaciones
La calidad de búsqueda es heurística: la relevancia léxica maneja resultados claramente fuera de tema y n-gramas chinos; las páginas internas de los motores de búsqueda se excluyen; las señales de granja de contenido/republicación solo ajustan el orden, no son un juicio universal de confianza. Un resultado relevante no es prueba de que sus afirmaciones sean correctas — busca y verifica los datos importantes.
Es raspado, no una API: los cambios de diseño pueden romper un parser; el fallo es ruidoso ("sin resultados orgánicos parseables"), nunca fabricado. Los parsers de Google y DuckDuckGo están escritos a partir de la estructura documentada del SERP y no son verificables en vivo desde esta red — ajústalos la primera vez que sus motores respondan realmente.
Control de ritmo: ambos motores públicos toleran el uso ocasional; las ráfagas atraen desafíos de bots.
La consulta sale de la máquina hacia los motores consultados (ese es el precio de la búsqueda sin clave); con el límite de dos fuentes, como máximo dos de ellos ven una consulta por búsqueda.
Es un lector de páginas públicas sin clave, no un navegador ni un cliente de intranet: el contenido renderizado con JavaScript es invisible para él (misma clase de límite que los parsers de búsqueda); las páginas que dan 403/429 a clientes anónimos se informan, no se evaden. Los destinos de red locales/privados/reservados se bloquean deliberadamente, incluidos los destinos de redirección.
Available Tools
2 toolsweb_fetchWeb Fetch (keyless anonymous HTTP(S) reader)A
Fetch one HTTP(S) URL anonymously and return the page as readable text: HTML is stripped to visible text with block structure preserved; text/markdown/JSON/XML pass through decoded. No credentials: browser User-Agent, up to five validated redirects, bounded output. Local, private, link-local, and reserved network targets are blocked, including after DNS resolution and redirects. The result is a status header (status code, final URL, content-type, truncation) followed by the content. Use it to read full page content for a URL, e.g. one found by web_search.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Absolute http(s) URL to fetch. | |
| maxChars | No | Maximum content characters to return (default 20000, hard cap 100000). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full responsibility. It discloses anonymous access, no credentials, browser User-Agent, redirect limits, target blocking, and truncation behavior, which is strong transparency for a network tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three purposeful sentences: main behavior, safety boundaries, and output/usage context. No filler, no redundant schema echoing, and key constraints are front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema or annotations, the description still explains output format, status header components, redirects, target restrictions, and content conversion. This is an unusually complete one-paragraph contract for a fetch tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already clearly documents both parameters at 100% coverage, with maxChars including a default and limits. The description affirms bounded output but does not add substantial meaning about parameter formats beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb, resource, and output: fetches one HTTP(S) URL and returns readable text. It also references web_search, making the distinction between search and fetch explicit without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Description explicitly says to use it to read page content for a URL and gives a web_search output as an example, naming the sibling tool. It does not explicitly state when not to use it, so it stops short of a full when/when-not map.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
web_searchWeb Search (self pool: Bing / 360 / Baidu / Google / Naver / Yandex / DuckDuckGo)A
Search the web without any API key from a self-operated pool: Bing, 360, Baidu, Google, Naver, Yandex, and DuckDuckGo. Each search keeps at most two usable engines — the pool is routed by query language when no explicit pool is given, failed or irrelevant engines are back-filled within a bounded attempt budget, and results are relevance-ranked, quality-adjusted, and deduplicated by canonical URL. Each result includes a title, the real destination URL, a snippet, and its engine. Engines unreachable from the local network, or walled by captcha/JS/bot checks, are skipped and reported in an engine note; the remaining engines still answer.
| Name | Required | Description | Default |
|---|---|---|---|
| count | No | Maximum merged results to return (default 8). | |
| query | Yes | Search query in any language. | |
| engines | No | Optional explicit engine pool in priority order; omitted uses query-language routing. | |
| maxSources | No | Maximum usable engines per search (default 2, hard cap 2; fallback attempts are bounded). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description thoroughly discloses behavioral details: no API key needed, engine pool self-operated, at most two usable engines, back-fill on failures, relevance/quality ranking, deduplication, skipping unreachable or walled engines, and reporting an engine note. This exceeds the baseline and compensates for the absence of annotations. No contradiction with annotations since none are provided.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and front-loaded with the primary purpose (search the web without API key) and then provides relevant behavioral details in a structured manner. Each sentence adds value; it is not overly verbose. Slight redundancy with the engines list in the title but overall well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers key aspects: purpose, engine selection, failure handling, result format, and edge cases (captcha/JS/bot walls). No output schema exists, but the description mentions what each result includes (title, URL, snippet, engine), which partially compensates. The absence of annotations is mitigated by the detailed description. Minor gaps remain about the return structure of the full response, but the information is sufficient for an agent to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already has complete (100% coverage) descriptions for all four parameters: count, query, engines, and maxSources. The description adds contextual insight on routing by query language and back-fill behavior but does not add substantial new parameter semantics beyond what the schema provides. Per the guideline, high schema coverage means baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool performs a web search using a self-operated engine pool, listing the supported engines and the result characteristics (title, URL, snippet, engine). It does not explicitly contrast with the sibling tool web_fetch, but the purpose is distinct and clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains how the engine pool is selected (query-language routing when no explicit pool), how failures are handled (back-filling, bounded attempts), and how results are ranked and deduplicated. It does not explicitly state 'when to use' versus 'when not to use' but provides contextual routing guidance. The sibling tool web_fetch is not referenced, so no alternative routing is mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v1.1.0- First observed
web_fetch - First observed
web_search
TDQS
Scored across 2 tools
The two tools are completely distinct: web_search performs web searches across multiple engines, while web_fetch retrieves the content of a specific URL. There is no overlap or ambiguity between them.
Both tool names follow the same verb_noun pattern: web_search and web_fetch. The naming is clear, consistent, and predictable.
The server has only two tools, which is slightly below the typical well-scoped range of 3-15. However, each tool is essential and covers the core functionality of keyless web search and fetching, so the count is reasonable for the narrow scope.
The tool surface fully covers the stated purpose of keyless web search: web_search finds relevant results and web_fetch retrieves full page content. There are no obvious missing operations for this domain.
Maintenance
Related MCP Connectors
Google, Bing, DuckDuckGo and Google Maps search results, free without an API key.
LLM-ready web search + instant answers + URL-to-clean-text fetch for agents and RAG.
Keyless web, GitHub, YouTube and Reddit search and read. Delegated shop, booking and signup.
Web search for AI agents — one tool across 6 engines, routed to the cheapest + cached.
Related MCP Servers
- AlicenseAqualityBmaintenanceEnables web search without API keys using DuckDuckGo and Bing search engines, and retrieves webpage content. Supports multiple search engines simultaneously with privacy protection and asynchronous processing.263 PyPI10MIT
- FlicenseNot gradedqualityDmaintenanceProvides free web search, content fetching, image search, and deep research via SearXNG, no API keys required.-
- AlicenseAqualityCmaintenanceEnables keyless multi-engine web, news, image, and video metasearch plus full-page markdown extraction for AI agents over MCP, with resilient fallback across DuckDuckGo, Bing, Brave, Google, and other backends.6MIT
- AlicenseNot gradedqualityCmaintenanceEnables MCP clients to perform free web search and read web pages as markdown without paid APIs, Docker, or a background service, by querying multiple free search engines in parallel with optional fallbacks and extracting clean page content. Also supports fetching a site's llms.txt documentation files.MIT