internet-context-mcp
Servidor MCP somente leitura que fornece a agentes de IA a web como evidência compacta, ranqueada e verificada. Reranker local de codificador cruzado, verificação de alegações NLI, detecção semântica de concordância e contradição entre fontes. Sem chaves de API.
Documentação
internet-context-mcp
Um servidor MCP somente leitura que dá a agentes de IA a web como evidência compacta, ranqueada e verificada — sem chaves de API, sem recuperação em nuvem, todos os modelos locais.
Seis ferramentas somente leitura — web_research, web_context, web_search, web_read, web_verify, web_extract — além de recursos MCP, prompts e metadados outputSchema / readOnlyHint adequados. Por trás de cada ferramenta: ranqueamento BM25 local, um reranker cross-encoder local, um classificador NLI local, embeddings de sentença locais, um scanner regex de injeção de prompt e um cache de busca em duas camadas (em memória + SQLite).
Medido, não aspiracional: 20/20 na avaliação de relevância, 92,5% de recall de injeção de prompt com 0% de taxa de falso positivo em páginas benignas, detector de contradição com 0 falsos positivos na web real (veja a tabela de avaliação abaixo).
Início rápido
Adicione isto ao seu claude_desktop_config.json (ou configuração equivalente de host MCP):
{
"mcpServers": {
"internet-context": {
"command": "npx",
"args": ["-y", "internet-context-mcp"]
}
}
}
Reinicie o host. Só isso.
A primeira chamada baixa preguiçosamente três modelos locais do HuggingFace (~125 MB no total, em cache): o reranker cross-encoder, o classificador NLI e o modelo de embedding de sentenças. Uma vez em cache, o servidor roda totalmente offline. Nenhuma chave de API é necessária em nenhum momento.
Variáveis de ambiente opcionais
{
"env": {
"BRAVE_SEARCH_API_KEY": "", // optional: use Brave instead of the DDG fallback
"INTERNET_CONTEXT_MCP_RERANK": "0", // optional: disable the cross-encoder reranker
"INTERNET_CONTEXT_MCP_NLI": "0", // optional: disable NLI for web_verify
"INTERNET_CONTEXT_MCP_EMBEDDINGS": "0", // optional: disable semantic clustering / contradictions
"INTERNET_CONTEXT_MCP_CACHE_DIR": "" // optional: override SQLite cache path
}
}
Executar localmente a partir do código-fonte (desenvolvedores)
git clone https://github.com/vivekvar-dl/internet-context-mcp
cd internet-context-mcp
npm install
npm run build
node dist/index.js # exits when stdin closes — used by the MCP host
O que há na v0.4.x
web_research— busca única + busca multi-fonte + ranqueamento entre fontes + citações por bloco + sinal de concordância baseado em redundância + detecção de contradição com suporte NLI.web_verify— verificação de afirmação versus fontes, com suporte do classificador NLI (implicação / neutro / contradição), fallback por regex.web_context— busca + ranqueamento + retorno de blocos de evidência ranqueados com cápsula de prioridade (TL;DR), sinal de confiança de recuperação, extração de dados estruturados, varredura de injeção de prompt, proveniência da fonte com caminhos DOM.web_read— texto de página limpo e compacto com metadados de economia de tokens.web_search— Brave quandoBRAVE_SEARCH_API_KEYestiver definido; fallback DuckDuckGo HTML caso contrário.web_extract— extração orientada por esquema de melhor esforço.
Além disso:
- Anotações
readOnlyHint: true+openWorldHint: trueem todas as ferramentas. Claude Desktop / Code pode pular prompts de permissão. outputSchemaem todas as ferramentas. Hosts recebem JSON tipado (structuredContent) em vez de reanalisar texto livre.- Template de recurso MCP
internet-context://page/{fingerprint}— o host pode referenciar novamente páginas buscadas por URI sem chamar uma ferramenta novamente. - Templates de prompt MCP
verify_with_sources,summarize_from_context,research_a_topic. - Cache de busca em duas camadas: em memória + uma camada SQLite persistente em
~/.cache/internet-context-mcp/cache.sqlite. Sobrevive a reinicializações do host. - Tokenizer
js-tiktokenreal (cl100k_base). Chega de aproximaçõeschars / 4. - Renderização Playwright opcional para SPAs com muito JS via
render: "browser", distribuído como umoptionalDependency.
Veja CHANGELOG.md para o detalhe por versão.
O que há dentro de uma cápsula de contexto
Uma resposta web_context inclui:
- uma cápsula de prioridade curta (TL;DR) antes da evidência longa
- blocos de evidência ranqueados com deslocamentos de caracteres, caminhos de seção e caminhos DOM
- um sinal de confiança de recuperação para que o agente possa pedir mais fontes quando necessário
- dados estruturados da página, quando presentes (JSON-LD, microdata, metadados)
- metadados da página e impressões digitais de conteúdo
- avisos de risco de injeção de prompt (visível / oculto / comentário / metadados)
- estimativas de economia de tokens
Ferramentas
web_research
Ferramenta de pesquisa única: busca na web, busca dos N principais resultados em paralelo, ranqueamento de blocos dentro de cada fonte (com o reranker local por padrão), depois ranqueamento cruzado global e retorno de um pacote de evidência unificado com citações de fonte por bloco e um sinal de concordância baseado em redundância.
Use isto quando você estaria chamando web_search e depois web_context várias vezes seguidas.
Entrada:
{
"query": "What is the Model Context Protocol and who built it?",
"depth": 4,
"max_tokens_total": 3000
}
Formato de saída (abreviado):
{
"query": "...",
"provider": "duckduckgo_html",
"depth": 4,
"unique_sources": 3,
"sources": [
{
"index": 0,
"requested_url": "https://en.wikipedia.org/wiki/Model_Context_Protocol",
"ok": true,
"title": "Model Context Protocol - Wikipedia",
"retrieval_confidence": { "level": "high", "score": 0.79 },
"selected_chunks": 1
}
],
"ranked_evidence": [
{
"source_index": 1,
"source_url": "https://www.anthropic.com/news/model-context-protocol",
"source_title": "Introducing the Model Context Protocol",
"chunk_id": 2,
"cluster_id": 2,
"agreement_count": 1,
"score": 1.0,
"combined_score": 1.0,
"section": null,
"matched_terms": ["model", "context", "protocol"],
"text": "Today, we're open-sourcing the Model Context Protocol..."
}
],
"agreement_score": 0.0,
"verdict_reasons": ["sources_did_not_overlap"],
"token_budget": { "max_tokens_total": 3000, "used_tokens": 1949 }
}
agreement_count e agreement_score usam similaridade semântica (cosseno all-MiniLM-L6-v2, ~22MB, carregado preguiçosamente) por padrão na v0.4.0+. Concordância parafraseada agora conta: três fontes dizendo independentemente o mesmo fato com palavras diferentes serão agrupadas. O agrupamento recorre a Jaccard de shingle de 4-gramas quando o modelo de embedding falha ao carregar; o campo clustering_method em cada resposta mostra qual foi usado.
contradictions lista casos em que blocos de fontes diferentes estão no mesmo tópico, mas nenhum implica o outro em nenhuma direção. O detector roda em duas etapas: um pré-filtro de cosseno de embedding (≥0,45) que exige que os dois blocos estejam discutindo a mesma afirmação, e depois uma verificação de não-implicação bidirecional NLI (≤0,05 de implicação em ambas as direções) nos sobreviventes. Ambas devem ser válidas.
Cada contradição inclui topical_similarity (o cosseno real) e confidence (o sinal NLI).
O pré-filtro intencionalmente permite pares do mesmo cluster: no mundo real, duas fontes fazendo afirmações opostas sobre o mesmo fato se parafraseiam com cosseno muito alto (~0,9), então elas se agrupam. Excluir pares do mesmo cluster significaria perder as contradições que mais queremos revelar.
Avaliação do detector — medido, não aspiracional
Isto é o que medimos que o detector realmente faz. Os scripts de avaliação estão em scripts/demo-contradiction-*.ts para que os números sejam reproduzíveis.
| Conjunto de avaliação | Fontes buscadas | Contradições detectadas | O que significa |
|---|---|---|---|
| Positivo sintético ("café reduz risco cardiovascular" vs "café aumenta risco cardiovascular") | n/a | 1 (conf 0,9999, tópico 0,91) | O detector dispara em desacordo inequívoco feito à mão |
| 5 consultas ao vivo (ovos, jejum intermitente, café/coração, velocidade da luz, capital da França) | 18 | 0 | Zero falsos positivos. A v0.4.0 produziu 3 falsos positivos neste conjunto exato; a v0.4.1 eliminou todos. |
| 3 pares de URL selecionados precisamente porque as fontes deveriam discordar (aspirina em prevenção primária, vitamina D, gordura saturada) | 5 de 8 — NEJM/BMJ retornaram 403 para busca estática | 0 | As fontes que foram buscadas deram cautela matizada; fontes primárias onde a disputa é direta estavam atrás de paywall. |
| 3 varreduras de busca com profundidade=8 em tópicos com divisões conhecidas entre popular e evidência (alongamento, café da manhã, corrida e joelhos) | 23 de 24 | 0 | Os mecanismos de busca retornam o consenso atual; a disputa vive em outro lugar. |
Em cerca de 30 fontes reais buscadas, o detector disparou exatamente zero vezes. Também produziu zero falsos positivos.
A afirmação verdadeira sobre a v0.4.x: o detector tem taxa de falso positivo quase zero na web real e dispara de forma confiável em afirmações opostas lexicalmente explícitas. Ele não detecta, em nossos testes, disputas reais mas expressas com prosa cautelosa ou qualificada — que é como a maior parte da web indexada fala sobre desacordo. Três razões:
- Os mecanismos de busca (DDG, Google) retornam conteúdo mainstream homogeneizado; a disputa vive em artigos acadêmicos ou fontes contrárias que não ranqueiam bem.
- A prosa da web mainstream qualifica seu desacordo ("alguns estudos sugerem", "para certas populações", "pesquisas recentes mostraram"). A não-implicação bidirecional do NLI não dispara em contraste cauteloso.
- Muitas fontes primárias onde a disputa é direta (NEJM, BMJ, ScienceDirect, Britannica) bloqueiam buscas estáticas com HTTP 403.
Se você quiser que o detector capture desacordo cauteloso, precisaria afrouxar o teto de implicação e aceitar alguns falsos positivos. Se quiser acesso mais amplo a fontes, precisaria de renderização de navegador e (para periódicos com paywall) credenciais. A v0.4.x não faz nenhum dos dois; permanece somente leitura, local e honesta sobre o que vê.
Ressalva honesta sobre o sinal de concordância: quando agreement_count=N em N fontes, isso significa que N fontes dos resultados de busca se corroboraram — não que a afirmação seja verdadeira. Os mecanismos de busca tendem a retornar a visão mainstream atual, o que pode esconder disputas genuínas (a consulta ovos/colesterol retornou 4 fontes modernas todas concordando com o consenso moderno, mesmo que o tópico tenha sido contestado por décadas).
web_context
Busca uma URL, limpa-a, divide-a em blocos, ranqueia blocos contra uma tarefa de agente com um algoritmo local estilo BM25 e retorna apenas o melhor orçamento de evidência. Esta é a principal ferramenta de redução de tokens.
Entrada:
{
"url": "https://example.com/docs",
"task": "find installation steps and configuration details",
"max_tokens": 1800
}
Formato de saída:
{
"task": "find installation steps and configuration details",
"title": "Documentation",
"context": "[chunk 2 | score 1]\\nInstall the package with npm install example...",
"evidence_chunks": [
{
"id": 2,
"score": 1,
"score_breakdown": {
"bm25": 2.4,
"phrase": 0,
"heading": 0.5,
"metadata": 0.35,
"structured_data": 0,
"position": 0
},
"provenance": {
"char_start": 182,
"char_end": 348,
"section": "Installation",
"section_path": ["Installation"],
"source_blocks": [
{
"block_id": 4,
"tag": "p",
"dom_path": "body:nth-of-type(1) > main:nth-of-type(1) > section:nth-of-type(1) > p:nth-of-type(1)",
"line_start": 22,
"line_end": 22,
"overlap_score": 1,
"text_preview": "Install the package with npm install example."
}
]
},
"matched_terms": ["install", "config"],
"text": "Install the package with npm install example..."
}
],
"structured_data": {
"metadata": {
"description": "..."
},
"json_ld": [],
"microdata": []
},
"safety": {
"risk": "low",
"score": 0,
"warnings": []
},
"priority_capsule": {
"tldr": "Install with npm install example. Configure via the MCP client config file.",
"top_sections": ["Installation", "Configuration"],
"highlight_chunk_ids": [2, 3]
},
"retrieval_confidence": {
"level": "high",
"score": 0.78,
"reasons": [],
"suggestion": null
},
"provenance": {
"content_fingerprint": "9f2a1c6e7b0d3a11",
"clean_text_fingerprint": "3d41e2f0780a5c19"
},
"ranking": {
"algorithm": "hybrid-bm25-lite",
"signals": ["bm25", "phrase", "heading", "metadata", "structured_data", "position"],
"total_chunks": 12,
"selected_chunks": 3,
"selected_tokens": 940
},
"token_savings_estimate": {
"raw_tokens": 42000,
"returned_tokens": 1100,
"saved_tokens": 40900,
"savings_ratio": 0.9738
}
}
web_read
Busca uma URL, remove o ruído visual da página, extrai o conteúdo principal e retorna texto limpo além de metadados de economia de tokens.
Entrada:
{
"url": "https://example.com/docs",
"query": "installation configuration",
"mode": "compact",
"max_tokens": 4000
}
web_search
Busca na web e retorna resultados compactos e classificados por fonte.
Se BRAVE_SEARCH_API_KEY estiver definido, usa Brave Search. Caso contrário, recorre à busca HTML do DuckDuckGo.
Entrada:
{
"query": "Model Context Protocol TypeScript SDK docs",
"limit": 5
}
web_verify
Verifica se uma afirmação é apoiada, refutada ou incerta a partir de uma ou mais URLs de fonte. Busca cada fonte, ranqueia blocos contra a afirmação e procura por apoio ou contradição explícita (com detecção simples de negação perto dos termos correspondentes). Retorna um veredito combinado além de blocos de evidência de apoio e refutação por fonte.
Entrada:
{
"claim": "the server is read-only",
"sources": [
"https://example.com/docs",
"https://example.com/safety"
],
"max_tokens_per_source": 1400
}
Formato de saída:
{
"claim": "the server is read-only",
"verdict": "supported",
"confidence": 0.82,
"reasons": ["2_sources_support"],
"sources": [
{
"requested_url": "https://example.com/docs",
"final_url": "https://example.com/docs",
"title": "Documentation",
"verdict": "supported",
"confidence": 0.74,
"supporting_chunks": [
{
"chunk_id": 3,
"section": "Safety",
"score": 0.91,
"matched_terms": ["server", "read", "only"],
"contains_negation": false,
"text_preview": "The default tools are read-only and never submit forms or modify remote data."
}
],
"refuting_chunks": []
}
]
}
web_extract
Extração genérica de campos de melhor esforço a partir do texto limpo da página. Isto é intencionalmente secundário ao web_context; em muitos agentes, o fluxo melhor é chamar web_context e deixar o modelo host raciocinar sobre os blocos de evidência retornados.
Entrada:
{
"url": "https://example.com/docs",
"schema": {
"title": "string",
"install_command": "string",
"configuration_file": "string"
},
"query": "installation command configuration file"
}
Instalação
npm install
npm run build
npm test
Teste de Estresse em Sites Reais
O repositório inclui um conjunto de estresse com 100 URLs de dados reais em data/real-sites.json. Ele exercita o pipeline completo contra páginas ao vivo:
npm run stress:real
Opções úteis:
npm run stress:real -- --limit=20 --concurrency=3 --timeout=15000 --maxTokens=1500
O script escreve um relatório compacto em:
reports/stress-real-sites-latest.json
Ele mede sucesso de busca ao vivo, economia de tokens, blocos selecionados, detecção de dados estruturados, avisos de segurança e cobertura de proveniência de fonte.
Avaliação de Injeção de Prompt
O repositório inclui um conjunto adversarial de 54 casos em evals/prompt-injection.json cobrindo sobreposição visível de instruções, texto oculto (display:none / visibility:hidden / opacity:0 / aria-hidden / fora da tela), injeção em comentários HTML, solicitações de credenciais, prompts de exfiltração e páginas de controle benignas.
npm run eval:injection
Números relatados para a v0.4.0 (scanner regex, sem LLM):
{
"true_positive_rate": 0.925,
"false_positive_rate": 0,
"precision": 1,
"recall": 0.925,
"by_category": {
"instruction_override_visible": 0.80,
"hidden_text": 0.90,
"html_comment": 1.00,
"credential_request": 1.00,
"exfiltration": 1.00,
"benign_control": 1.00
}
}
Falhas conhecidas: "desconsidere as instruções anteriores" (artigo interveniente), enquadramento "não é mais válido", posicionamento fora da tela via position:absolute;left:-9999px. Falhas reais, intencionalmente expostas em vez de encobertas.
Avaliação de Relevância
O repositório inclui um conjunto de relevância rotulado em evals/relevance.json. Ele verifica se cápsulas comprimidas preservam fatos necessários, evitam termos inúteis, permanecem sob o orçamento de tokens de evidência e incluem proveniência de fonte.
npm run eval:relevance
A execução mais recente de 20 casos na v0.3.0 (reranker ativado por padrão, tokenizer real) passou em todos os casos:
{
"all_pass_rate": 1,
"included_pass_rate": 1,
"excluded_pass_rate": 1,
"provenance_pass_rate": 1,
"token_budget_pass_rate": 1,
"average_token_savings_ratio": 0.9192
}
O relatório é escrito em:
reports/eval-relevance-latest.json
Executar
npm run dev
Para uso compilado:
npm run build
node dist/index.js
Configuração do Cliente MCP
Para clientes que aceitam configuração JSON de servidor MCP:
{
"mcpServers": {
"internet-context": {
"command": "node",
"args": ["C:/Users/domai/internet-context-mcp/dist/index.js"],
"env": {
"BRAVE_SEARCH_API_KEY": ""
}
}
}
}
Restrições de Design
- Somente leitura primeiro: sem cliques, login, compras, envio de formulários ou ações que mudam estado.
- Saída compacta primeiro: agentes devem receber contexto útil, não despejos de página.
- Ranqueamento local primeiro: reduzir tokens sem exigir uma segunda chave de API de LLM.
- Evidência primeiro: o contexto retornado deve incluir o texto usado para apoiar afirmações.
- Conteúdo web não confiável primeiro: páginas são varridas em busca de texto semelhante a instruções antes que o agente raciocine sobre elas.
- Limites honestos: extração fraca deve ser marcada como fraca em vez de fingir ser confiável.
Status Atual
Este é um protótipo open-source inicial. A parte mais forte é web_context: limpeza local, divisão em blocos, ranqueamento, descoberta de dados estruturados, varredura de segurança e redução de tokens. A parte mais fraca é a extração estruturada genérica sem um LLM, então essa ferramenta deve permanecer secundária até ter cobertura real de avaliação.
Configuração
Variáveis de ambiente:
BRAVE_SEARCH_API_KEY— se definida,web_searchusa o Brave Search em vez do fallback HTML do DuckDuckGo.INTERNET_CONTEXT_MCP_RERANK=1— ativa o reranker cross-encoder local globalmente. Desativado por padrão.INTERNET_CONTEXT_MCP_CACHE_DIR— substitui a localização do cache SQLite. O padrão é~/.cache/internet-context-mcp.
Para habilitar a renderização no navegador (necessária apenas para SPAs renderizadas via JS):
npm install playwright
npx playwright install chromium
Em seguida, chame qualquer ferramenta com render: "browser".
Próximos Marcos
- Decomposição de afirmações com múltiplas sentenças em
web_verifypara que afirmações compostas retornem veredictos por cláusula. - Âncoras estáveis de fragmentos de texto (
#:~:text=...) na proveniência dos trechos para vinculação profunda de volta à página. - Suporte a PDF no pipeline de busca + limpeza.
- Consciência de
robots.txt+ crawl-delay para busca responsável somente leitura. - Expandir a avaliação de injeção de prompt além dos 54 casos selecionados manualmente — integrar conjuntos de dados adversariais disponíveis publicamente.
- Fechar as lacunas de regex que a avaliação de injeção revelou (artigos intervenientes, "não é mais válido", posicionamento fora da tela).