Servidor MCP
Servidor MCP
Use o FourA a partir de qualquer cliente Model Context Protocol (Claude Desktop, Claude Code, Cursor, Windsurf, VS Code) como quatro ferramentas nativas e seis prompts de fluxo de trabalho. Sem código de integração, sem cliente HTTP personalizado.
Código aberto no GitHub; no npm como @fouradata/mcp. Versão atual: 0.7.3.
Início rápido: stdio local (recomendado para Claude Desktop)
Obtenha uma chave em foura.ai/dashboard#api-keys (um clique, exibida uma única vez na criação, formato pk_live_...). Insira isto na configuração do seu cliente MCP:
{
"mcpServers": {
"foura": {
"command": "npx",
"args": ["-y", "@fouradata/mcp"],
"env": { "FOURA_API_KEY": "pk_live_..." }
}
}
}
Atenção no Claude Desktop: feche totalmente o Claude Desktop (
Cmd+Qno macOS) antes de editar o arquivo de configuração. Se o aplicativo ainda estiver em execução, ele sobrescreverá suas alterações com a configuração da memória ao fechar.
O comando npx baixa o @fouradata/mcp na primeira inicialização e o executa como um subprocesso do seu cliente MCP. Não é necessária instalação global.
| Cliente | Onde fica o arquivo de configuração |
|---|---|
| Claude Desktop (macOS) | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Claude Desktop (Windows) | %APPDATA%\Claude\claude_desktop_config.json |
| Claude Code | claude mcp add foura -- npx -y @fouradata/mcp (defina FOURA_API_KEY no env primeiro) |
| Cursor | ~/.cursor/mcp.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| VS Code (extensão MCP) | .vscode/mcp.json |
Reinicie o cliente. As ferramentas (foura_auto, foura_single, foura_proxy, foura_browser) e seis prompts aparecerão na sua lista de ferramentas.
Início rápido: hospedado (Streamable HTTP)
Para clientes com suporte ao transporte Streamable HTTP (Cursor, Windsurf, VS Code, Claude Code com --transport http), aponte para o endpoint hospedado em vez de executar um subprocesso local:
{
"mcpServers": {
"foura": {
"url": "https://mcp.foura.ai/mcp",
"headers": {
"Authorization": "Bearer pk_live_..."
}
}
}
}
Para o Claude Desktop, use a configuração de stdio acima ou faça o bridge do endpoint hospedado por meio do mcp-remote:
{
"mcpServers": {
"foura": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.foura.ai/mcp", "--header", "Authorization: Bearer pk_live_..."]
}
}
}
Referência do endpoint hospedado
| Propriedade | Valor |
|---|---|
| URL | https://mcp.foura.ai/mcp |
| Transporte | HTTP com suporte a streaming (POST /mcp, respostas SSE) |
| Autenticação | Authorization: Bearer pk_live_... por request |
| MCP-Protocol-Version | Conforme @modelcontextprotocol/sdk (atualmente 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07) |
| Desafio 401 | WWW-Authenticate: Bearer realm="foura-mcp" |
O desafio 401 não inclui o parâmetro RFC 9728 resource_metadata, intencionalmente. Informar um faz com que um cliente compatível com OAuth inicie um fluxo que este servidor não implementa. Envie sua chave pk_live_ como um token Bearer e o 401 desaparece.
O servidor hospedado é stateless. Cada request traz sua própria chave, que o servidor encaminha para a API FourA como X-API-Key. Uma única chave libera todas as quatro ferramentas.
Para proteção contra DNS-rebinding (CVE-2025-66414), o servidor valida o header Host (deve ser mcp.foura.ai ou localhost) e o header Origin quando presente (na lista de permissões: mcp.foura.ai, claude.ai, app.cursor.sh, app.cursor.com). Chamadores server-to-server (curl, clientes MCP em modo ponte stdio) não enviam Origin e passam diretamente.
Ferramentas
Todas as quatro ferramentas são anotadas com readOnlyHint: true e openWorldHint: true de acordo com a especificação MCP 2025-06-18. Clientes que aprovam automaticamente ferramentas confiáveis de somente leitura as executam sem uma janela modal de confirmação a cada request.
foura_auto é o padrão inteligente: forneça uma URL e ele retorna o conteúdo, escolhendo o método de busca por você. As outras três são as primitivas de nível mais baixo que ele orquestra; utilize-as quando quiser controle explícito.
foura_auto
Forneça uma URL quando você quiser que a FourA escolha o método de request. Ela faz tentativas limitadas entre os caminhos disponíveis de HTTP, proxy e navegador. Passe validate em alvos protegidos para que a response precise conter conteúdo que identifique a página real. Se nenhuma tentativa atender à validação, a ferramenta retorna um erro em vez de apresentar uma página de desafio como sucesso.
A response inclui detalhes de conclusão em meta e, por padrão, uma session reutilizável com proxy, cookies e userAgent. Para uma requisição de acompanhamento simples, chame foura_single com session.proxy como proxy, serialize os cookies como um header Cookie e envie session.userAgent como o header User-Agent. Para renderização em JavaScript, passe os valores da sessão para os campos correspondentes de foura_browser.
foura_single
Um request HTTP, retorno da response. Espelha POST /api/single/ de forma direta.
Use para páginas estáticas, APIs JSON, HTML renderizado no servidor.
Escolhendo qual navegador você apresenta
Um request apresenta o Google Chrome mais recente por padrão. Quando um destino aceita um navegador e recusa outro, defina browser (Chrome, Edge, Safari, Firefox ou Tor), os (Windows, macOS, Android ou iOS), ou version, ou passe um id profile exato:
{
"method": "GET",
"url": "https://example.com",
"browser": "Firefox",
"os": "Windows"
}
A versão mais recente tem prioridade quando vários perfis correspondem. Uma combinação que não existe retorna um erro listando o que está disponível, para que uma request nunca seja enviada como um navegador que você não escolheu. A seleção precisa de unblocker, que fica ativado por padrão. O catálogo é publicado em GET /api/profiles e não requer chave de API.
Os mesmos quatro campos ficam dentro do objeto request de foura_proxy.
foura_proxy
Encaminhe uma request HTTP por meio de proxies rotativos com repetição automática. Use-o quando foura_single estiver bloqueado ou o destino exigir um país de saída específico.
Defina exitCountries com uma allowlist restrita de códigos de país de duas letras visíveis ao destino, fornecidos pelo usuário ou pelos requisitos do destino:
{
"maxTries": 5,
"exitCountries": ["CZ", "GB"],
"request": {
"method": "GET",
"url": "https://example.com/pricing",
"browser": "Chrome",
"os": "Windows"
}
}
Os valores são normalizados (espaços removidos), convertidos para maiúsculas e deduplicados. Proxies com saídas desconhecidas são excluídos, e a request nunca faz fallback para um país não solicitado. A seleção usa os metadados de país visíveis ao destino mais recentes disponíveis, normalmente atualizados em até dez minutos; não se trata de uma consulta de geolocalização em tempo real durante a request. Não deduza o país de atendimento a partir do endereço de host do proxy.
Um sucesso com escopo retorna exitCountry e o ID reutilizável proxy. Verifique se exitCountry pertence à allowlist solicitada. Se o pool atual não tiver correspondências, a ferramenta retornará code: "no_eligible_proxy" com o escopo normalizado em details.exitCountries. Mantenha esse escopo e tente novamente mais tarde. Altere ou amplie o escopo apenas quando o usuário alterar explicitamente o requisito. O escopo por país está incluído a partir do plano Startup. Em um plano sem esse recurso, uma chamada que enviar exitCountries será recusada com 403 e X-FourA-Limit: plan_limit_feature.
Se a página selecionada precisar de JavaScript posteriormente, passe o ID proxy retornado para foura_browser.proxy para que o navegador reutilize a mesma saída.
Defina exitClass: "premium" para um destino que o pool padrão não consegue alcançar, independentemente de quantas saídas sejam tentadas. Trata-se de uma permissão, não de uma instrução: o pool padrão ainda disputa para obter a resposta e geralmente vence, e uma request respondida por ele antes que qualquer saída premium seja tentada não consome tráfego premium. Uma tentativa premium contabiliza o tráfego transportado mesmo quando falha. A response informa exitClass de volta, premium ou standard, para que você possa ver por request qual classe atendeu você. standard também é a resposta quando o tráfego premium incluído no seu plano se esgota, sendo um resultado normal e não um erro. exitClass: "standard" proíbe o escalonamento diretamente. exitClass: "premium" em um plano sem saídas premium é recusado com code: "plan_limit_premium". Consulte exitClass.
Quando a rotação precisou mudar para outra família de navegadores para obter uma resposta, uma response bem-sucedida trará profile com a família definida. Repita a chamada com ela, caso contrário a próxima chamada repetirá a versão que falhou.
Uma rotação com falha traz attemptReport ao lado do erro: uma frase em summary, além de contagens que separam saídas que nunca responderam (noResponse), saídas que uma verificação de bot recusou (defense, com os fornecedores em vendors), páginas que chegaram e foram rejeitadas apenas pelo seu próprio validate.data (contentRejected), statusRejected e other. profilesTried lista os navegadores que a tarefa enviou, em ordem de primeiro uso, com default significando que a request foi enviada exatamente como escrita. Um valor alto de contentRejected significa que a FourA entregou páginas reais e sua própria regra as descartou. Consulte Why a Proxy Request Ran Out of Tries.
foura_browser
Sessão completa de navegador. O JavaScript é executado, o DOM é renderizado, os cookies são retornados. Espelha POST /api/browser/.
Use para single-page applications, conteúdo carregado sob demanda (lazy loading) ou páginas com uma verificação que exige um navegador real para ser concluída.
Para formatos de entrada, padrões e regras de validação em cada ferramenta, consulte a referência de endpoints REST. Os esquemas das ferramentas correspondem campo a campo à API REST, além do opt-in offload_large exclusivo do MCP (veja abaixo).
Quando um alvo executa uma verificação de bot
foura_single e foura_proxy retornam defense quando o alvo executou uma verificação de bot a caminho do body. defense.solved: true significa que a verificação foi aprovada e data é a página real; false significa que o body pode ser uma página de desafio. Tente novamente com um navegador, sistema operacional ou versão diferente, ou mude para foura_proxy ou foura_browser, em vez de tratar a página de desafio como conteúdo.
Respostas tipadas
Cada resposta de ferramenta inclui content (resumo de texto legível por humanos) e structuredContent (JSON tipado e validado em relação ao outputSchema da ferramenta). Cada ferramenta tem seu próprio formato exclusivo:
foura_auto:{ status, headers, data }em formato único maismeta({ rung, solved, attempts, credits }, sempre presente, onderungé um decache,probe,proxy,browser,warmup,fail) e, por padrão,session({ proxy, cookies, userAgent }) para repetição por meio das ferramentas de nível inferior. Semtotal_time.foura_single:{ status, headers, data, total_time, ... }(headers é um array, uma entrada por salto de redirecionamento)foura_proxy: igual ao single mais{ proxy, total }; um sucesso com escopo definido também incluiexitCountry, uma solicitação que especificou uma classe incluiexitClass, uma rotação que alterou a família do navegador incluiprofilee uma falha incluiattemptReportfoura_browser: formato distinto{ status, headers: object, body, cookies, userAgent }(observação:bodypode ser uma string ou um objeto dependendo do content-type)
Cada ferramenta também informa o custo da chamada e como rastreá-la, lidos dos headers de resposta da API:
credits, créditos gastos nesta chamada. Presente também em falhas, pois o trabalho foi executado de qualquer forma. Você é cobrado apenas por chamadas bem-sucedidas; portanto, uma falha mostra seus créditos aqui, mas não custa nada a você.request_id, identificador da FourA para a chamada. Mencione-o em uma solicitação de suporte.exitClass,premiumquando uma saída premium atendeu à chamada. Nofoura_singleefoura_browser, isso acontece quando oproxyrepete uma saída encontrada pelofoura_proxy.
Cada um é omitido quando a API não reporta nada, portanto, um cliente desenvolvido para uma versão anterior continua funcionando sem alterações. Os mesmos valores estão documentados em Response Headers.
Clientes que suportam structuredContent podem passar o objeto tipado diretamente para o LLM em vez de exigir que ele analise o JSON a partir de texto puro.
Headers de resposta com múltiplos valores
Headers que aparecem várias vezes (Set-Cookie, Link, WWW-Authenticate) retornam como arrays:
{
"headers": [
{
"result": { "version": "HTTP/2", "code": 200, "reason": "" },
"content-type": "text/html",
"set-cookie": ["a=1; Path=/", "b=2; Path=/"]
}
]
}
Isso é importante para sites que definem cookies de sessão + rastreamento + consentimento em uma única response (a maior parte do e-commerce).
Large responses: offload_large (default: inline)
Por padrão (desde a v0.2.0), os corpos completos de response são retornados inline em structuredContent independentemente do tamanho. Isso funciona em qualquer cliente MCP nativamente.
Se o seu cliente suporta MCP resources/read E você deseja economizar tokens em páginas grandes, passe offload_large: true por chamada de ferramenta. Responses >= 50 KB são então gravadas em disco, retornadas como um resource_link, e seu cliente busca o body apenas quando realmente precisa dele. No servidor hospedado, payloads em cache expiram após 1 hora. Em sua própria instância nada exclui os payloads armazenados: limpe você mesmo os arquivos com mais de uma hora do diretório de payloads.
{
"method": "GET",
"url": "https://en.wikipedia.org/wiki/Web_scraping",
"offload_large": true
}
| Cliente | offload_large: true |
|---|---|
| Claude Desktop | ainda não, mantenha o padrão false |
| Claude Code, Cursor, Windsurf | suportado |
| Extensão MCP do VS Code | suportado |
Isolamento por tenant: cada chave de API obtém seu próprio namespace (sha256(apiKey)[:16]). Apenas a chave que armazenou um payload pode lê-lo de volta. Leituras entre tenants retornam Payload not found sem vazamento de existência.
Prompts integrados
Seis templates de fluxo de trabalho aparecem sob /prompts em qualquer cliente MCP. Cada um aceita argumentos nomeados e retorna uma mensagem de usuário com template orquestrando uma ou mais ferramentas.
| Prompt | Argumentos | O que faz |
|---|---|---|
smart_fetch |
url, opcional must_contain, extract |
Auto fetch (escolhe o método, lida com proteção contra bots), depois retorna ou extrai o conteúdo |
scrape_product_page |
url |
Browser fetch, depois extrai título do produto, preço, imagem, estoque, SKU como JSON |
extract_article |
url |
Single com fallback para proxy, depois remove navegação/anúncios e retorna JSON limpo do artigo |
monitor_pricing |
url, opcional target_price |
Proxy fetch, extrai o preço atual, compara com o valor alvo |
check_endpoint_health |
url, opcional expected_text |
Single com validação estrita, retorna acessibilidade e tempo de resposta |
bulk_fetch_urls |
urls (separados por vírgula) |
Single paralelo, fallback automático para proxy por URL, retorna apenas metadados |
Os prompts custam zero tokens em repouso. Apenas prompts invocados entram no contexto do LLM.
Texto completo com prompts manuais de fallback: MCP Recipes.
Envelope de erro
Todo erro (isError: true) carrega um envelope structuredContent. Campos mínimos em cada erro:
{
"service": "auto | single | proxy | browser",
"code": "rate_limited",
"error": "Rate limit exceeded"
}
Em erros de upstream com status HTTP, status também está presente. Em erros de rate limit e capacidade, o envelope upstream adiciona retryAfter, current.{concurrency, rpm} e limits.{maxConcurrency, maxRpm}. Consulte API Errors para o formato REST subjacente.
Valores estáveis de code:
| Código | HTTP | Significado | Seguro tentar novamente? |
|---|---|---|---|
ssrf_blocked |
n/a | O destino é um endereço privado ou reservado (RFC 5735, 6598, IPv6 reservado), a URL não é http(s) ou o hostname não resolveu | Não, verifique a URL. Uma resolução que falhou brevemente pode ser tentada novamente |
upstream_non_json |
varia | O upstream retornou um body malformado | Talvez, investigue |
output_validation_failed |
n/a | O outputSchema do servidor MCP rejeitou a resposta do upstream, ou a ferramenta não conseguiu concluir a chamada (nenhuma chave de API configurada, API inacessível) |
Talvez: verifique a configuração e depois relate |
bad_request |
400 | Formato de entrada rejeitado | Não, corrija os argumentos |
auth_failed |
401 | Chave ausente, inválida ou desativada | Não, corrija a chave |
forbidden |
403 | O destino respondeu 403 e seu validate rejeitou isso (uma verificação do site, uma restrição de país) |
Não, ou mude para foura_proxy |
not_found |
404 | Destino ou endpoint ausente | Não |
rate_limited |
429 | Limite de RPM atingido | Sim, aguarde retryAfter |
at_capacity |
503 | Limite de concorrência atingido | Sim, aguarde retryAfter |
service_disabled |
503 | O serviço está desligado para manutenção. Uma ferramenta que seu plano não inclui retorna como plan_limit_feature |
Entre em contato com o suporte |
service_unavailable |
503 | 503 genérico | Sim, backoff curto |
upstream_error |
500+ ou 0 | O destino respondeu com um erro de servidor, ou em foura_proxy, foura_browser e foura_auto nunca responderam |
Sim, backoff exponencial |
upstream_client_error |
4xx | Outro 4xx | Geralmente não |
upstream_unknown |
outro | A requisição foi executada mas não produziu uma resposta aceita: em foura_single o destino nunca respondeu (timeout, conexão recusada), e em qualquer ferramenta seu validate rejeitou uma resposta 2xx ou 3xx. Leia status e error |
Investigue |
no_eligible_proxy |
n/a | Nenhum proxy corresponde ao escopo estrito de exitCountries |
Tente novamente mais tarde; altere o escopo apenas explicitamente |
plan_limit_* |
403 ou 429 | Um dos limites do seu plano recusou a chamada: plan_limit_ seguido por feature, premium, concurrency, rate, browser_daily, credits ou bandwidth. Consulte MCP Server Errors |
Aguarde retryAfter quando presente; caso contrário, não tente até que o limite seja redefinido ou o plano seja alterado |
Agentes de LLM podem ler code diretamente para lógica de repetição sem analisar texto. Passo a passo de autenticação: Authentication.
Limites
- Corpo inline por padrão. Com
offload_large: true, respostas >= 50 KB vão para o disco +resource_link(por tenant, TTL de 1 hora). - Destinos privados são recusados (RFC 5735, RFC 6598, blocos reservados IPv6) na camada MCP. Apenas hosts públicos são encaminhados.
- Limite de corpo de requisição de 256 KB em requisições
/mcpde entrada (payloads reais de MCP são < 4 KB). - Rate limits são aplicados pela FourA API por serviço. Consulte Rate Limits.
Auto-hospedagem
O código-fonte completo do servidor é público no GitHub sob @fouradata/mcp. Clone o repositório, execute npm install, npm run build e rode node dist/http.js para subir sua própria instância. Opera sem estado em um único container atrás de qualquer balanceador de carga.
Ambiente configurável:
| Variável | Padrão | Finalidade |
|---|---|---|
PORT |
3076 |
Porta de escuta HTTP |
FOURA_API_BASE |
https://api.foura.ai/api |
URL base REST upstream da FourA |
FOURA_MCP_PAYLOADS_DIR |
uma pasta foura-mcp-payloads no diretório temporário do sistema (o arquivo Docker Compose incluído define /data/payloads) |
Onde respostas >= 50 KB são armazenadas em cache no disco (com offload_large: true) |
FOURA_MCP_ALLOWED_HOSTS |
mcp.foura.ai,localhost,127.0.0.1,[::1] |
Lista de permissões de hostname para o cabeçalho Host (defesa contra DNS rebinding) |
FOURA_MCP_ALLOWED_ORIGINS |
https://mcp.foura.ai,https://claude.ai,https://app.cursor.sh,https://app.cursor.com |
Lista de permissões de Origin para chamadores via navegador |
O container oficial roda como uid 1001 (não root). O bind mount de host /data/payloads deve ter permissão de escrita para esse UID.
Escale horizontalmente atrás de qualquer balanceador de carga. Os clientes fornecem suas chaves em cada requisição, portanto não há necessidade de sessão persistente.