Skip to main content
Glama

🔍 CPF Validador

Valide CPFs, descubra a quem pertencem e encontre o CPF correto a partir de dígitos parciais ou ilegíveis — com resolução automática de CAPTCHA via rede neural treinada localmente.

Expõe as mesmas operações como MCP tools (para agentes AI) e REST API (para integrações diretas), com interface web incluída.


💡 O que este projeto faz

Valida se um CPF é matematicamente correto

👤

Confirma a quem um CPF pertence pelo nome

🔎

Descobre o CPF completo a partir de dígitos parciais ou ilegíveis

👥

Processa dezenas de CPFs em paralelo

🤖

Integra com qualquer agente AI via protocolo MCP

Para confirmar a titularidade de um CPF, o sistema consulta o TRT3 — que emite certidões públicas associando CPF e nome. A resolução de CAPTCHA é feita por uma CRNN (Convolutional Recurrent Neural Network) treinada especificamente para isso, atingindo ~99% de acurácia sem depender de nenhum serviço externo.


Related MCP server: CPFHub MCP Server

🤖 MCP Tools

Tool

Descrição

validate_cpf

Valida matematicamente um CPF pelo algoritmo módulo-11

generate_valid_variations

Gera todas as variações válidas de um CPF com dígitos errados ou ilegíveis

check_cpf

Confirma titularidade de um CPF consultando o TRT3

find_cpf_by_mask

Descobre o CPF completo a partir de uma máscara com * nos dígitos desconhecidos

find_cpf_by_variations

Dado um CPF parcial ou errado, encontra o correto filtrando pelo nome

check_multiple_cpfs

Valida e confirma titularidade de uma lista de CPFs em paralelo


🌐 REST API

Método

Rota

Rate limit

Descrição

GET

/

Interface web

POST

/cpf/validate

Valida um CPF matematicamente

POST

/cpf/variations

Gera variações válidas de um CPF

POST

/consulta/cpf

10/min por IP

Confirma a titularidade de um CPF na fonte ativa

POST

/consulta/cpfs

5/min por IP

Confirma lista de CPFs em paralelo

POST

/consulta/buscar-por-mascara

3/min por IP

Descobre CPF por máscara com curingas

POST

/consulta/buscar-por-variacoes

3/min por IP

Descobre CPF correto a partir de variações

GET

/auth/check

Valida o token — 401 se ausente/incorreto, 200 se válido

GET

/health

Health check — retorna {"status": "ok"}

Documentação interativa: http://localhost:8000/docs (disponível apenas em ENV=development).

📂 Histórico de consultas

O histórico é local ao navegador — fica no localStorage da interface web e nunca sai do cliente. O servidor não persiste CPFs consultados.

  • Interface web: o toggle na aba Histórico ativa ou desativa o salvamento automático; a preferência também é salva no localStorage.

  • REST API / MCP: não gravam histórico — cada cliente registra o que quiser do seu lado.

  • Por fonte: a chave é cpf::fonte, então o mesmo CPF consultado no TRT3 e no TCU são duas entradas. Certidão é documento de quem emitiu; uma entrada só guardaria um número que não corresponde ao que está exibido.


🏗️ Arquitetura

FastAPI com FastMCP 3.0 montado em /mcp (streamable-http). A camada services/ não tem dependência de framework — a mesma lógica é consumida pelos routers REST e pelo MCP server.

app/
├── main.py             # FastAPI — routers + mcp.http_app() em /mcp + rate limiter
├── config.py           # Lê todas as variáveis de ambiente com defaults
├── mcp_server.py       # FastMCP("cpf-validador") — 6 tools
├── auth.py             # TokenMiddleware — autenticação via API_TOKEN + controle prod/dev
├── rate_limit.py       # Limiter compartilhado por main.py e routers/consulta.py
├── metrics.py          # Métricas Prometheus
├── services/
│   ├── cpf.py          # Validação, variações e geração por máscara (zero deps de framework)
│   └── sources/        # Fontes de consulta — escolhidas por SOURCE no .env
│       ├── base.py       # Contrato: ABC Fonte + formato do retorno
│       ├── __init__.py   # Registro + busca em lote paralela (agnóstica de fonte)
│       ├── trt3.py       # TRT3: curl_cffi + CAPTCHA de imagem (CRNN) + pypdf
│       ├── tcu.py        # TCU: API JSON + CAPTCHA Altcha (proof-of-work)
│       └── exemplo.py    # Modelo para novas fontes (fictícia, sem rede)
├── routers/
│   ├── cpf.py          # POST /cpf/validate, POST /cpf/variations
│   ├── consulta.py     # POST /consulta/cpf, /cpfs, /buscar-por-mascara, /buscar-por-variacoes
│   └── ui.py           # GET / — interface web
└── captcha/
    ├── model.py        # Arquitetura CRNN (CNN + BiLSTM + CTC Loss)
    ├── predictor.py    # Inferência: carrega captcha_model.pt e prediz
    ├── dataset.py      # CaptchaDataset com data augmentation
    ├── train.py        # Loop de treino com early stopping + AMP + registry
    ├── collector.py    # Coleta amostras rotuladas direto do TRT3
    ├── registry.py     # Versionamento de modelos (models/vN/model.pt + meta.json)
    └── models/         # Histórico de versões treinadas

Regras de camada:

  • services/ — zero imports de FastAPI ou FastMCP

  • routers/ e mcp_server.py — importam apenas de services/, e nunca uma fonte concreta

  • I/O bloqueante em services/sources/ é sempre executado via run_in_threadpool

🔌 Fontes de consulta

A pergunta "a quem pertence este CPF?" é respondida por uma fonte. A fonte ativa vem de SOURCE no .env:

SOURCE

Fonte

Abrangência

CAPTCHA

trt3 (padrão)

TRT 3ª Região — feitos trabalhistas

Minas Gerais

imagem, resolvida por CRNN local

tcu

TCU — contas julgadas irregulares

Nacional

Altcha (proof-of-work, via altcha-solver)

exemplo

Dados fictícios, não consulta nada

nenhum

As duas fontes reais não se parecem em nada por dentro, e é essa a prova de que a camada funciona: o TRT3 é um formulário JSF com ViewState, CAPTCHA de imagem e resposta em PDF; o TCU é uma API JSON cujo CAPTCHA é um proof-of-work — o cliente procura um contador cujo PBKDF2-HMAC-SHA256 comece com um prefixo dado, gastando CPU em vez de visão computacional. Nenhum router, tool MCP ou a lógica de máscara precisou mudar para a segunda entrar.

Cada fonte decide sozinha como consulta — cliente HTTP, autenticação, CAPTCHA ou a ausência dele, parsing da resposta e limite de conexões simultâneas. A camada comum padroniza apenas o formato do resultado.

A fonte também declara o que sabe fazer, e a interface se adapta: uma fonte com usa_captcha = False mostra "Consulta concluída" no lugar de "CAPTCHA resolvido", em vez de anunciar um trabalho que não aconteceu.

Imagem sem PyTorch

O PyTorch existe só para a CRNN que lê o CAPTCHA de imagem do TRT3 — são ~780 MB, 44% da imagem. O CAPTCHA do TCU é proof-of-work, resolvido com a biblioteca padrão. Se você não vai usar SOURCE=trt3:

docker build --build-arg COM_TRT3=false .   # 473 MB em vez de 1.76 GB

Subir essa imagem com SOURCE=trt3 falha no boot com a instrução de como instalar, em vez de subir e quebrar na primeira consulta.

Escrevendo uma fonte nova

Copie app/services/sources/exemplo.py — ele tem os cinco passos de uma consulta comentados — implemente consultar() e registre a classe:

class TRT2(Fonte):
    nome = "trt2"                       # o valor usado em SOURCE=
    rotulo = "TRT 2ª Região (SP)"       # texto legível, aparece no log e na UI
    usa_captcha = True                  # padrão é False

    def consultar(self, cpf_limpo: str) -> dict:
        ...

E registre:

# app/services/sources/__init__.py
_REGISTRO = {
    "trt3":    ("app.services.sources.trt3",    "TRT3",    "TRT 3ª Região"),
    "trt2":    ("app.services.sources.trt2",    "TRT2",    "TRT 2ª Região (SP)"),  # nova
}

O contrato do retorno é este — só estas chaves são interpretadas:

{
    "cpf": "151.879.820-95",       # obrigatório, formatado
    "encontrado": True,            # True achou | False não consta | None erro
    "nome_certidao": "FULANO",     # o filtro nome= das buscas em lote depende desta chave
    "tem_registro": False,         # a certidão é positiva? (há processo/conta irregular)
    "cpf_inexistente": False,      # a fonte não reconhece o CPF — acompanha encontrado=False
    "mensagem": "...",             # texto exibido ao usuário; use as constantes MSG_* de base.py
    "erro": "...",                 # só quando a consulta falhou
}

consultar() não deve levantar exceção: falha vira encontrado: None + erro. Quem chama roda centenas em paralelo e trata ausência de resultado, não stack trace.

Nenhum router, tool MCP ou a lógica de máscara/variações precisa mudar — todos falam com a fonte ativa através de sources.consultar() e sources.consultar_multiplos().


⚙️ Configuração

Todas as opções são lidas de variáveis de ambiente ou do arquivo .env na raiz do projeto.

Referência completa de variáveis

Variável

Padrão

Descrição

API_TOKEN

(vazio — sem auth)

Token Bearer. Se vazio, todos os endpoints ficam abertos

ENV

development

development ou production — controla quais rotas ficam abertas sem token

SOURCE

trt3

Fonte consultada: trt3, tcu ou exemplo

TCU_BASE_URL

https://certidoes.apps.tcu.gov.br

Base da API do TCU

TCU_POW_MAX_COUNTER

200000

Teto da busca do proof-of-work (na prática o contador fica abaixo de 5.000)

TCU_MAX_ATTEMPTS

3

Tentativas por consulta ao TCU (o desafio vale ~90s e é de uso único)

TRT3_BASE_URL

https://certidao.trt3.jus.br

URL base do site do TRT3

TRT3_FORM_PATH

/certidao/feitosTrabalhistas/aba1.emissao.htm

Path do formulário de consulta

HTTP_TIMEOUT

30

Timeout (segundos) para requisições HTTP ao TRT3

CAPTCHA_TIMEOUT

15

Timeout (segundos) para download da imagem CAPTCHA

MAX_CAPTCHA_ATTEMPTS

20

Tentativas máximas de resolver o CAPTCHA antes de desistir

RETRY_DELAY

1.0

Segundos de espera entre tentativas de CAPTCHA

DEFAULT_WORKERS

8

Threads paralelas padrão nas consultas em lote

MAX_WORKERS

20

Limite máximo de workers que o cliente pode solicitar

TASK_TIMEOUT

60

Timeout (segundos) por CPF individual em consultas paralelas

MAX_WILDCARDS_IN_MASK

5

Máximo de curingas na parte base da máscara (evita explosão combinatória)

RATE_LIMIT_CPF

10/minute

Rate limit de /consulta/cpf por IP

RATE_LIMIT_CPFS

5/minute

Rate limit de /consulta/cpfs por IP

RATE_LIMIT_MASK

3/minute

Rate limit de /consulta/buscar-por-mascara por IP

RATE_LIMIT_VARIACOES

3/minute

Rate limit de /consulta/buscar-por-variacoes por IP

CAPTCHA_MODEL_PATH

(vazio — usa app/captcha/captcha_model.pt)

Path absoluto para o modelo .pt (útil para montar modelo externo)

METRICS_PUBLIC

false

true abre /metrics sem token também em production

LOG_LEVEL

INFO

Nível de log da consulta ao TRT3. DEBUG mostra cada tentativa de CAPTCHA

FORWARDED_ALLOW_IPS

*

Proxies em que confiar para ler X-Forwarded-For. Necessário para o rate limit contar por IP real atrás de proxy

🔒 Rotas abertas por ambiente

Rota

development

production

/

✅ aberta

✅ aberta

/health

✅ aberta

✅ aberta

/docs

✅ aberta

🔒 token

/redoc

✅ aberta

🔒 token

/openapi.json

✅ aberta

🔒 token

/metrics

✅ aberta

🔒 token (ou METRICS_PUBLIC=true)

/mcp

🔒 token

🔒 token

demais

🔒 token

🔒 token

Se API_TOKEN estiver vazio, o middleware ignora autenticação em qualquer ambiente.


🔐 Autenticação

Com API_TOKEN configurado, todas as requisições protegidas precisam enviar:

Authorization: Bearer meu-token-secreto

REST:

curl -X POST http://localhost:8000/consulta/cpf \
  -H "Authorization: Bearer meu-token-secreto" \
  -H "Content-Type: application/json" \
  -d '{"cpf": "151.879.820-95"}'

Claude Desktop / Claude Code (claude_desktop_config.json):

{
  "mcpServers": {
    "cpf-validador": {
      "command": "npx",
      "args": ["mcp-remote", "http://localhost:8000/mcp", "--allow-http"],
      "env": {
        "MCP_REMOTE_HEADER_AUTHORIZATION": "Bearer meu-token-secreto"
      }
    }
  }
}

A interface web (/) exibe um gate de autenticação quando API_TOKEN está definido — o token é validado contra o servidor e salvo no navegador.


📊 Métricas

GET /metrics expõe métricas Prometheus. Os nomes separam o que vale para qualquer fonte do que é de uma só:

Prefixo

Exemplos

O que mede

consulta_*

consulta_queries_total{fonte,result}, consulta_duration_seconds{fonte}, consulta_cpf_total, consulta_matches_total

A consulta em si, com label fonte. Contadas num ponto só, então toda fonte é medida igual

trt3_*

trt3_captcha_attempts_total, trt3_captcha_result_total, trt3_pdf_parsed_total, trt3_session_resets_total

Específicas do scraping do TRT3

tcu_*

tcu_pow_duration_seconds, tcu_pow_counter, tcu_concurrent_queries, tcu_http_errors_total

Específicas do proof-of-work do TCU

cpf_*

cpf_validations_total, cpf_mask_searches_total, cpf_bulk_size

Operações de CPF, sem rede

mcp_calls_total{tool,result}, http_rate_limit_total{endpoint}

Uso da aplicação

O resultado de consulta_queries_total distingue found, not_found, not_registered (o CPF não existe na base), indeterminate e error.

Em production a rota exige token; METRICS_PUBLIC=true abre. Configure bearer_token no Prometheus se mantiver fechada.


🚀 Instalação

Docker (recomendado)

git clone https://github.com/opastorello/cpf-validador.git
cd cpf-validador
cp .env.example .env   # edite se quiser definir API_TOKEN
docker compose up --build -d

Local

pip install -r requirements-trt3.txt   # inclui o PyTorch da CRNN do TRT3
# sem usar SOURCE=trt3? `pip install -r requirements.txt` basta e evita ~780 MB
cp .env.example .env
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload

Após iniciar:

  • Interface web: http://localhost:8000/

  • REST docs: http://localhost:8000/docs (apenas em ENV=development)

  • MCP endpoint: http://localhost:8000/mcp


📋 Exemplos de uso

Validar um CPF

curl -X POST http://localhost:8000/cpf/validate \
  -H "Content-Type: application/json" \
  -d '{"cpf": "151.879.820-95"}'

Confirmar titularidade

curl -X POST http://localhost:8000/consulta/cpf \
  -H "Content-Type: application/json" \
  -d '{"cpf": "151.879.820-95"}'
{
  "cpf": "151.879.820-95",
  "encontrado": true,
  "nome_certidao": "JOAO DA SILVA",
  "valida_ate": "18/04/2026",
  "numero_certidao": "2026/123456"
}

Descobrir CPF por máscara

Quando você conhece apenas parte dos dígitos — substitua os desconhecidos por *:

curl -X POST http://localhost:8000/consulta/buscar-por-mascara \
  -H "Content-Type: application/json" \
  -d '{"mascara": "***.123.456-**", "nome": "João Silva"}'

O servidor gera todas as combinações válidas para as posições curinga, consulta em paralelo e retorna apenas os matches com o nome informado.

A busca para assim que confirma o nome. Confirmar segue a mesma regra do selo ✓ Confirmado da interface: nomes iguais, ou toda palavra procurada aparecendo inteira no nome encontrado — MARIA SILVA confirma MARIA APARECIDA SILVA, mas SILVA sozinho não confirma, senão pararia no primeiro homônimo parcial. Numa máscara de 1.000 candidatos isso costuma cortar metade das consultas ao serviço externo. A resposta traz consultados e interrompido, e parar_ao_confirmar: false desliga quando você quiser listar homônimos.

Formatos de máscara aceitos. Os curingas *, X, x, ?, _ e # são equivalentes, os separadores ., -, / e espaços são ignorados (inclusive nenhum separador), e os dígitos verificadores podem ser omitidos. Todas estas máscaras são a mesma coisa:

***.879.820-**      ← mascaramento LGPD de documento público
***879820**         ← sem separador
*** 879 820 **      ← separado por espaço
XXX.879.820-XX      ← anotação manual
???.879.820-??
___.879.820-__      ← campo de formulário
###.879.820-##      ← planilha
***.879.820         ← dígitos verificadores omitidos

Um caractere que não seja dígito, curinga ou separador é rejeitado com 422 apontando qual é — em vez de ser descartado silenciosamente e virar erro de tamanho.

Máximo de 5 wildcards na parte base (posições 0–8) = até 100.000 combinações. Configurável via MAX_WILDCARDS_IN_MASK.

Recuperar CPF com erros ou dígito faltando

curl -X POST http://localhost:8000/consulta/buscar-por-variacoes \
  -H "Content-Type: application/json" \
  -d '{"cpf_parcial": "1518798209", "nome": "joao"}'

Consulta em lote

curl -X POST http://localhost:8000/consulta/cpfs \
  -H "Content-Type: application/json" \
  -d '{"cpfs": ["151.879.820-95", "151.879.821-76"], "workers": 4}'

🧠 Modelo de CAPTCHA

Arquitetura CRNN

Input (1×60×160)
    → Conv2D ×4 + BatchNorm + ReLU + MaxPool   (extração de features visuais)
    → BiLSTM ×2 (128 hidden, bidirectional)    (modelagem de sequência)
    → Linear → CTC Loss                         (decode sem segmentação)
Output: string de 5 caracteres [0-9a-z]

Bootstrapping em 3 rodadas

Rodada

Amostras

Rotulador

Acurácia dos labels

Acurácia do modelo

1

15.000

ddddocr (OCR genérico)

~43%

98.70%

2

20.000

Modelo R1

~96%

98.80%

3

20.000

Modelo R2

~99.3%

98.55%

Total: 55.000 amostras. O modelo final (v1) convergiu na época 106/120 com val_loss=0.0072.

Hiperparâmetros

  • Optimizer: AdamW | LR: 1e-3 com CosineAnnealingLR

  • Epochs: 120 com early stopping (patience: 20)

  • Batch size: 128 | Treino: GPU com AMP float16 via torch.amp.autocast

  • Inferência: CPU-only (Docker)

  • Augmentation: rotação, shear, translate, color jitter, gaussian blur, random erasing


Treinar o modelo

1. Coletar amostras

python -m app.captcha.collector --cpf 000.000.000-00 --target 15000 --workers 4

2. Treinar

python -m app.captcha.train --epochs 120 --batch 128 --lr 1e-3

O melhor modelo (menor val_loss) é salvo em app/captcha/captcha_model.pt.

3. Bootstrap (melhora qualidade dos labels)

rm -rf app/captcha/data/
python -m app.captcha.collector --cpf 000.000.000-00 --target 20000 --workers 4
python -m app.captcha.train --epochs 120 --batch 128 --lr 1e-3

Repita 2–3 rodadas até a acurácia estabilizar. Para consultar o histórico de versões:

python -m app.captcha.registry

📦 Dependências principais

Pacote

Uso

FastMCP

Framework MCP server

FastAPI

REST API

slowapi

Rate limiting por IP

curl-cffi

HTTP com impersonação TLS Chrome-124

altcha-solver

Proof-of-work do CAPTCHA Altcha (fonte TCU)

PyTorch

Rede neural CRNN para o CAPTCHA de imagem (fonte TRT3, opcional)

torchvision

Transforms e augmentation de imagem (fonte TRT3, opcional)

pypdf

Extração de dados do PDF de certidão

Pillow

Processamento de imagem

python-dotenv

Carregamento de variáveis do .env


🗺️ Roadmap

Ideias e melhorias planejadas para versões futuras.

Escalabilidade

  • Worker distribuído — arquitetura de fila (Redis + worker nodes) onde cada nó é uma VPS com IP próprio contribuindo com slots de conexão ao TRT3. Escala horizontalmente: 1 worker = 20 slots, 5 workers = 100 slots, IPs diferentes reduzem risco de throttling.

  • Cache de resultados — CPFs já consultados recentemente retornam resultado armazenado sem nova requisição ao TRT3. Reduz latência e carga no tribunal.

Multi-usuário

  • Quota de consultas por token — cada token teria um limite mensal/diário de consultas configurável independentemente do rate limit por IP. Ex: token A = 1.000 consultas/dia, token B = 10.000/dia.

  • Workers por token — cada token teria um número máximo de workers simultâneos ao TRT3. Ex: token gratuito = 2 workers, token premium = 20 workers. Garante que um único cliente não monopoliza a capacidade do servidor enquanto outros aguardam.

Cobertura

  • Suporte a outros tribunais — expandir para TRT1 (RJ), TRT2 (SP) e demais regiões, consolidando resultados em uma única consulta.

  • Consulta à Receita Federal — validar situação cadastral do CPF diretamente na base da RF.

Observabilidade

  • Dashboard de uso — visualizar volume de consultas, taxa de acerto do CAPTCHA e latência média por endpoint.

  • Alerta de bloqueio — detectar automaticamente quando o TRT3 começa a retornar erros acima do normal e notificar.


⚖️ Responsabilidade de Uso

Este projeto consulta exclusivamente o sistema público do TRT3 (certidao.trt3.jus.br) — os mesmos dados acessíveis por qualquer pessoa pelo navegador, sem login ou cadastro. As certidões emitidas são documentos públicos por determinação legal.

Usos adequados:

  • Due diligence em processos de contratação

  • Verificação de titularidade em contextos jurídicos ou de compliance

  • Integração com agentes AI para automação de processos legítimos

O projeto não se destina a:

  • Varredura em massa sem finalidade específica

  • Coleta de dados para fins não autorizados pela LGPD

  • Qualquer uso que viole a legislação brasileira vigente

O código é aberto e auditável. A responsabilidade pelo uso é inteiramente do operador que implanta e utiliza o serviço. Rate limiting está configurado por padrão para desincentivar abuso.


📄 Licença

MIT © 2026 Nícolas Pastorello

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    MCP server for CPFHub.io that enables AI agents to retrieve identity data (full name, gender, date of birth) from Brazilian CPF numbers and check API quota.
    2
    53
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables querying basic Brazilian CPF registration data (name, status, birth date) via a hosted MCP server with a single read-only tool, usable from any MCP client.
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Consulta dados cadastrais e situação de CPF na Receita Federal a partir de um número de CPF. Serve como ferramenta somente leitura, paga por uso, para clientes MCP.
    MIT