Agent Evidence API

Evidência web citada e verificação de alegações para agentes de IA: envie uma pergunta ou alegação, além de URLs públicas, e receba trechos vinculados às fontes com horários de recuperação e hashes de conteúdo. A descoberta é gratuita; cada chamada é paga em USDC na Base via x402.

Servidor MCP hospedado

npx add-mcp 'https://agent-evidence-api.thx93.workers.dev/mcp'

Instala no Claude Code, Codex, Cursor e outros

Documentação

API de Evidências para Agentes (Agent Evidence API)

CI M8ven Score

Evidências web citadas e fundamentadas em fontes, e verificação de alegações para agentes de IA, tanto via HTTP quanto via MCP. Pagamento por chamada em USDC na Base via x402 — US$ 0,003 por chamada, e nada quando nada é recuperado.

O quêOnde
Endpoint de evidências HTTPPOST https://agent-evidence-api.thx93.workers.dev/v1/evidence
Serviço MCP (research_evidence)POST https://agent-evidence-api.thx93.workers.dev/mcp
Serviço MCP (get-alerts, get-forecast)POST https://agent-evidence-api.thx93.workers.dev/weather/mcp
Amostra gratuita de saída realGET https://agent-evidence-api.thx93.workers.dev/demo — uma resposta não editada de uma chamada paga real, sem necessidade de carteira
CLI de compra sem instalaçãocurl -fsSL https://agent-evidence-api.thx93.workers.dev/buy.mjs -o buy.mjs
Manifesto de capacidade x402https://agent-evidence-api.thx93.workers.dev/.well-known/x402

A descoberta é gratuita em todas as rotas MCP (tools/list, initialize, ping e uma ferramenta health), para que um agente possa ler os esquemas e testar a disponibilidade antes de pagar por qualquer coisa.

Opcional: ranqueamento semântico

O ranqueamento é, por padrão, correspondência lexical determinística, e tem um teto medido. Perguntado "Qual é a população de Tóquio?", ele retorna passagens que mencionam "população" e "Tóquio" — 1603 história, declínios em tempos de guerra, impostos municipais — e perde a frase que responde à pergunta, porque essa frase diz "a cidade propriamente dita" em vez de repetir "Tóquio". Duas heurísticas lexicais foram testadas e revertidas; nenhum truque de palavras-chave resolve isso.

Um Laya sidecar opcional resolve isso. Laya é um modelo de decisão tipada de pesos abertos (Apache-2.0): ele pontua uma passagem com noul, P(esta passagem responde diretamente à pergunta). Sem fornecedor, sem chave de API, sem taxa por chamada, e seu conteúdo nunca sai do host.

python services/laya/server.py                 # ~2 GB resident, ~35 s cold load
REASONING_PROVIDER=laya REASONING_URL=http://127.0.0.1:8077 ...

Medido no caso acima, fonte única:

FontesnonelayaO Top 3 contém a resposta?
1~1,4 s~11,4 s❌ → ✅
5~1,6 s~1,8 s (recorre ao lexical)❌ → ❌

O modelo é acionado somente quando o orçamento pode arcar com o pool completo. O custo é de ~800 ms por candidato (uma única chamada mede ~420 ms, mas o sidecar serializa, então ~700 ms sob concorrência real). O orçamento é dividido entre as fontes, então 1–2 fontes podem arcar com um pool de 12 e solicitações maiores não podem. Um pool mais estreito foi medido como inútil — ele só pode reorganizar passagens que já excluíam a resposta — então, em vez de gastar ~20 s nisso, essas solicitações recorrem ao lexical e permanecem rápidas. Reduza REASONING_POOL_SIZE para engajar em solicitações maiores, trocando recall.

O orçamento é um teto rígido, não um alvo: ele é reservado antes de cada chamada, para que fontes concorrentes não possam, coletivamente, ultrapassá-lo. (Uma versão anterior verificava e depois aguardava, o que permitia que cinco fontes passassem na verificação antes que qualquer uma o decrementasse — um orçamento de 8 s produziu uma solicitação de 50 s.)

A troca é latência, não precisão: ~420 ms por candidato, então um pool de 12 candidatos custa ~5 s de inferência por fonte. É por isso que está desativado por padrão. Ativá-lo muda apenas a ORDEM das evidências — cada trecho, fonte, URL e hash é idêntico — e se o sidecar estiver ausente, lento ou retornar qualquer coisa inesperada, o serviço mantém silenciosamente seu resultado lexical. A probabilidade bruta do modelo nunca é exposta (SPEC §21).

Observe que o pool importa: a primeira versão disso ranqueava apenas os 5 candidatos que o lexical já havia escolhido, e a resposta havia sido ranqueada em 8º–20º, então nunca estava disponível para promoção. O pool mais amplo é o que faz funcionar.

Executando o backend no Docker? O sidecar deve ser alcançável a partir do contêiner: --add-host=host.docker.internal:host-gateway e aponte REASONING_URL para http://host.docker.internal:8077, ou coloque ambos em uma única rede Docker.

Você só é cobrado quando o serviço entrega

O middleware x402 liquida um pagamento somente quando o handler retorna um status abaixo de 400, então o serviço é construído para que todas as formas de falha sejam 4xx ou 5xx:

  • Se nenhuma fonte puder ser recuperada — todos 404s, todos bloqueados por SSRF, todos os tipos de conteúdo não suportados — a solicitação falha com NO_SOURCES_RETRIEVED (502) e nenhum pagamento é feito. Uma versão anterior retornava 200 inconclusive aqui, o que teria cobrado de um comprador US$ 0,03 por um resultado vazio.
  • Sucesso parcial ainda liquida. Se uma de cinco fontes foi recuperada, evidências reais foram entregues e os avisos por fonte explicam o restante.
  • No transporte MCP, uma chamada de ferramenta com falha é relatada como isError: true dentro de um HTTP 200 — comportamento MCP correto, mas invisível para o middleware de pagamento. O Worker reescreve isso para 502 para que o pagamento não seja feito; o corpo JSON-RPC é passado adiante inalterado.

Verificado contra a implantação ativa: uma solicitação cujas fontes falham todas retorna 502 NO_SOURCES_RETRIEVED, e uma solicitação com uma fonte boa e uma morta retorna 200.

Análise de mercado

docs/market-analysis.md — o que a economia x402 realmente paga, medido a partir do único catálogo que publica dados de uso reais (chamadas de 30 dias e pagadores únicos por serviço). É uma leitura desconfortável: a categoria em que este serviço se encontra é 1% da busca por volume, e sua faixa de preço é a mais fraca das cinco.

Relatório de engenharia

docs/ENGINEERING-REPORT.md — o relatório exigido por SPEC.md §44: o que foi construído, a arquitetura, os comandos de implantação e teste, o status x402 e MCP, a prontidão para registro, a configuração manual restante e as limitações conhecidas. Ele declara claramente o que é demonstrado e o que não é — incluindo que nenhuma liquidação foi exercitada e que um critério de aceitação do §42 não foi atendido. Ele não afirma que o projeto está pronto para produção.

Ações que somente você pode tomar

docs/CHECKLIST.md — cada etapa restante que precisa de um humano: o primeiro pagamento, a confirmação da listagem no catálogo, a publicação e as decisões que deixei deliberadamente para você. Todo o resto está feito.

Fazendo a primeira venda

Veja docs/FIRST-SALE.md — todo o caminho de uma carteira vazia a um pagamento liquidado e uma entrada no catálogo, em uma página.

Como ver a receita

Cada solicitação que o backend atende em uma rota paga já passou pelo próprio gate de pagamento x402 do backend (o Worker apenas faz proxy). O log é somente de acréscimo no volume de dados, então ele sobrevive à recriação de contêineres e reimplantações — ao contrário dos logs do Docker.

Uma linha significa que uma prova de pagamento foi verificada neste processo. Não é prova de liquidação. A ordem x402 é verificar → handler → liquidar, então o backend escreve sua linha antes de o facilitador liquidar, e uma liquidação que falhar posteriormente ainda aparecerá aqui. O campo é nomeado payment_provided por esse motivo; anteriormente era chamado settled, o que estava errado.

docker exec aee-live cat /app/data/usage.jsonl            # the raw record

# Buyer traffic: requests that carried an x402 payment proof, so operator and
# test calls are excluded. This is NOT a revenue figure - see below.
docker exec aee-live sh -c "grep -c '"payment_provided":true' /app/data/usage.jsonl"

Para dinheiro, use o registro on-chain. O cliente do comprador imprime a transação de liquidação, e o livro-razão autoritativo é o endereço do destinatário:

https://basescan.org/address/0x9c0e2B44180439294Fa30Ae2B2a94f8655455FD0

Cada linha carrega o timestamp, o ID da solicitação, um hash salgado da pergunta (nunca o texto), quantas fontes foram recuperadas, quantos itens de evidência retornaram, a avaliação e a duração no lado do servidor.

{"ts":"2026-09-21T07:53:04.341Z","request_id":"req_2fcc…","question_hash":"725f50fca9fbe049",
 "question_chars":32,"sources_requested":1,"sources_retrieved":1,"evidence_items":5,
 "assessment":"supported","processing_ms":6,"outcome":"ok"}

Para o lado on-chain, a resposta de pagamento carrega um hash de transação de liquidação, e o destinatário é 0x9c0e2B44180439294Fa30Ae2B2a94f8655455FD0 — verifique-o no basescan.

Implantação ativa

Endpointhttps://agent-evidence-api.thx93.workers.dev
MCPhttps://agent-evidence-api.thx93.workers.dev/mcp
Saúde/health · profunda: /health?deep=1
Registroio.github.Thx93/agent-evidence-api — publicado, status ativo
Pagamentox402, exact, 0,03 USDC na mainnet da Base (eip155:8453)
Compresem instalação: curl -fsSL .../buy.mjs -o buy.mjs && node buy.mjs "question" https://source.example

Compre algo sem conta npm e sem nada para instalar — o CLI de compra é um único arquivo autocontido servido pelo próprio serviço:

curl -fsSL https://agent-evidence-api.thx93.workers.dev/buy.mjs -o buy.mjs
X402_PRIVATE_KEY=0x... node buy.mjs "Is Rotamech a manufacturer of centrifugal pumps?" https://example.com

Ou apenas veja o paywall primeiro — isso retorna um 402 e não cobra nada:

curl -X POST https://agent-evidence-api.thx93.workers.dev/v1/evidence \
  -H 'content-type: application/json' \
  -d '{"question":"Is Rotamech a manufacturer of centrifugal pumps?","urls":["https://example.com"]}'

Infraestrutura de evidências para agentes de IA. Dê a ele uma pergunta ou alegação, mais as páginas da web públicas que você deseja verificar, e ele retorna evidências estruturadas e citadas: URLs de origem, timestamps de recuperação, trechos curtos de evidência, metadados e uma avaliação explícita de supported / contradicted / mixed / inconclusive.

Ele é alcançável por agentes tanto via HTTP quanto via MCP, e é pago por solicitação com x402 + USDC na Base. Não há contas, senhas ou chaves de API — o pagamento é a autenticação.

Ele fornece evidências, não verdade. A avaliação é produzida por correspondência lexical determinística, e o serviço diz inconclusive em vez de adivinhar. Não trate um status supported como prova.

Status de implementação — leia isto primeiro. Todos os pacotes e ambos os aplicativos estão implementados, e pnpm typecheck passa em todo o workspace. pnpm test cobre ~147 casos em seis suítes, incluindo um teste de fluxo ponta a ponta entre pacotes.

O que não está feito: nenhum pagamento x402 on-chain foi demonstrado, não há teste automatizado de pagamento x402, ROBOTS_POLICY está configurado, mas inerte, e dois endereços de carteira de teste literais confirmados em apps/worker/wrangler.jsonc precisam ser substituídos antes de qualquer implantação. Veja Status de implementação.


1. O que o serviço faz

Um agente envia:

  • uma pergunta ou alegação, e
  • uma ou mais URLs públicas para usar como fontes.

O serviço então:

  1. valida a URL e rejeita qualquer coisa insegura (defesas SSRF),
  2. busca a página com timeouts limitados, redirecionamentos e tamanho de resposta,
  3. detecta o tipo de conteúdo e analisa o HTML,
  4. extrai metadados (título, descrição, URL canônica, Open Graph, JSON-LD, idioma, datas de publicação e modificação, cabeçalhos, contagem de palavras),
  5. normaliza o conteúdo principal e produz um hash de conteúdo SHA-256,
  6. extrai trechos curtos de evidência que correspondem à pergunta, com sua posição no documento,
  7. compara as fontes e chega a uma avaliação,
  8. retorna uma resposta estruturada com proveniência completa.

Ele não é um raspador da web, uma ferramenta de SEO, um rastreador genérico, um proxy, um serviço de automação de navegador ou um mecanismo de busca. É infraestrutura de evidências: a coisa que um agente chama quando precisa mostrar seu trabalho.

O que retorna

{
  "request_id": "req_3f9c1a7b2e4d4a6f8b0c1d2e",
  "version": "1",
  "question": "Is Rotamech Industries a manufacturer of centrifugal pumps?",
  "assessment": {
    "status": "supported",
    "basis": "1 source(s) contained passages matching the question (example.invalid) with no contradicting passages found."
  },
  "sources": [
    {
      "requested_url": "https://example.invalid/products",
      "final_url": "https://example.invalid/products",
      "status": 200,
      "content_type": "text/html; charset=utf-8",
      "title": "Rotamech Industries — Products",
      "canonical_url": "https://example.invalid/products",
      "description": "Rotamech Industries manufactures centrifugal pumps for industrial use.",
      "publisher": "Rotamech Industries",
      "language": "en",
      "published_at": "2024-03-01T09:00:00.000Z",
      "modified_at": null,
      "retrieved_at": "2026-09-20T21:16:07.412Z",
      "word_count": 63,
      "content_hash_sha256": "3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b",
      "evidence": [
        {
          "excerpt": "Rotamech Industries is a manufacturer of centrifugal pumps.",
          "context": "h2:Products > p[1]",
          "relevance": "direct"
        }
      ],
      "structured_data": { "json_ld": [], "open_graph": {} },
      "warnings": [],
      "from_cache": false,
      "redirect_chain": []
    }
  ],
  "limitations": [
    "Assessment is derived from deterministic lexical matching, not semantic reasoning. A configured reasoning provider may refine it, but never replaces source evidence."
  ],
  "processing_ms": 412
}

Cada campo é documentado em docs/api.md.


2. Por que um agente o usaria

Porque um agente que cita fontes é mais útil do que um que as afirma.

  • Fundamentação. Em vez de gerar uma frase plausível, o agente pode anexar uma URL real, um timestamp de recuperação, um hash de conteúdo e a passagem na qual a alegação se baseia.
  • Verificação. Um agente pode verificar o que uma página específica realmente diz, em vez de confiar em um resumo.
  • Comparação. Múltiplas fontes são comparadas, e a discordância é relatada como mixed em vez de ser diluída em uma média.
  • Honestidade por construção. Quando nada corresponde de perto o suficiente, a resposta é inconclusive. O serviço nunca inventa um fato, nunca finge que uma fonte diz algo que não diz e nunca emite uma pontuação de confiança.
  • Sem integração. Sem cadastro, sem chave, sem plano. Descubra a ferramenta, chame-a, pague por solicitação, obtenha evidências.

3. Exemplo de caso de uso

Um agente foi questionado: "A Rotamech Industries é realmente uma fabricante de bombas centrífugas, ou apenas um revendedor?"

O conhecimento do próprio modelo é desatualizado e não verificável, então ele reúne URLs candidatas e chama este serviço:

{
  "question": "Is Rotamech Industries a manufacturer of centrifugal pumps?",
  "urls": [
    "https://example.invalid/products",
    "https://example.invalid/about",
    "https://example.invalid/registry-record"
  ],
  "max_sources": 5,
  "language": "auto",
  "mode": "evidence"
}

O site da empresa apoia a alegação; a página do registro a nega. O serviço retorna:

{
  "assessment": {
    "status": "mixed",
    "basis": "Sources disagreed: 2 leaning to support (example.invalid) and 1 leaning against (example.invalid)."
  }
}

com trechos curtos citados de cada lado, seus timestamps de recuperação e seus hashes de conteúdo. O agente agora tem algo que não tinha antes: uma resposta defensável que nomeia ambos os lados e mostra de onde cada um veio, além de limitações honestas. Ele pode dizer ao humano "a empresa afirma isso; um registro contesta; aqui estão ambas as fontes", em vez de escolher um lado e parecer confiante.


4. Uso do MCP

Transporte: HTTP streamable. Endpoint: /mcp no mesmo host da API.

${MCP_PUBLIC_URL}          e.g. https://${PUBLIC_API_DOMAIN}/mcp

Ferramentas

FerramentaPagamentoPropósito
research_evidencepago (x402)Buscar fontes públicas e retornar evidências estruturadas e citadas.
healthgratuitoVerificação de status.

Exemplo de configuração do cliente

{
  "mcpServers": {
    "agent-evidence-api": {
      "type": "http",
      "url": "${MCP_PUBLIC_URL}",
      "headers": {
        "Accept": "application/json, text/event-stream"
      }
    }
  }
}

Não há nada para colocar em headers para autenticação. Não há chave.

initialize e tools/list são gratuitos

Isso importa para agentes autônomos, e é deliberado:

Método JSON-RPCPago?
initializegratuito
tools/listgratuito
tools/call → healthgratuito
tools/call → research_evidencepago
todo o restogratuito

Um agente deve ser capaz de descobrir as ferramentas antes de decidir pagar por uma. Apenas uma invocação real da ferramenta paga exige pagamento. Um lote JSON-RPC é cobrado se qualquer elemento for uma chamada paga.

Exemplo de chamada de ferramenta

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "research_evidence",
    "arguments": {
      "question": "Is Rotamech Industries a manufacturer of centrifugal pumps?",
      "urls": ["https://example.invalid/products"],
      "max_sources": 5,
      "language": "auto",
      "mode": "evidence"
    }
  }
}

Esquema de entrada da ferramenta (idêntico ao corpo da requisição HTTP):

CampoTipoObrigatórioObservações
questionstringsim1–2000 caracteres.
urlsstring[]nãoNo máximo 25 no esquema, 5 por padrão em tempo de execução.
max_sourcesintegernãoPositivo, ≤ 25.
languagestringnão"auto" ou uma tag BCP-47.
mode"evidence"nãoO único valor na v0.1.0.

Detalhes completos, incluindo como uma resposta de pagamento exigido se parece para um cliente MCP: docs/mcp.md.


5. Uso do HTTP

GET  /health       free   liveness
GET  /             free   capabilities
POST /v1/evidence  paid   the evidence resource

GET /health

curl -s https://${PUBLIC_API_DOMAIN}/health
{ "status": "ok", "service": "agent-evidence-api", "version": "0.1.0" }

GET /

Uma descrição de capacidade gratuita, útil para descoberta antes de pagar.

curl -s https://${PUBLIC_API_DOMAIN}/
{
  "service": "agent-evidence-api",
  "version": "0.1.0",
  "description": "Evidence infrastructure for AI agents. Returns structured, cited, freshly-retrieved evidence from public web pages so an agent can verify claims and ground answers in sources.",
  "endpoints": {
    "health": "GET /health (free)",
    "evidence": "POST /v1/evidence (paid, x402)",
    "mcp": "POST /mcp (MCP streamable HTTP; initialize and tools/list are free)"
  },
  "mcp": { "transport": "streamable-http", "tools": { "research_evidence": "paid", "health": "free" } },
  "payment": {
    "protocol": "x402",
    "scheme": "exact",
    "network": "eip155:84532",
    "asset": "USDC",
    "price_usd": "0.03",
    "recipient": "0x…",
    "facilitator": "https://x402.org/facilitator"
  }
}

POST /v1/evidence

POST /v1/evidence HTTP/1.1
Host: ${PUBLIC_API_DOMAIN}
Content-Type: application/json
payment-signature: <x402 payment proof>

{
  "question": "Is Rotamech Industries a manufacturer of centrifugal pumps?",
  "urls": ["https://example.invalid/products", "https://example.invalid/about"],
  "max_sources": 5,
  "language": "auto",
  "mode": "evidence"
}

Retorna o documento EvidenceResponse mostrado na §1.

Sem pagamento válido, você recebe HTTP 402 com um envelope de erro PAYMENT_REQUIRED e os requisitos de pagamento x402:

{
  "error": {
    "code": "PAYMENT_REQUIRED",
    "message": "Payment is required to access this resource.",
    "request_id": "req_5c4b3a291807f6e5d4c3b2a1"
  }
}

Erros

Toda falha usa um envelope. Os códigos são estáveis — use error.code para decidir.

{
  "error": {
    "code": "INVALID_URL",
    "message": "The supplied URL is invalid or unsupported.",
    "request_id": "req_3f9c1a7b2e4d4a6f8b0c1d2e"
  }
}
CódigoHTTP
INVALID_REQUEST400
INVALID_URL400
BLOCKED_URL400
SSRF_ATTEMPT400
PAYMENT_REQUIRED / PAYMENT_INVALID / PAYMENT_EXPIRED402
UNAUTHORIZED401
UNSUPPORTED_CONTENT415
RATE_LIMIT429
EXTRACTION_FAILURE / INTERNAL_ERROR500
TIMEOUT504
REDIRECT_LIMIT / RESPONSE_TOO_LARGE / UPSTREAM_HTTP_FAILURE / BACKEND_UNREACHABLE502
NOT_CONFIGURED503

Tabela completa com significados: docs/api.md §5.

Uma fonte que falha não falha a requisição

Se uma de cinco URLs estiver inacessível, você ainda recebe as outras quatro. A fonte que falhou aparece com status: null, evidence vazio e um aviso com o motivo:

{
  "requested_url": "https://example.invalid/gone",
  "status": null,
  "evidence": [],
  "warnings": [
    { "code": "UPSTREAM_HTTP_FAILURE", "message": "The source returned an error status." }
  ]
}

e limitations ganha: "1 de 2 fonte(s) não pôde ser recuperada; veja avisos por fonte."


6. O fluxo de pagamento x402

Agent
  │  1. POST /v1/evidence   (or tools/call research_evidence)
  ▼
Worker ──▶ 402 Payment Required + payment requirements
  │
Agent
  │  2. pays USDC on Base / Base Sepolia to the recipient address
  │  3. retries the same request with  payment-signature: <proof>
  ▼
Worker ──▶ 4. verifies via the x402 facilitator
  │           invalid → 402 PAYMENT_INVALID
  │           expired → 402 PAYMENT_EXPIRED
  ▼
Backend ──▶ 5. runs the evidence pipeline
  ▼
Worker ──▶ 6. 200 + EvidenceResponse
  • Sem chaves de API. Sem contas de usuário. Por design (SPEC §11, §38). Um agente nunca deve precisar se cadastrar, solicitar uma chave ou assinar.
  • O destinatário precisa apenas de um endereço público. Receber USDC não exige chave privada, porque o serviço nunca assina nada — o cliente pagante é quem assina.
  • Nunca comprometa uma chave privada. Não em wrangler.jsonc, não em .env, não em lugar nenhum. X402_TEST_PRIVATE_KEY é uma chave descartável da Base Sepolia para testes locais apenas, nunca deve conter fundos da mainnet e nunca deve ser comprometida.
  • O desvio de desenvolvimento é duplamente protegido. Localmente, DEV_BYPASS_PAYMENT=true pula o bloqueio — mas apenas quando a rede não é a Base mainnet. Em eip155:8453, o pagamento nunca pode ser ignorado, mesmo que a flag vaze para a configuração de produção.

Detalhe completo: docs/x402.md.


7. Base e Base Sepolia

AmbienteRedeIdentificador CAIP-2
TesteBase Sepoliaeip155:84532
ProduçãoBaseeip155:8453

O token de liquidação é USDC em ambos os casos.

As configurações de testnet e produção são mantidas em ambientes Worker separados e nunca devem ser misturadas. O padrão seguro em packages/core/src/config.ts é Base Sepolia, então uma implantação não configurada fica na testnet em vez de acidentalmente na mainnet.

apps/worker/wrangler.jsonc fornece três ambientes:

AmbienteAtivaçãoRedePagamento
produçãowrangler deployeip155:8453 (Base)obrigatório
devwrangler dev --env deveip155:84532 (Sepolia)ignorado
testewrangler dev --env testeip155:84532 (Sepolia)obrigatório

8. Configuração de preços

O preço é orientado por ambiente, nunca codificado.

VariávelPadrãoSignificado
X402_PRICE_USD0.003Preço por requisição de evidência, em USD.
X402_NETWORKeip155:84532Rede de liquidação.
X402_RECIPIENT(vazio)Endereço público de recebimento.
X402_FACILITATOR_URLhttps://x402.org/facilitatorFacilitador usado para verificação.

O padrão do MVP é aproximadamente US$ 0,03 por requisição de evidência. Esse é um ponto de partida, não um preço comercial fixo.

A string de preço é normalizada antes do uso: um $ inicial é opcional, e o valor é renderizado com duas casas decimais. Observe que um valor não analisável não interrompe o Worker — ele silenciosamente volta para $0.03. Verifique o valor após qualquer alteração.


9. Desenvolvimento local

Requer Node.js ≥ 22.6 (o cache usa o módulo integrado node:sqlite, então não há dependência nativa para compilar) e pnpm.

pnpm install

cp .env.example .env               # placeholders only; fill in locally, never commit
openssl rand -hex 32               # → BACKEND_AUTH_SECRET

pnpm typecheck
pnpm test
ScriptPropósito
pnpm typecheckVerificação de tipos de cada workspace a partir do código-fonte.
pnpm testTodos os arquivos *.test.ts.
pnpm test:securitySuíte de SSRF / validação de URL.
pnpm test:e2eFluxo de aceitação ponta a ponta.
pnpm fixturesServidor de fixtures local determinístico.
pnpm dev:backendBackend em :8080.
pnpm dev:workerWorker em :8787.
pnpm validatetypecheck && test.

O servidor de fixtures (tests/fixtures/server.ts) é offline e determinístico — sem dependência de sites ao vivo. Ele serve páginas de conteúdo, cadeias de redirecionamento, armadilhas de redirecionamento para privado e para metadados, uma rota que nunca responde, uma rota de streaming de 8 MiB e respostas 404/500, para que os controles de SSRF e limites possam ser exercitados contra um socket real.

pnpm fixtures
# [fixtures] listening on http://127.0.0.1:<port>

Ambos os comandos de desenvolvimento funcionam, com uma ressalva. pnpm dev:backend inicia o backend Fastify em :8080; pnpm dev:worker inicia o Worker. Apontar o Worker para o backend e chamar /v1/evidence também exige que a etapa x402 seja liquidada, ou DEV_BYPASS_PAYMENT=true com uma rede que não seja a mainnet. Veja Status da implementação.


10. Implantação

Cloudflare Worker (public edge)  →  protected origin  →  Docker container  →  Fastify backend  →  SQLite
  1. Backend no VPS. Um serviço Node.js + Fastify construído a partir de docker/ e executado com docker compose, com restart: unless-stopped e um volume persistente montado em /app/data para o cache SQLite.

  2. Cloudflare Worker. bash scripts/deploy-live.sh envia o ambiente de produção e se recusa a relatar sucesso a menos que o build saia limpo, o ID da versão realmente mude e o serviço ao vivo verifique de fora. (wrangler deploy sozinho canaliza mal: wrangler deploy | tail sai com 0 mesmo quando o build falha, o que escondeu uma implantação quebrada duas vezes.) (Base mainnet).

  3. O segredo compartilhado. BACKEND_AUTH_SECRET está deliberadamente ausente de wrangler.jsonc para que nunca possa ser comprometido:

    wrangler secret put BACKEND_AUTH_SECRET
    

    Ele deve corresponder ao próprio BACKEND_AUTH_SECRET do backend. Gere-o com openssl rand -hex 32.

  4. Proteção de origem — a opção preferida é um Cloudflare Tunnel, para que o backend não tenha listener público nem registro DNS público. A alternativa é uma origem autenticada atrás de um firewall restrito às faixas de saída da Cloudflare. Em ambos os casos, o segredo compartilhado é validado em cada requisição interna, porque a restrição de rede e a autenticação de requisição são camadas independentes.

Use placeholders — PUBLIC_API_DOMAIN, BACKEND_ORIGIN_URL, MCP_PUBLIC_URL — e nunca invente um domínio real.

Instruções completas, tabelas de variáveis de ambiente, verificações de saúde e a lista de verificação manual de credenciais: docs/deployment.md.

Implantável em princípio, ainda não implantado ou exercitado ponta a ponta. Os artefatos Docker, o backend e o Worker existem. Nada foi implantado a partir deste repositório, e dois defeitos de configuração devem ser corrigidos primeiro (veja Status da implementação). Veja docs/deployment.md.


11. Segurança

O buscador trata cada URL como entrada hostil. Defesas obrigatórias (SPEC §18), todas aplicadas no pacote @aee/fetcher:

  • Lista de permissão de esquemas — apenas http e https; file:// e todo o resto rejeitados.
  • Rejeição de endereços — localhost e seus aliases, loopback, IPv4 RFC1918/privado, link-local, multicast, não especificado, loopback IPv6, link-local IPv6, faixas IPv6 privadas e endpoints de metadados de nuvem (169.254.169.254 e amigos).
  • Evasão codificada — representações decimal, octal, hexadecimal, forma curta e IPv4-mapeado-para-IPv6 são verificadas por faixa após a análise, nunca correspondidas como strings.
  • DNS — resolva explicitamente, valide cada endereço resolvido e revalide no momento da conexão para fechar a janela de rebinding de DNS.
  • Redirecionamentos — valide cada salto, não apenas a primeira URL, e aplique MAX_REDIRECTS.
  • Portas — apenas lista de permissão.
  • Limites — timeout de conexão, timeout total de requisição, bytes máximos de resposta aplicados durante o streaming, defesa contra bombas de descompactação, limites de concorrência.
  • Nenhuma execução de shell de URLs, nunca. Sem child_process no caminho de busca.
  • Logs — JSON estruturado com redação de chaves secretas. Nunca registre segredos de pagamento ou de origem, chaves privadas ou segredos de carteira.

Separadamente, a proteção de origem garante que um chamador não possa pular o Worker e chamar o backend diretamente para evitar pagar: um Cloudflare Tunnel (preferido) ou uma origem com firewall, além de autenticação servidor a servidor em cada requisição interna. BACKEND_AUTH_SECRET não tem padrão justamente para que um backend mal configurado falhe fechado em vez de rodar sem autenticação.

E as regras de acesso da SPEC §19: sem ignorar controles de acesso, sem derrotar proteções anti-bot, sem automação de login, sem contornar paywalls, sem resolver CAPTCHA. Um User-Agent claramente identificável é usado, o comportamento de robots.txt é configurável via ROBOTS_POLICY, e apenas recursos publicamente acessíveis estão no escopo. Envie apenas URLs que você tem permissão para acessar.

Esses controles estão implementados em packages/fetcher e testados por unidade em tests/security/, que passa localmente (92 casos de segurança). Nenhuma auditoria independente foi realizada. ROBOTS_POLICY é aplicado. Veja docs/security.md para a tabela de status por controle, o que é aplicado onde, e a lista honesta de lacunas.


12. Limitações

Ditas claramente, porque você deve conhecê-las antes de confiar na saída.

LimitaçãoDetalhe
Apenas correspondência lexical determinísticaA avaliação vem da correspondência de termos mais uma lista fixa de pistas de negação. Não há compreensão semântica. Uma contradição parafraseada que não compartilha vocabulário não será detectada; uma passagem negada que compartilha muitos termos será.
Sem raciocínio semântico, a menos que um provedor seja configuradoO ponto de extensão ReasoningProvider na SPEC §37 existe no design e não está implementado. Mesmo quando estiver, ele pode decompor, classificar, comparar e sintetizar — mas nunca deve substituir evidências de origem por prosa sem suporte.
Apenas URLs fornecidas pelo agente na v0.1.0Você deve fornecer as URLs. Não há provedor de busca, então o serviço não pode descobrir fontes por você. urls é necessário na prática.
Excertos são curtos por designO MAX_EXCERPT_CHARS padrão é 600 (limite do esquema: 4000). Este é um serviço de evidências citadas, não um serviço de despejo de conteúdo, e não reproduz documentos inteiros.
inconclusive é comum e corretoSe a pergunta não compartilha termos significativos com o texto recuperado, a resposta honesta é inconclusive. Isso é o serviço funcionando, não falhando.
Tokens com menos de 3 caracteres são ignoradosEles são descartados dos termos da pergunta, então perguntas muito curtas ou apenas com siglas podem ter correspondência ruim.
Stemming é rudimentarUm ing/ed/es/s final é removido. Sem biblioteca de stemming, sem formas irregulares.
Stopwords são uma lista fixa em inglêsPerguntas não-inglesas perdem pouco (a lista é específica do inglês e majoritariamente inerte em outros idiomas), mas a qualidade da classificação para perguntas não-inglesas não é ajustada.
Sem evidências em PDF, imagem ou renderizadas por JavaScriptDocumentProvider e BrowserProvider são pontos de extensão futuros e não estão implementados. Apenas HTML estático.
Sem detecção de mudança de fonte ou pontuação de confiançaSourceTrustProvider não está implementado; o serviço relata o que uma página diz, não o quanto confiar no editor.
Acertos de cache são sinalizados, não ocultadosfrom_cache: true mais um aviso de SERVED_FROM_CACHE, e retrieved_at é sempre o tempo real de recuperação. Evidências com até CACHE_TTL_SECONDS (padrão 24 h) podem ser servidas.
Uma fonte ruim não falha a solicitaçãoFalhas são relatadas por fonte em warnings, e uma contagem de falhas é adicionada a limitations. Leia esses arrays.
Limitação de taxa é por processo de backendUm token bucket baseado em CF-Connecting-IP aplica RATE_LIMIT (429) com um mapa de bucket limitado. É em processo, então múltiplas réplicas de backend têm cada uma seu próprio orçamento; limitação no nível de borda exigiria Durable Objects.
Conteúdo não-HTML não é processadoUm tipo de conteúdo não suportado gera uma fonte com corpo null e um aviso UNSUPPORTED_CONTENT_TYPE em vez de um erro. HTML, texto simples, XML e JSON são os tipos processados.
Correspondência de robots é prefixo/curinga, não RFC 9309 completoROBOTS_POLICY=ignore|warn|enforce é aplicado, com um cache limitado por origem. Regras ambíguas resolvem para permitir e geram aviso em vez de recusa silenciosa. Um User-Agent claramente identificável é enviado em cada solicitação.
Nenhum pagamento on-chain demonstradoO gate x402 está implementado; um settlement financiado na Base Sepolia ou mainnet não foi executado contra uma implantação.
Nenhuma revisão de segurança independenteOs controles de SSRF estão implementados e testados por unidade no código-fonte; eles não foram auditados adversarialmente.

E, agora

Implementado e com verificação de tipos: todos os seis pacotes (schemas, core, fetcher, extraction, cache, mcp), ambos os apps (backend, worker), os artefatos Docker e server.json. pnpm typecheck passa em todo o workspace, e seis suítes de teste cobrem aproximadamente 147 casos, incluindo um teste de fluxo de ponta a ponta que aciona o backend real via HTTP contra o servidor de fixture.

Ainda em aberto:

LacunaDetalhe
Endereços de carteira de teste literaisapps/worker/wrangler.jsonc tem o mesmo endereço de destinatário literal em env.dev e env.test. Substitua por placeholders antes de implantar.
Correspondência de robots simplificadaROBOTS_POLICY é aplicado; a correspondência é prefixo/curinga em vez de RFC 9309 completo, e ambiguidade resolve para permitir.
Sem verificação de pagamento on-chainO gate x402 está implementado e revisado; nenhum settlement financiado na Base Sepolia ou mainnet foi executado.
Sem teste automatizado de pagamento x402A SPEC §26 pede um teste de 402 e um teste de pagamento válido em testnet. Nenhum existe.
Limitação de taxa em processoAplicada por réplica de backend, não globalmente na borda.
URL remota server.json é um placeholderO namespace está confirmado (io.github.Thx93/), mas remotes[].url deve ser substituído, e repository.url referencia um repositório que ainda não existe.
Nenhuma revisão de segurança independenteOs controles de SSRF estão implementados e testados por unidade no código-fonte; ninguém os auditou adversarialmente.

Verificado localmente: pnpm typecheck sai com código 0, pnpm test relata 199 testes passando, e tanto scripts/smoke.sh quanto scripts/worker-smoke.sh passam contra sockets ativos. Execute-os novamente e relate a saída real em vez de assumir uma aprovação — esses resultados são de uma única máquina.


13. Publicação no registro

A SPEC §28 exige que o projeto esteja pronto para registro, não publicado automaticamente. Isso significa:

  • um arquivo de metadados server.json usando o esquema oficial atual,
  • validação desse arquivo,
  • etapas exatas de publicação documentadas,
  • uma lista de verificação de propriedade de namespace e autenticação,
  • publicação manual com o fluxo de trabalho oficial mcp-publisher, e somente quando credenciais e autorização estiverem explicitamente disponíveis.

server.json agora existe e declara isso como um servidor remoto streamable-HTTP (sem entrada packages, porque não há pacote npm para instalar). Duas coisas permanecem antes de ser publicável:

  • remotes[].url ainda é https://mcp.example.invalid/mcp; substitua-o pelo seu MCP_PUBLIC_URL real.
  • name e repository.url afirmam um namespace do GitHub — confirme se são genuinamente seus, porque a propriedade do namespace é validada e um identificador fabricado falha.

Nada foi publicado. O procedimento exato de publicação, etapas de validação e lista de verificação de namespace estão em docs/registry-publication.md.

A estratégia de descoberta — o Registro MCP, o repositório GitHub, metadados npm quando apropriado, metadados legíveis por máquina, documentação e descrições de ferramentas orientadas a agentes — está em docs/discovery.md. Ela também lista as frases descritivas verdadeiras que valem a pena usar (evidência web, verificação de fonte, verificação de alegação, extração de evidência, pesquisa fundamentada em fontes, comparar fontes, evidência citada, evidência web fresca) e afirma claramente que as descrições devem ser verdadeiras e não devem ser recheadas de palavras-chave.

Não publique até que o serviço realmente funcione. Uma entrada de registro listando uma ferramenta que não pode ser chamada é pior do que nenhuma entrada. Dois bloqueadores concretos permanecem: o placeholder remotes[].url deve ser substituído por um endpoint ativo, e o namespace name/repository.url deve ser confirmado como genuinamente seu.


Estrutura do projeto

agent-evidence-api/
├── AGENTS.md            # sole project rules file
├── SPEC.md              # product specification (authority on requirements)
├── README.md
├── server.json          # MCP Registry metadata (remote streamable-HTTP server)
├── .env.example         # environment template, placeholders only
├── pnpm-workspace.yaml
├── package.json
├── docs/
│   ├── architecture.md          # architecture, pipeline, layering rule
│   ├── api.md                   # HTTP endpoints, exact schemas, error codes, limits
│   ├── mcp.md                   # MCP transport, tools, free vs paid, client config
│   ├── x402.md                  # payment flow and configuration
│   ├── security.md              # SSRF controls, origin protection, secrets
│   ├── deployment.md            # local, Docker, Worker, origin protection
│   ├── discovery.md             # agent discoverability strategy
│   └── registry-publication.md  # exact MCP Registry publish steps
├── apps/
│   ├── backend/         # Fastify service — the VPS workload
│   │   └── src/         # app.ts, auth.ts, server.ts
│   └── worker/          # Cloudflare Worker — the public edge
│       ├── src/index.ts
│       ├── wrangler.jsonc
│       └── .dev.vars.example
├── packages/
│   ├── schemas/         # zod schemas + types (the shared wire contract)
│   ├── core/            # EvidenceService, config, logger, assessment
│   ├── fetcher/         # SSRF-hardened HTTP fetching (ip.ts, fetch.ts)
│   ├── extraction/      # HTML parsing, metadata, main content, lexical ranking
│   ├── cache/           # SQLite-backed bounded cache (node:sqlite)
│   └── mcp/             # MCP server + tool definitions (streamable HTTP)
├── tests/
│   ├── fixtures/        # deterministic local fixture server
│   ├── security/        # ssrf.test.ts, limits.test.ts
│   └── e2e/             # evidence-flow.test.ts (cross-package)
├── scripts/
│   ├── run-tests.mjs    # test runner (node --test + tsx)
│   └── smoke.sh         # live socket smoke test against the built backend
├── .dockerignore
└── docker/
    ├── Dockerfile
    ├── docker-compose.yml
    ├── env.production.example    # Base mainnet
    └── env.development.example   # Base Sepolia

Tanto o adaptador HTTP quanto o adaptador MCP chamam o mesmo EvidenceService — não há lógica de negócios duplicada entre eles (SPEC §39):

HTTP adapter ─────┐
                  ├──> EvidenceService ──> Fetch / Extract / Cache
MCP adapter ──────┘

x402 fica no limite de pagamento no Worker, nunca dentro do mecanismo principal.


Status da implementação

Instantâneo tirado enquanto escrevia a documentação.

Implementado

  • packages/schemas — o contrato de fio completo (solicitações, respostas, fontes, itens de evidência, avisos, erros, limites) com saída construída.
  • packages/fetcher — recuperação endurecida contra SSRF: allowlist de esquemas, classificação de faixas IPv4/IPv6 (incluindo formas decimal/octal/hex/127.1 e IPv6 mapeado por IPv4), regras de hostname, allowlist de portas, validação de IP resolvido em todos os registros DNS, validação de redirecionamento por salto, revalidação na conexão contra rebinding de DNS, timeouts de conexão e total, limite de bytes em streaming e descompressão manual.
  • packages/extraction — parsing de HTML, metadados, extração de conteúdo principal, normalização, hash de conteúdo, classificação lexical determinística, pistas de negação.
  • packages/cache — normalização de chaves, CacheProvider, adaptador SQLite limitado.
  • packages/core — configuração, logger estruturado com redação de segredos, avaliação entre fontes, EvidenceService, ServiceError tipado.
  • packages/mcp — o adaptador MCP remoto: HTTP streamable no modo stateless (sessionIdGenerator: undefined, enableJsonResponse: true), um novo par Server + transporte por solicitação HTTP, tools/list e tools/call delegando para o mesmo EvidenceService que a camada HTTP usa. Esquemas de entrada de ferramentas são gerados a partir de zod via z.toJSONSchema.
  • apps/backend — serviço Fastify: inicialização com falha fechada em segredo ausente, verificação de segredo compartilhado em tempo constante em tudo, exceto /health, GET /health, POST /internal/v1/evidence e POST/GET/DELETE em /mcp.
  • apps/worker — a borda completa: gate x402, /health e / gratuitos, encaminhamento POST /v1/evidence, inspeção e encaminhamento de corpo MCP, bypass de desenvolvimento protegido, envelope de erro canônico.
  • docker/ — Dockerfile multi-estágio, docker-compose.yml, modelos de ambiente separados para mainnet/testnet, além de um .dockerignore raiz.
  • server.json, apps/worker/.dev.vars.example, scripts/smoke.sh.

Verificado neste ambiente

  • pnpm typecheck — passa em todo o workspace (tsc --noEmit, código de saída 0).
  • Seis suítes de teste existem totalizando ~147 casos: tests/security/ssrf.test.ts (30), tests/security/limits.test.ts (16), tests/e2e/evidence-flow.test.ts (18), packages/mcp/src/mcp.test.ts (15), packages/extraction/src/extraction.test.ts (46), packages/cache/src/cache.test.ts (22).

Verificado localmente, não reproduzido de forma independente

  • pnpm typecheck → código de saída 0; pnpm test → 199 passando; scripts/smoke.sh e scripts/worker-smoke.sh → todas as verificações passaram. Nenhum terceiro reproduziu esses resultados.
  • Nenhum pagamento x402 on-chain foi demonstrado (o gate 402 está verificado; o caminho de settlement precisa de uma carteira de testnet financiada).

Defeitos em aberto

DefeitoDetalhe
Endereços de carteira de teste literaisapps/worker/wrangler.jsonc contém o mesmo endereço de destinatário literal em env.dev e env.test. A SPEC §33 e AGENTS.md §6 proíbem commitar configuração de carteira.
Correspondência de robots simplificadaROBOTS_POLICY é aplicado em EvidenceService; a correspondência é prefixo/curinga, não RFC 9309 completo.
— (corrigido)UNSUPPORTED_CONTENT (415) agora é emitido por fonte.
Sem teste de settlement on-chainO gate 402 e a divisão MCP gratuito/pago são cobertos por scripts/worker-smoke.sh; a limitação de taxa é testada por unidade e integração. O settlement real de USDC precisa de uma carteira financiada na Base Sepolia, que é uma credencial externa.
server.json ainda não publicávelO namespace está confirmado, mas remotes[].url é um placeholder e o repositório referenciado não existe.
Allowlist de portas inclui 8080/8443Conveniente para ferramentas, mas também portas comuns de interfaces internas. Restrinja se desnecessário.

Documentação

DocumentoConteúdo
docs/architecture.mdMapa de componentes, pipeline de requisições, divisão edge/backend, fronteira de autenticação, regra de camadas, propriedade de pacotes, pontos de extensão.
docs/api.mdGET /health, GET /, POST /v1/evidence; esquemas exatos de requisição e resposta; status de avaliação; exemplos práticos; todos os códigos de erro; limites de recursos e suas variáveis de ambiente.
docs/mcp.mdTransporte HTTP streamable, /mcp, ambas as ferramentas, esquema de entrada exato, descoberta gratuita vs paga, configuração do cliente, exemplo de chamada, resposta de pagamento obrigatório.
docs/x402.mdA sequência 402 → pagar → tentar novamente → verificar → executar, variáveis de configuração, IDs de rede CAIP-2, liquidação USDC, separação teste/produção, o bypass de desenvolvimento e as regras de chave privada.
docs/security.mdO conjunto de controles SSRF exigido pela SPEC §18, proteção de origem, o esquema de segredo compartilhado, tratamento de segredos, comportamento de robots/acesso e o que é aplicado onde.
docs/deployment.mdDesenvolvimento local, Docker no VPS, o Cloudflare Worker, wrangler secret put BACKEND_AUTH_SECRET, verificações de saúde, política de reinício, o volume SQLite e opções de proteção de origem.
docs/discovery.mdRegistro, repositório, npm, metadados legíveis por máquina, documentação e descrições de ferramentas orientadas a agentes.
docs/registry-publication.mdAs etapas exatas de publicação no MCP Registry, validação e a lista de verificação de propriedade de namespace.

Regras de contribuição

AGENTS.md é o único livro de regras do projeto. Ele define as restrições rígidas, as regras de segurança, os padrões de codificação, o nível de teste e a definição de pronto. Não crie CLAUDE.md, .cursorrules, GEMINI.md ou qualquer arquivo de instruções concorrente.

Os requisitos de produto estão em SPEC.md. Onde este README e a especificação discordarem, a especificação é autoritativa — e qualquer contradição entre o código-fonte e a especificação deve ser relatada em vez de resolvida silenciosamente.

Licença

MIT. Consulte package.json.