web-search-mcp
Enables web searching and page reading through SearXNG, returning summarized results with cited sources.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@web-search-mcpResearch the current state of electric vehicle adoption and summarize with sources."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
web-search-mcp
Servidor MCP autônomo que pesquisa na web,
abre as páginas, lê o conteúdo e devolve um resumo com as fontes para o
agente que chamou. Duas tools — read_url e research_web — para qualquer
agente (Claude Code, LangChain, LangGraph, etc). Sem framework de agente
embutido: só FastMCP.
A ideia: pesquisar num contexto isolado
A pesquisa inteira acontece fora da janela de contexto do agente principal. Ele manda uma pergunta em linguagem natural e recebe de volta um resumo curto — nunca vê o material bruto.
┌─────────────────────────────────────────────┐
agente principal │ web-search-mcp (contexto próprio) │
──────────────── │ │
│ 1. gera variantes de busca (LLM) │
"quem foi X?" ──► │ 2. busca em paralelo no SearXNG │
│ 3. abre as N melhores páginas │
│ 4. monta o dossiê ....... 15-50k chars │
│ 5. resume com as fontes (LLM) │
resumo ◄── │ ....... ~700 tokens│
~700 tokens └─────────────────────────────────────────────┘Sem isso, uma pesquisa séria significa despejar dezenas de milhares de tokens de HTML e texto extraído na conversa principal — material que fica lá ocupando espaço em todas as chamadas seguintes, mesmo depois de já ter sido usado. Aqui esse custo é pago num processo separado, com o LLM que você escolher, e o que atravessa é só a resposta.
Na prática:
O contexto do agente não incha. Ele gasta ~700 tokens por pesquisa em vez dos 6k-20k tokens do material lido. Conversas longas com muitas pesquisas continuam viáveis.
Dá para usar um modelo barato na parte cara. Quem lê 5 páginas e resume pode ser um modelo local pequeno; o agente principal, o caro, só recebe o resultado pronto.
A resposta vem citada. O resumo traz as URLs realmente consultadas e um carimbo de data/hora, então dá para conferir a fonte em vez de confiar.
Uma chamada resolve. O
research_webjá busca vários ângulos por dentro e lê em paralelo — o agente não precisa orquestrar rodadas de busca.
Quando você quer o texto cru mesmo — "leia este link para mim" — é o read_url
que serve, e aí o conteúdo vai inteiro para o agente, sem resumo.
Related MCP server: myscrape
Requisitos
Python ≥ 3.13
Um servidor de busca SearXNG rodando (formato JSON habilitado) — há um
docker composepronto emsearxng/Um servidor de LLM com API compatível com OpenAI (
/v1/chat/completionse/v1/models) — ex. llama.cpp server, vLLM, ou a própria OpenAI
SearXNG via docker compose
O diretório searxng/ traz a stack que eu uso, já na porta que é o default do
SEARXNG_URL:
cd searxng
docker compose up -dSobe SearXNG em http://localhost:8886 mais um Valkey de cache. Na primeira
subida o SearXNG gera searxng/data/settings.yml (ignorado pelo git) com
formats: [html] — o research_web não funciona assim, porque o cliente
pede format=json (util/searxng.py:32) e o SearXNG responde 403. Habilite o
JSON e reinicie:
# searxng/data/settings.yml
search:
formats:
- html
- jsondocker compose restart searxngOs serviços mcp-searxng e caddy do compose são um servidor MCP de busca
de terceiros, independente deste projeto — este aqui fala com o SearXNG
direto, por HTTP. Se você não os usa, pode removê-los do compose sem afetar em
nada o web-search-mcp.
Antes de subir isso em qualquer lugar que não seja sua máquina, troque as duas
senhas do compose. Elas vêm com o placeholder password123, que está
versionado neste repositório e portanto é público:
SEARXNG_SECRET(emsearxng/docker-compose.yaml) — chave com que o SearXNG assina; deve ser um valor aleatório e longo, ex.openssl rand -hex 32o
Bearer password123dosearxng/caddy/Caddyfile— é a única autenticação na frente domcp-searxng, cuja porta8887é publicada no host. Quem souber o token usa o serviço
Instalação
A partir do GitHub (não precisa clonar)
uvx --from git+https://github.com/fabio-barboza/web_search_mcp@v0.1.0 web-search-mcpRegistro no Claude Code:
claude mcp add web-search \
-e SEARXNG_URL=http://localhost:8886 \
-e MODEL_BASE_URL=http://localhost:8200/v1 \
-- uvx --from git+https://github.com/fabio-barboza/web_search_mcp@v0.1.0 web-search-mcpInstalado assim, o .env não é lido: a configuração inteira entra por -e —
ver Configurando o servidor instalado.
Trocar @v0.1.0 por @main pega o topo do branch.
Para deixar o comando fixo no PATH em vez de resolver a cada execução:
uv tool install git+https://github.com/fabio-barboza/web_search_mcp@v0.1.0A partir do clone (desenvolvimento)
uv sync
cp .env.example .envEdite o .env com as URLs do seu SearXNG e do seu servidor de modelo. O
servidor sobe com os defaults do .env.example se você não copiar nada, mas
sem SEARXNG_URL/MODEL_BASE_URL corretos as tools não vão funcionar.
Uso
Dois transportes, mesmas tools. A diferença é quem sobe o processo — e isso muda de onde vem a configuração.
stdio | http | |
Quem sobe o processo | o cliente, a cada sessão | você, uma vez |
Quantos clientes | um por processo | vários no mesmo processo |
Porta de rede | nenhuma |
|
Configuração vem de | bloco | ambiente de quem subiu e/ou |
stdio (padrão — para Claude Code e clientes locais)
uv run web-search-mcpNa prática você não roda isso à mão: quem executa é o cliente. Registro no Claude Code apontando para o clone:
claude mcp add web-search -- uv --directory /caminho/para/web_search_mcp run web-search-mcpPara registrar a versão instalada do GitHub, com a configuração no bloco
env, ver Configurando o servidor instalado.
HTTP (compartilhar entre vários agentes)
Suba o servidor. Do clone, que lê o .env da raiz:
uv run web-search-mcp --httpOu instalado, passando a configuração pelo ambiente:
SEARXNG_URL=http://localhost:8886 \
MODEL_BASE_URL=http://localhost:8200/v1 \
uvx --from git+https://github.com/fabio-barboza/web_search_mcp@v0.1.0 web-search-mcp --httpSobe em http://{MCP_HOST}:{MCP_PORT}/mcp (padrão 127.0.0.1:8765).
Com ele no ar, registre o cliente pela URL:
claude mcp add --transport http web-search http://127.0.0.1:8765/mcpQue no .mcp.json fica:
{
"mcpServers": {
"web-search": {
"type": "http",
"url": "http://127.0.0.1:8765/mcp"
}
}
}No modo http o bloco env do cliente não tem efeito. No stdio o cliente
spawna o processo, então o -e dele vira o ambiente do servidor; no http o
processo é seu e já está rodando quando o cliente conecta, com o ambiente que
você deu na hora de subir. Toda a configuração migra para o lado do
servidor, e trocar uma variável exige reiniciá-lo — editar o .mcp.json não
adianta.
Deixando rodando (systemd de usuário, sem sudo)
# ~/.config/systemd/user/web-search-mcp.service
[Unit]
Description=web-search-mcp (http)
After=network.target
[Service]
Environment=SEARXNG_URL=http://localhost:8886
Environment=MODEL_BASE_URL=http://localhost:8200/v1
ExecStart=%h/.local/bin/uvx --from git+https://github.com/fabio-barboza/web_search_mcp@v0.1.0 web-search-mcp --http
Restart=on-failure
[Install]
WantedBy=default.targetsystemctl --user daemon-reload
systemctl --user enable --now web-search-mcpAntes de expor esse endpoint além da sua máquina, note que o servidor não tem
autenticação nenhuma. Com o default MCP_HOST=127.0.0.1 só processos locais
alcançam, o que é seguro. Trocar para 0.0.0.0 para outra máquina consumir
deixa as duas tools abertas a qualquer um na rede, sem credencial e servindo de
proxy de scraping em cima do seu LLM. Nesse caso ponha um reverse proxy com
token na frente e restrinja MCP_CORS_ALLOW_ORIGINS às origens que você usa,
em vez de deixar *.
Tools
read_url(url: str) -> str
Abre uma URL específica e devolve o conteúdo principal da página em Markdown, sem busca nem resumo — o texto bruto volta pro agente processar. Bloqueia URLs que apontam para IP privado/loopback/link-local (proteção anti-SSRF).
research_web(query: str, recent: bool = False) -> str
Pesquisa a pergunta na web (gera variantes de busca, roda em paralelo, lê as páginas mais relevantes) e devolve um resumo em português citando as fontes, com carimbo de data/hora e a lista de URLs realmente consultadas.
Use recent=True só quando a resposta depende do dia de hoje (clima,
cotação, placar, notícia). Para fatos estáveis (história, biografia,
conceitos), deixe recent=False — filtrar por data descarta as melhores
fontes.
Configuração
Nenhuma variável é obrigatória. Toda uma tem default no código, e o
servidor sobe sem configuração alguma. Você só declara o que desviar do
padrão — na prática, SEARXNG_URL e MODEL_BASE_URL, se os seus não
estiverem nas portas abaixo.
A lista completa, com o default de cada uma:
Log
Variável | Default | O que faz |
|
|
|
Modelo (API compatível com OpenAI)
Variável | Default | O que faz |
| (vazio) | Nome do modelo a usar. Vazio = usa o modelo default do servidor, ou seja, o que já está carregado: o servidor consulta |
|
| Base da API compatível com OpenAI, sem o |
|
| Vai como |
|
| Timeout, em segundos, de cada chamada de LLM. Modelo grande em CPU pode precisar de mais |
|
| Temperatura das chamadas. |
|
| Janela de contexto do modelo. Tem que bater com o |
|
| Quanto da janela fica reservado para o que não é dossiê: instruções, pergunta e a resposta que o modelo ainda vai gerar. O orçamento do dossiê é |
| (vazio) | JSON cru mesclado no payload do |
| (vazio) | Texto apenso ao fim do system prompt em toda chamada. Existe porque nem todo modelo desliga reasoning por parâmetro de API — em alguns só obedece por instrução. Ex. |
SearXNG
Variável | Default | O que faz |
|
| Base da sua instância SearXNG. Precisa estar com o formato JSON habilitado |
|
| Quantos resultados são pedidos por busca. O |
|
| Timeout, em segundos, de cada consulta ao SearXNG |
|
| Idioma passado na busca. Muda que fontes aparecem — para pesquisar em inglês, |
|
| Categorias do SearXNG, separadas por vírgula, repassadas cruas |
Scraper
Variável | Default | O que faz |
|
| Timeout, em segundos, do download de cada página. Baixo de propósito: no |
| (vazio) | Corte de caracteres do texto extraído no |
Research
Variável | Default | O que faz |
|
| Quantas páginas entram no dossiê de uma pesquisa, somando todas as buscas. É o principal botão de qualidade × latência |
|
| Reserva de links candidatos. Link morto, bloqueado ou sem texto não gasta vaga do orçamento: cede o lugar para o próximo da reserva |
|
| Teto de tentativas de leitura antes de desistir. Sem ele, uma sequência ruim de links varreria a reserva inteira e estouraria a latência |
|
| Teto de caracteres por página no dossiê do |
Servidor MCP
Variável | Default | O que faz |
|
| Nome que o servidor anuncia no handshake MCP |
|
| Transporte usado quando você não passa |
|
| Interface de escuta no modo |
|
| Porta de escuta no modo |
|
| Origens liberadas no CORS do modo |
| (fuso do host) | Fuso usado no carimbo de data do resumo. Conveniência para container, cujo padrão é UTC. Ex. |
Juiz do eval
Variável | Default | O que faz |
| (mesmo do | Modelo usado como juiz no eval. Apontar para um modelo diferente do que escreveu o resumo torna a avaliação bem menos complacente |
Sobre MCP_HOST e MCP_CORS_ALLOW_ORIGINS: o servidor não tem autenticação
nenhuma. Com os defaults ele só escuta em 127.0.0.1, o que restringe o acesso
à sua máquina. Trocar MCP_HOST para 0.0.0.0 expõe as duas tools para
qualquer um na rede, sem credencial — o que permite usar seu servidor como
proxy de scraping e queimar seu LLM. Se precisar compartilhar na rede, ponha um
reverse proxy com autenticação na frente e restrinja
MCP_CORS_ALLOW_ORIGINS às origens que você de fato usa.
De onde a configuração vem
Isto não depende do transporte: a leitura acontece no import do config, antes
de stdio ou http entrarem em cena. O que decide é onde o config.py está.
Origem | Rodando do clone | Instalado ( |
| vale | ignorado |
Variável de ambiente | vale, e sobrescreve o | único caminho |
Default do código | fallback | fallback |
load_dotenv() procura o .env subindo a partir do diretório do
config.py. No clone isso chega na raiz do projeto e acha o arquivo; instalado,
o config.py mora no site-packages e a busca não encontra nada — nem mesmo um
.env que exista no diretório de onde o servidor foi executado. Instalado,
portanto, tudo entra por variável de ambiente.
De onde sai essa variável de ambiente, aí sim depende do transporte: no stdio,
do bloco env do cliente (-e), que é quem spawna o processo; no http, do
ambiente de quem subiu o processo — export, systemd, compose.
A precedência é variável de ambiente > .env > default, porque o
load_dotenv() roda sem override. Útil no clone para testar uma variação sem
editar arquivo:
MODEL_BASE_URL=http://localhost:8205/v1 uv run web-search-mcp --httpConfigurando o servidor instalado
Declare no bloco env do registro:
claude mcp add web-search \
-e SEARXNG_URL=http://localhost:8886 \
-e MODEL_BASE_URL=http://localhost:8200/v1 \
-e MODEL_CONTEXT_TOKENS=65536 \
-e TZ=America/Sao_Paulo \
-- uvx --from git+https://github.com/fabio-barboza/web_search_mcp@v0.1.0 web-search-mcpNote que MODEL não aparece: deixado de fora, o servidor usa o modelo já
carregado no seu MODEL_BASE_URL. Passe -e MODEL=nome-do-modelo só para
fixar um.
O comando acima grava isto no .mcp.json (escopo de projeto) ou no
~/.claude.json (escopo de usuário, com -s user):
{
"mcpServers": {
"web-search": {
"command": "uvx",
"args": ["--from", "git+https://github.com/fabio-barboza/web_search_mcp@v0.1.0", "web-search-mcp"],
"env": {
"SEARXNG_URL": "http://localhost:8886",
"MODEL_BASE_URL": "http://localhost:8200/v1"
}
}
}
}O que entra em env fica em texto puro nesse arquivo. Para SEARXNG_URL e
MODEL_BASE_URL isso não tem consequência, mas se o seu provedor de LLM exigir
uma MODEL_API_KEY real, ela vai parar no .mcp.json — que costuma ser
versionado quando está no escopo de projeto. Nesse caso registre com
claude mcp add -s user, que grava em ~/.claude.json, fora do repositório.
Detecção de modelo
Quando MODEL fica vazio, a primeira chamada de LLM consulta
GET {MODEL_BASE_URL}/models para achar o modelo já carregado, em vez de
forçar um específico (evita pagar reload de GPU a troco de nada). Funciona
nativamente com routers que expõem status de load (ex. llama.cpp/llama-swap);
em providers genéricos, cai no único modelo da lista ou pede pra você
preencher MODEL explicitamente se houver ambiguidade.
Testes
uv run --group test pytestTudo determinístico — mocka rede e LLM, não precisa de SearXNG nem de modelo rodando.
Eval
uv run python -m evals.runRoda um conjunto fixo de perguntas contra a web e o LLM reais, mede
faithfulness (afirmações do resumo suportadas pelo dossiê) e relevância, e
salva o resultado em evals/results/. Não é teste de CI — a web muda entre
execuções — serve para comparar rodadas e pegar alucinação escancarada, não
como avaliação independente (o juiz costuma ser o mesmo modelo que escreveu o
resumo).
Estrutura
src/web_search_mcp/
server.py # FastMCP: tools, prompt, transporte, main()
config.py # única fonte de configuração (lê o .env inteiro)
llm.py # chat completion via requests, detecção de modelo
tools/
read_url.py # tool: lê uma URL específica
research.py # tool: pesquisa, lê páginas, resume com fontes
util/
scraper.py # download + extração de conteúdo principal (anti-SSRF)
searxng.py # cliente do SearXNG
tests/ # pytest, sem rede, sem LLM
evals/ # roda contra web/LLM reais, sob demanda
searxng/ # docker compose do SearXNG (dependência externa, opcional)Layout src/ de propósito: o pacote instalado ocupa um único namespace
(web_search_mcp), em vez de despejar server/config/util na raiz do
site-packages e colidir com outros pacotes.
Available Tools
3 toolsanalyze_urlsA
Lê uma ou mais URLs e devolve uma análise pronta, sem o texto bruto.
Use quando o usuário fornecer a(s) URL(s) e quiser resumo, parecer técnico, opinião ou comparação entre páginas: a leitura e a análise acontecem internamente e só o resultado volta — o conteúdo integral das páginas não entra no seu contexto. Prefira read_url apenas quando o texto completo da página for necessário de verdade.
| Name | Required | Description | Default |
|---|---|---|---|
| urls | Yes | 1 a 8 URLs completas (http/https), na ordem em que devem ser referidas. Para comparação, passe todas na mesma chamada. | |
| request | No | O pedido em linguagem natural, como o usuário fez ("resuma", "dê um parecer técnico sobre a proposta", "compare os dois produtos e recomende um"). Vazio = resumo. | Resuma o conteúdo. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the behavioral burden and does meaningful work: it discloses that full page content will not enter the agent's context and that only the analysis result returns. It does not cover error or failure behavior, but for a URL-reading tool the key privacy/context behavior is clearly disclosed.
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 three sentences with no filler: a crisp purpose statement, a usage condition list, and an explicit pointer to the alternative tool. It is front-loaded and every sentence earns its place.
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 output schema covers return shape, the input schema fully documents both parameters, and the description covers when to use the tool, when to avoid it, and what behavioral guarantee to expect. Although research_web is not named, the phrase 'quando o usuário fornecer a(s) URL(s)' clearly separates this tool from web research.
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?
Schema description coverage is 100% and the schema already documents URL count, ordering, comparison usage, the request default, and examples. The description reinforces the comparison use case but does not add significant parameter-level meaning beyond what the schema provides, so the baseline score of 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 first sentence states a specific verb ('Lê'), resource ('URLs'), and outcome ('devolve uma análise pronta, sem o texto bruto'), which makes the tool's function unambiguous. The negative clause about raw text also distinguishes it from read_url.
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 explicitly says when to use the tool ('quando o usuário fornecer a(s) URL(s) e quiser resumo, parecer técnico, opinião ou comparação') and names the alternative for the opposite case ('Prefira read_url apenas quando o texto completo da página for necessário de verdade'). This gives the agent clear routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_urlA
Abre uma URL específica e devolve o conteúdo principal da página.
UMA página por chamada, e o texto bruto inteiro entra no seu contexto. Se você precisa ler VÁRIAS páginas, use analyze_urls (aceita até 8 de uma vez, lê todas, e devolve só a análise) — encadear read_url gasta contexto e tempo à toa.
O texto vem com um cabeçalho "Fonte desta página" e um link markdown pronto. Use esse link ao citar qualquer coisa que tenha lido aqui: nome de página sem endereço não é fonte, é referência que o usuário não consegue conferir.
Use quando o usuário fornecer um link e pedir para você ler, resumir, analisar ou extrair algo dele. Diferente de research_web, aqui não há busca nem resumo interno: a página é lida e o texto bruto (em Markdown) volta para você processar conforme o que foi pedido.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | O endereço completo da página (http/https). |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Não há annotations, e a descrição assume integralmente o papel de transparência. Ela revela que uma página por chamada é lida, que o texto bruto inteiro entra no contexto, que o retorno inclui cabeçalho 'Fonte desta página' com link markdown pronto, e que não há resumo interno — comportamento relevante para o agente saber o que esperar.
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?
Embora mais longa que o mínimo, cada frase agrega valor: scopo, aviso de contexto, alternativa, instrução de citação e comparação com o irmão. A informação essencial está na frente e a estrutura é clara, sem redundância.
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?
Para uma ferramenta com um único parâmetro, output schema presente e um irmão alternativo, a descrição cobre uso, diferenças, retorno e implicações de contexto. Nada essencial para selecionar e invocar corretamente está ausente.
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?
Há apenas um parâmetro, url, com description no schema cobrindo 100% do significado ('O endereço completo da página (http/https)'). A descrição do tool acrescenta pouco além de reforçar que é uma URL específica, então o baseline 3 é adequado já que o schema faz o trabalho.
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?
A descrição usa verbo específico ('Abre uma URL específica') e recurso claro ('devolve o conteúdo principal da página'), diferenciando-se imediatamente dos irmãos: analyze_urls lê várias páginas e research_web faz busca/resumo. A função e o escopo de uma chamada ficam inequívocos.
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?
Há orientação explícita de quando usar: 'quando o usuário fornecer um link e pedir para você ler, resumir, analisar ou extrair algo dele'. Também indica explicitamente a alternativa para múltiplas páginas ('encadear read_url gasta contexto e tempo à toa') e a diferença frente a research_web, que não faz busca nem resumo interno.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
research_webA
Pesquisa na web e devolve um resumo com fontes.
Use para qualquer informação que você não saiba com certeza — e também quando acha que sabe mas o assunto pode ter mudado desde o seu treino: nesses casos, prefira pesquisar a responder de memória. Passe a pergunta completa em linguagem natural — a busca, a leitura das páginas e o resumo são feitos internamente.
UMA CHAMADA POR PERGUNTA. Esta ferramenta já reformula a pergunta em vários ângulos de busca por dentro, roda todos em paralelo e lê as melhores páginas do conjunto. Chamar de novo com a mesma pergunta escrita de outro jeito não traz material novo: relê as mesmas páginas e gasta o mesmo tempo outra vez. Só chame outra vez quando a pergunta for genuinamente outra, ou quando o resumo apontar o que faltou. Pergunta NOVA do usuário = chamada nova, mesmo que seja sobre o mesmo assunto de antes: cada pergunta diferente merece sua própria pesquisa.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | A pergunta completa em linguagem natural, do jeito que o usuário faria. Não reduza a palavras-chave nem parta em pedaços: a reformulação em termos de busca é feita aqui dentro, e uma pergunta inteira dá um resultado melhor que um fragmento. | |
| recent | No | True apenas quando a resposta depende do dia de hoje (clima, cotação, placar, notícia de agora). False para fatos estáveis (história, biografia, conceitos, documentação), pois filtrar por data descarta as fontes boas. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, and it delivers: it discloses that the tool internally reformulates the query into multiple search angles, runs them in parallel, reads the best pages, and summarizes. It also reveals that calling again with the same question yields no new material, which is a significant behavioral trait. This goes far beyond a basic purpose statement and provides actionable insight for the agent.
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 front-loaded with the core purpose ('Pesquisa na web e devolve um resumo com fontes') and then provides essential usage and behavioral guidance. It is somewhat verbose, especially the repeated explanation of one-call-per-question, but every sentence adds value. It is well-structured into coherent paragraphs, though it could be tightened.
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 tool is relatively simple (search + summarize), and the description covers when to use it, how to phrase the query, and the one-call-per-question rule. The output schema exists, so the description does not need to explain return formats. Annotations are absent, but the description provides all necessary behavioral context for an agent to call the tool correctly. Nothing essential is missing.
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?
Schema coverage is 100% – both 'query' and 'recent' have detailed descriptions in the schema. The description's instructions on passing the full natural-language query are already present in the schema, so it adds little over the structured definitions. The baseline of 3 is appropriate because the schema already explains parameters thoroughly.
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 'Pesquisa na web e devolve um resumo com fontes' (searches the web and returns a summary with sources), which is a specific verb and resource. It clearly differentiates from 'read_url' and 'analyze_urls' by focusing on autonomous searching rather than processing given URLs, though it does not explicitly name the siblings. The purpose is unambiguous.
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 gives explicit when-to-use guidance: 'Use para qualquer informação que você não saiba com certeza' and 'quando acha que sabe mas o assunto pode ter mudado' – effectively stating to use this tool instead of memory when uncertain or potentially outdated. It also provides a clear when-not-to-call repeatedly: 'Só chame outra vez quando a pergunta for genuinamente outra'. However, it does not explicitly mention alternatives like read_url or analyze_urls, so it stops short of full alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Each tool has a clearly distinct purpose: read_url returns raw content, analyze_urls returns an analysis of provided URLs, and research_web performs a web search with summarized results. Descriptions explicitly cross-reference the tools to prevent confusion.
All tool names follow the same verb_noun snake_case pattern: read_url, analyze_urls, research_web. The naming is predictable and immediately communicates the action and target.
Three tools is well-scoped for a web research server: one for raw reading, one for URL analysis, and one for open-ended search. Each tool covers a distinct workflow without unnecessary redundancy.
The tool surface covers the full web research workflow: searching, reading a page in full, and analyzing one or more provided URLs. There are no obvious missing operations that would block an agent from completing typical research tasks.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Docs: https://docs.keenable.ai/mcp-server Keenable is a free, remote MCP server that gives agents access to the web index. Search the web with ranked results and date/site filters, then fetch any indexed page as clean markdown. Works out of the box with no account or API key.
An MCP server for deep research or task groups
Live AI-native web search with citations. One tool for every MCP client. Flat per-request pricing.
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP server that enables web searching, URL content extraction, and summarization without requiring API keys. It also provides advanced mathematical evaluation and multi-language Wikipedia summary retrieval tools.53196MIT
- AlicenseNot gradedqualityAmaintenanceA self-contained web-research MCP server that lets local LLM agents search, fetch, and synthesize web content using tools like web_search, web_fetch, and web_research.1MIT
- AlicenseNot gradedqualityCmaintenanceMulti-purpose research MCP server integrating web search, deep research, web scraping, research methodology routing, and GPT Researcher report generation.MIT
- AlicenseCqualityAmaintenanceAn MCP server for deep research that performs search, scraping, synthesis, fact-checking, and persistent memory, enabling users to conduct comprehensive research tasks via Claude.81MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/fabio-barboza/web_search_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server