Mais cedo ou mais tarde alguém solta a foto de um passaporte no chat com um assistente e pede para ele "só preencher o formulário". Um modelo de visão de uso geral vai tentar. Pode até acertar o nome. O que ele não vai fazer é dizer se os dígitos verificadores da zona de leitura mecânica (MRZ) bateram, devolver as datas sempre no mesmo formato ou dizer "não consegui ler isto" em vez de chutar.
Essa lacuna é um bom caso para uma ferramenta. O Model Context Protocol permite que um agente chame uma, e este post mostra como dar ao Claude Desktop, ao Claude Code, ao Cursor e a outros clientes uma ferramenta de reconhecimento de documentos, o que o agente recebe de volta, como manter o custo sob controle e no que pensar antes de apontar um agente para documentos de identidade.
Este é o blog do doc.cheap, a API por trás do servidor MCP usado aqui. O servidor tem licença MIT, e as questões de configuração valem para qualquer ferramenta desse tipo.
O que o agente recebe
O servidor é o @doc-cheap/mcp no npm (MIT, Node 20 ou superior), e ele expõe três ferramentas:
| Ferramenta | O que faz | Gasta crédito? |
|---|---|---|
scan_document |
Reconhece um passaporte, carteira de identidade ou carteira de motorista a partir de uma foto ou digitalização e devolve o resultado estruturado | Sim, só quando um documento é reconhecido |
check_balance |
Lê os créditos restantes e os contadores deste mês | Não (somente leitura) |
search_docs |
Pesquisa a documentação da API que vem junto com o servidor, offline | Não (somente leitura) |
Cada ferramenta traz um título, uma descrição (as duas que mexem no estado da conta informam o preço) e as dicas de comportamento do MCP que um cliente lê antes de decidir se pergunta a você primeiro: scan_document é marcada como não somente leitura, e as outras duas como somente leitura. O servidor também envia instruções que o modelo lê antes de qualquer chamada, dizendo o que ele reconhece e quanto custa uma chamada. Além das ferramentas há quatro prompts (scan_document_to_json, check_document_expiry, batch_scan, explain_error), e cada página da documentação é exposta como um recurso somente leitura, por exemplo doccheap://docs/reference/fields.
scan_document responde com o resultado completo em JSON estruturado mais um resumo de uma linha, por exemplo:
Scan 01a0af18-cd8d-7a61-9f2d-4c7b8e105da3: recognized · passport (GRC) · PARADEIGMA ELENI SOFIA · billed · 684 ms
(Um titular de espécime inventado da documentação.) O JSON por trás traz o titular, o número do documento e as datas em ISO 8601, cada campo com uma faixa de confiança, as linhas da MRZ com um veredito passed / failed / absent, e um flag billed. Essa estrutura é o ponto: o agente não precisa interpretar pixels, ele lê campos.
Instalação: o servidor local
Todos os clientes abaixo iniciam o servidor com npx. Sem chave configurada, ele usa a chave pública de sandbox, que dá 10 documentos reconhecidos grátis por endereço IP no total e no máximo 10 requisições por hora. É o suficiente para testar. O cadastro dá 20 créditos grátis; depois disso, um documento reconhecido custa $0.01.
Claude Desktop, Cursor e Windsurf leem o mesmo bloco, em claude_desktop_config.json, ~/.cursor/mcp.json e ~/.codeium/windsurf/mcp_config.json, respectivamente:
{
"mcpServers": {
"doc-cheap": {
"command": "npx",
"args": ["-y", "@doc-cheap/mcp"],
"env": { "DOC_CHEAP_API_KEY": "sk_live_your_key" }
}
}
}
Deixe de fora a linha env para rodar com a chave de sandbox.
Claude Code:
claude mcp add-json doc-cheap '{"command":"npx","args":["-y","@doc-cheap/mcp"],"env":{"DOC_CHEAP_API_KEY":"sk_live_your_key"}}'
VS Code:
code --add-mcp '{"name":"doc-cheap","command":"npx","args":["-y","@doc-cheap/mcp"]}'
O Gemini CLI e o Kiro usam o mesmo bloco mcpServers nos seus próprios arquivos de configuração; o guia de MCP da documentação (em inglês) traz o caminho de cada um. Reinicie o cliente depois de editar: o servidor só percebe um ambiente alterado quando é iniciado de novo.
Instalação: o servidor hospedado
Se o seu cliente se conecta a uma URL em vez de iniciar um comando, as mesmas três ferramentas estão hospedadas em https://mcp.doc.cheap/mcp via Streamable HTTP, sem login. A chave vai num cabeçalho, X-Doc-Cheap-Api-Key ou Authorization: Bearer (se os dois forem enviados, vale o cabeçalho nomeado); sem chave, é usada a chave de sandbox.
Claude Code:
claude mcp add --transport http doc-cheap https://mcp.doc.cheap/mcp --header "Authorization: Bearer sk_live_your_key"
Cursor:
{
"mcpServers": {
"doc-cheap": {
"url": "https://mcp.doc.cheap/mcp",
"headers": { "Authorization": "Bearer sk_live_your_key" }
}
}
}
No Claude Desktop e no claude.ai, adicione-o em Settings → Connectors como um conector personalizado com essa URL.
O servidor hospedado não enxerga os arquivos da sua máquina, então ali o scan_document recebe a imagem como image_base64 ou como uma image_url pública.
Arquivos locais e URLs têm cerca de propósito
O argumento de uma ferramenta é escolhido por um modelo, e um modelo pode ser convencido de muita coisa. Por isso o servidor local não lê caminhos arbitrários:
image_pathfica desligado até você apontarDOC_CHEAP_IMAGE_ROOTpara um diretório. Os caminhos são resolvidos primeiro através dos links simbólicos, e..ou um link que aponte para fora do diretório é recusado. Um arquivo inexistente e um arquivo fora dos limites recebem a mesma mensagem, então a ferramenta não pode ser usada para sondar se um arquivo existe.image_urlprecisa serhttps:, precisa resolver apenas para endereços públicos (loopback, faixas privadas, link-local e similares são recusadas), segue no máximo três redirecionamentos, com cada salto verificado de novo, e tem limite de 25 MB.
Se você já conectou uma ferramenta de leitura de arquivos a um agente, compare-a com esta lista. "O modelo só vai passar caminhos sensatos" não é uma fronteira de segurança.
Mantendo o custo sob controle
Duas propriedades tornam previsível o uso por agentes:
- Só documentos reconhecidos são cobrados. Uma chamada é cobrada quando o tipo do documento foi determinado e dados foram de fato extraídos: uma MRZ cujos dígitos verificadores batem, pelo menos cinco campos impressos ou um código de barras decodificado corretamente. Documento não encontrado, imagem ilegível, tipo não suportado, erro interno ou timeout: nada disso custa. O flag
billeddo resultado diz o que aconteceu, sempre. Na chave de sandbox nada é cobrado, e o flag então diz se a mesma leitura teria sido cobrada numa chave de produção. - Retentativas podem sair de graça.
scan_documentaceita umidempotency_key; numa chave de produção, uma repetição com a mesma chave devolve o primeiro resultado armazenado em vez de cobrar de novo. Uma retentativa sem chave é uma segunda leitura. Uma repetição devolve o resultado armazenado, então éretain_hours: 0ou retentativas repetíveis, não os dois.
Na prática:
- Faça o agente chamar
check_balanceantes de um lote. As próprias instruções do servidor mandam o modelo fazer isso, e o promptbatch_scanfaz isso primeiro. Com a chave de sandbox o saldo énull, e a ferramenta diz que não há saldo em vez de mostrar zeros. - Aprove automaticamente só as ferramentas somente leitura. A configuração do Kiro, por exemplo, aceita
"autoApprove": ["check_balance", "search_docs"]. Deixe oscan_documentatrás de uma confirmação, porque é ele que gasta. - Deixe o agente consultar a documentação.
search_docsfunciona offline sobre a documentação embutida, então "o que significaunsupported_document" não custa nada e não depende da memória do modelo.
Privacidade: perguntas a fazer antes de fazer isso
Documentos de identidade são dos dados mais sensíveis que existem, e um agente acrescenta participantes ao fluxo. Veja o que é verdade do lado da API e o que depende da sua configuração.
Do lado da API (conforme a documentação):
- A imagem enviada fica na memória durante a requisição e nunca é gravada em armazenamento persistente.
- O resultado do reconhecimento é guardado para poder ser lido depois, por um período definido na conta (24 horas, 7 dias, 30 dias ou um ano). O padrão de uma conta nova é um ano. Por chamada,
retain_hours: 0não grava linha nenhuma, e oscan_documenttambém aceitaretain_hours. Se o agente só precisa da resposta uma vez, configure isso. - O processamento acontece na União Europeia. Os dados não são usados para treinar modelos.
return_portrait: falsedeixa de foraimages.main_photo, o recorte da foto do titular. O recorte da página inteira continua vindo, e com ele a segunda cópia esmaecida do rosto que alguns documentos imprimem na página.
Do seu lado:
- O resultado entra no contexto do modelo. O que o
scan_documentdevolve (nomes, números, datas) passa a estar na conversa e é processado pelo provedor de LLM que roda o seu cliente, nos termos desse provedor. Isso é inerente a qualquer ferramenta MCP, não algo específico desta. - O caminho da imagem importa. Com
image_pathno servidor local, o servidor lê o arquivo e o envia direto para a API. Comimage_base64, os bytes da imagem ficam nos argumentos da chamada de ferramenta do modelo. Se você quer que os pixels fiquem fora do contexto do modelo, use um diretório local cercado. - Isto é reconhecimento, não verificação. O grupo
authenticitydo resultado diznot_checked. Uma MRZ aprovada significa que a zona foi lida e é coerente consigo mesma, não que o documento seja autêntico. Não há prova de vida (liveness) nem comparação facial. Se o seu caso de uso é KYC, isto é um insumo, não a decisão. - Use documentos sintéticos enquanto desenvolve. Espécimes e MRZs geradas bastam para ligar tudo.
Uma sessão curta
Com o servidor instalado, basta um prompt como "Leia este passaporte digitalizado e me diga se ele vence nos próximos seis meses" com um espécime sintético anexado. Um agente bem-comportado chama scan_document, lê document.expiry_date e document.days_remaining no resultado e responde com base nesses campos, não na impressão que teve da imagem. Se a leitura voltar unreadable, ele deve dizer isso e pedir uma foto melhor, e você não foi cobrado por ela.
Esse último comportamento é o verdadeiro motivo para usar uma ferramenta aqui: o agente recebe um "não consegui ler" explícito em vez da tentação de preencher a lacuna.
Links
- Página do MCP com o trecho de cada cliente: https://doc.cheap/mcp
- Guia completo: https://doc.cheap/docs/guides/use-the-mcp-server
- Código-fonte (MIT): https://gitlab.com/doccheap/ocr-mcp
- npm: https://www.npmjs.com/package/@doc-cheap/mcp
Se você construir algo com ele, ou encontrar um cliente em que a configuração acima não funcione, escreva para admin@doc.cheap.
Cada afirmação sobre o doc.cheap e o seu servidor MCP foi conferida com o código deles.