lex-rag
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@lex-ragqual o texto do art. 5º da Constituição Federal?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
lex-rag
MCP server de RAG sobre a base normativa federal brasileira (Constituição, Leis Complementares, Leis Ordinárias, Decretos). Foco em anti-alucinação: o MCP devolve sempre texto literal do dispositivo + URN-LEX + URL canônica do Planalto, e nunca paráfrase.
Stack
Python 3.12
Qdrant embedded (sem Docker — escreve em
data/qdrant/)BGE-M3 (denso + esparso num único pass) — embedding local, acelerado por GPU quando disponível
BGE-reranker-v2-m3 — reranker (Fase 2)
MCP SDK (stdio para Claude Desktop / Claude Code)
Daemon de inferência (FastAPI/uvicorn) — segura os modelos quentes; o MCP server é um cliente fino que fala com ele por HTTP no loopback
Related MCP server: ickyMCP
Arquitetura: daemon de inferência
Os modelos (BGE-M3 + reranker, ~4,6 GB) são carregados uma única vez por um daemon residente (lex_rag.service), que também é o dono único do Qdrant embedded. O MCP server que o Claude Code inicia é apenas um cliente HTTP fino — sobe em milissegundos e encaminha cada consulta ao daemon.
Claude Code ──spawn──> MCP server (cliente fino)
│ HTTP 127.0.0.1:8765
▼
Daemon de inferência (lex_rag.service)
BGE-M3 + reranker quentes + QdrantPor que: sem o daemon, cada sessão do Claude recriava o processo MCP e recarregava os ~4,6 GB na primeira pergunta (cold start de vários segundos). Com o daemon, esse custo é pago uma vez ao iniciá-lo; toda consulta seguinte (e qualquer reinício do Claude) responde quente.
É preciso ter o daemon no ar para o MCP funcionar. Controle manual (sob demanda):
.\tasks.ps1 serve # foreground: sobe o daemon e mostra os logs (Ctrl+C encerra)
# ou, em background:
.\tasks.ps1 daemon-start # inicia escondido (pythonw), grava o PID em data\daemon.pid
.\tasks.ps1 daemon-status # confere o processo + GET /health
.\tasks.ps1 daemon-stop # encerra e libera a VRAMHardware / GPU
A escolha de device é automática (src/lex_rag/device.py): usa CUDA + fp16 quando há GPU NVIDIA, senão cai para CPU em fp32. Para forçar, defina LEX_RAG_DEVICE=cuda ou LEX_RAG_DEVICE=cpu.
Desenvolvido numa RTX 3060 (12 GB), mas roda sem GPU dedicada. O que muda em CPU:
Consulta: embedar a pergunta é rápido; o gargalo é o reranker sobre os 40 candidatos — espere alguns segundos por busca, contra frações de segundo em GPU.
RAM: os dois modelos em fp32 ocupam ~5 GB; 8 GB é o mínimo prático, 16 GB é confortável. Em disco, os modelos baixados do Hugging Face somam ~6,5 GB.
Indexar o corpus do zero (
bootstrap) leva horas. Por isso o corpus é distribuído pronto — veja Instalação a partir do snapshot.Apple Silicon: não há tratamento de
mps; cai em CPU e funciona.
Corpus
São 761 documentos: 696 normas baixadas ao vivo do Planalto — o núcleo essencial curado à mão (35), todas as Leis Complementares (conjunto fechado, descoberto no quadro oficial), um lote curado de leis ordinárias de consulta frequente (388) e um núcleo de decretos (42) —, os 63 enunciados de Súmula Vinculante do STF, servidos de um JSON versionado, e os 2 regimentos internos do Senado e da Câmara, baixados do sítio de cada Casa.
Constituição Federal de 1988
Códigos: Civil, Penal, Processo Penal, Processo Civil, Tributário Nacional, CLT, Defesa do Consumidor, Trânsito, Eleitoral, Florestal, Penal Militar, Processo Penal Militar, Brasileiro de Aeronáutica, de Telecomunicações, de Mineração
Leis Complementares: todas (LC 1/1962 à mais recente, incluindo 95/1998, 101/2000 — LRF, 116/2003 — ISS, 123/2006 — Simples, 214/2025 — reforma tributária)
Leis ordinárias, por eixo: processo e carreiras jurídicas (MS, ação civil pública, mediação, OAB, LONMP), controle e finanças públicas, administração e contratação pública, eleitoral, penal extravagante, civil e empresarial, urbano e ambiental, agrário, saúde, educação, cultura e esporte, trabalho, transportes, energia e mineração, sistema financeiro e tributário, comunicações e direitos sociais. Entre os regimes de incentivo setorial, a Rota 2030 (Lei 13.755/2018) e o Mover (Lei 14.902/2024) entram como par, porque o Mover sucede a Rota 2030 e revoga dispositivos dela — quem consulta um precisa do outro para saber o que sobrou —, ao lado do Reidi (Lei 11.488/2007)
Direito econômico: além da ordem econômica já coberta (defesa da concorrência, liberdade econômica, consumidor, as agências reguladoras e a Lei 13.848/2019, concessões, PPP, estatais), entram os quatro flancos que faltavam — defesa comercial (Lei 9.019/1995 e o Decreto 8.058/2013, o regulamento antidumping) com a Zona Franca de Manaus (DL 288/1967, cujo texto-base faltava embora a Lei 8.387/1991, que o altera, já estivesse no corpus); resolução bancária (Leis 6.024/1974 e 9.447/1997, que a Lei 11.101/2005 exclui do seu âmbito) com o processo sancionador do BCB e da CVM (Lei 13.506/2017); infraestrutura de mercado (Lei 10.214/2001, o SPB, base da Lei 12.865/2013, já presente) e o mercado de capitais de 1965 (Lei 4.728/1965); e os títulos que financiam a atividade produtiva — CPR, CDA/WA, CDCA, LCA e CRA, LCI, CCI e CCB, arrendamento mercantil, consórcio, debêntures de infraestrutura, PNMPO e Pronampe. Junto vieram portos (Lei 12.815/2013) e a relicitação de contratos de parceria (Lei 13.448/2017), o registro público de empresas (Lei 8.934/1994) e os canais de distribuição (representação comercial e Lei Ferrari)
Fundos: as leis que instituem ou disciplinam os principais fundos federais — constitucionais de financiamento (FNO/FNE/FCO) e garantidores (FGO, FGI, FGE), de investimento e patrimoniais (FII, FIP-IE, endowments), socioambientais (FNMA, Fundo Clima, FNDF), de infraestrutura e comunicações (Fust, Funttel, Fistel, FMM, FNHIS, CDE, FCVS), o FNDCT e os fundos setoriais de C&T que o abastecem, além de FNDE, FCDF e audiovisual
Políticas nacionais: as leis que instituem ou definem uma Política Nacional — conjunto levantado por varredura exaustiva, não por memória (quadros oficiais do Planalto para 1988-2000 e a API de metadados do LexML para 1934-2026, 15.396 leis, filtrando a ementa). Ficaram de fora só as revogadas ou superadas. Junto vieram as correlatas estruturantes do mesmo tipo — Sistema Nacional (Sinase, Sinaes, Sine, Sinamob, prevenção à tortura, sementes e mudas, marco do SNC) e Plano Nacional (gerenciamento costeiro, Pnatrans, PNE 2026)
Leis orçamentárias: a parte textual da LDO e da LOA de cada exercício de 2012 a 2026 (15 pares). Entra a lei que fixa as diretrizes ou que estima a receita e fixa a despesa; ficam de fora as que só as alteram e as dezenas anuais de crédito suplementar, especial e extraordinário. A parte textual é o que o pipeline indexa por construção — os anexos são tabelas, e o parser só produz dispositivo a partir de artigo (a LOA de 2024 tem 309 KB de HTML e rende 10 artigos; a LDO, 130 a 199). O apelido leva o exercício (
LDO 2024), o que distingue na busca artigos que se repetem quase iguais de um ano para o outroDecretos: o que regulamenta lei já presente no corpus ou consolida um regulamento de consulta frequente — RIR, RIPI, Regulamento Aduaneiro, RPS, IOF, ITR, processo administrativo fiscal e eSocial; contratações públicas sob a Lei 14.133 (registro de preços, agente de contratação, plano anual, credenciamento, margem de preferência) e o par do regime antigo (pregão eletrônico, SRP da 8.666); administração e integridade (LAI, anticorrupção, governança, Código de Ética, PNDP, MROSC); direitos e consumidor (SUS, BPC, acessibilidade, migração, Bolsa Família, SNDC, SAC, comércio eletrônico); e setoriais (infrações ambientais, energia, ANEEL, desarmamento, florestas públicas)
Regimentos internos: o RISF (Resolução do Senado Federal nº 93, de 1970 — 448 dispositivos) e o RICD (Resolução da Câmara dos Deputados nº 17, de 1989 — 316), no texto compilado que cada Casa publica. Entram porque o rito das Casas não está na lei: prazo de emenda, regime de urgência, quórum, competência de comissão e questão de ordem são matéria regimental, e sem eles o corpus respondia processo legislativo só pelo art. 59 e seguintes da Constituição. O Planalto não os publica, então são a única parte do corpus com fonte fora dele — e a página de cada Casa serve mais de um documento na mesma URL (a da Câmara traz a resolução promulgadora, o Regimento anexo e o Código de Ética), daí o campo
recortedo catálogo. Ficam de fora, por ora, o Regimento Comum do Congresso Nacional e o Código de Ética e Decoro Parlamentar da CâmaraSúmulas Vinculantes do STF: os 63 enunciados, do portal oficial. É a única jurisprudência do corpus, e entra por ter força normativa erga omnes (CF, art. 103-A): é o degrau entre a lei e o acórdão, não uma amostra de julgados. Acórdãos, votos, informativos e ementas de ADI/ADC continuam fora de escopo — a proposta é conhecimento jurisprudencial sintético, não peça processual. As duas fora de vigor entram marcadas em vez de omitidas (a SV 9, cancelada em 2025, e a SV 30, cuja publicação foi suspensa em 2010 e que nunca produziu efeitos): o default
somente_vigenteas esconde da busca comum, e quem as procura recebe o enunciado com a marca em vez de silêncio
O catálogo fica em src/lex_rag/ingest/urn_mapper.py (REGISTRO): o núcleo
curado à mão (REGISTRO_CURADO) mesclado com quatro registros gerados e
validados — registro_lcp.json (de scripts/descobrir_lcps.py, a partir do
quadro oficial), registro_ordinarias.json (de
scripts/descobrir_ordinarias.py, que resolve a URL canônica, já que o Planalto
não a deriva do número, e confere a data contra a epígrafe impressa na página),
registro_decretos.json (de scripts/descobrir_decretos.py, pela mesma
mecânica, com as convenções de URL e o rótulo de epígrafe próprios da espécie) e
sumulas_vinculantes.json (de scripts/descobrir_sumulas.py). Em conflito de
URN, a entrada curada vence.
Para incluir uma norma avulsa, acrescente uma entrada curada com o URN-LEX e a
URL canônica e rode bootstrap (ou update). Para crescer o corpus por lote,
acrescente as candidatas a CANDIDATAS em scripts/descobrir_ordinarias.py e
rode o script (ele reaproveita as URLs já resolvidas e só vai à rede pelas
novas); para LC nova promulgada, rode scripts/descobrir_lcps.py. Depois de
qualquer lote, rode scripts/verificar_parser.py --novos --baixar antes de
indexar: das nove expansões do corpus, quatro revelaram bug de parser e uma um
bug de decodificação — achá-lo antes da carga custa uma correção em vez de uma
reindexação inteira. Vale inspecionar os suspeitos um a um, mesmo os que
parecem só o ruído já conhecido: foi assim que apareceram os bugs nº 8 e nº 9.
As súmulas seguem outro caminho, porque a forma do documento é outra: um
enunciado único, sem articulação. O parser só produz dispositivo a partir de
marcador Art. N, então uma súmula rodada nele sairia com zero dispositivos — e
zero dispositivo é sucesso silencioso (a norma vai para o state.sqlite, nenhum
ponto entra no índice, nada acusa erro). O dispatch fica em dois pontos por onde
bootstrap, update e reindexação já passam — ingest/source.py e parse_norma —,
e leva a ingest/jurisprudencia.py, que monta uma norma de dispositivo único
(path enunciado). O caminho do Planalto não é tocado.
Outra diferença: o enunciado não é rebaixado a cada update, é servido do
próprio sumulas_vinculantes.json versionado. São 63 textos curtos que o STF
edita uma ou duas vezes por ano; um scraper vigiando isso em produção custaria
mais manutenção do que a edição que evita. O hash que decide reindexação é o do
JSON canônico da entrada, então reindentar o arquivo não reindexa nada e editar
uma súmula reindexa só ela. Para incorporar súmula nova ou cancelamento, rode
python scripts/descobrir_sumulas.py (recolhe os enunciados do portal do STF e
confere a situação que ele publica contra a curada) e depois
python scripts/verificar_sumulas.py, que é o verificar_parser.py desse lote:
confere numeração sem buraco, URN batendo com a data de aprovação, enunciado sem
mojibake nem truncamento, e vocabulário de situação. As datas de sessão e DJe
não estão na página e vivem na tabela DATAS do script de descoberta.
Quando o que mudar for o parser, e não o conteúdo no Planalto, reindexe com
scripts/reindexar_do_cache.py: o update decide o que refazer pelo hash do
HTML, então correção de parser não dispara reindexação nenhuma, e o bootstrap
rebaixaria as 696 normas — o portal estrangula a conexão bem antes do fim.
Reparsear o HTML já em data/raw/ dá o mesmo resultado sem tocar na rede. Como
ele recria a coleção, pare o daemon antes.
Para descobrir o que falta num recorte temático, a API pública de metadados
do LexML (https://normas.leg.br/api/public/metadados/simples?urn=...) devolve
data e ementa oficiais por URN e aceita urn:lex:br:federal:lei:{ano};{numero},
o que permite varrer a numeração inteira sem tocar no Planalto. Duas ressalvas:
o urn casa o número por sufixo (pedir lei:1962;118 devolve a Lei 4.118),
então confira o name da resposta contra o número pedido; e a busca do LexML
(www.lexml.gov.br/busca/SRU) está atrás de desafio de segurança — só a API de
metadados serve.
As 5 primeiras normas curadas têm um HTML offline em tests/fixtures/, usado
como fallback quando o download falha (só no bootstrap — no update uma falha
de download preserva o índice atual em vez de regredi-lo).
O Planalto recusa User-Agents não-navegador (derruba a conexão); por isso o fetcher usa um UA de navegador e faz a coleta de forma sequencial e educada (
http_polite_delay). O decodificador assume Windows-1252 (não latin-1: a faixa 0x80-0x9F carrega travessão e aspas, que em latin-1 virariam caracteres de controle) e é ciente de BOM (algumas páginas vêm em UTF-16).
Setup (Windows)
.\scripts\setup_env.ps1 # cria .venv (Python 3.12) e instala torch CUDA + deps
.\scripts\setup_env.ps1 -Cpu # idem, sem GPU NVIDIA (torch CPU)
.\tasks.ps1 smoke # smoke test: indexa 3 artigos da CF e faz 1 buscaRequer Python 3.12 acessível via
py -3.12. Versões mais novas não atendemrequires-python.
Em Linux/macOS, o Makefile (com uv) expõe os mesmos alvos: make install-dev (GPU) ou make install-cpu.
Instalação a partir do snapshot
O git guarda só o código. O corpus pré-montado — índice Qdrant, state.sqlite
e o cache HTML das normas, ~620 MB — circula como um zip anexado a cada
Release do repositório. Restaurá-lo dispensa o bootstrap
(horas de download do Planalto e de embedding), e é o único caminho viável
sem GPU.
.\scripts\setup_env.ps1 -Cpu # ou sem -Cpu, com GPU NVIDIA
.\tasks.ps1 snapshot-restaurar https://github.com/arturlascala/lex-rag/releases/latest/download/lex-rag-snapshot.zip
.\tasks.ps1 daemon-start # 1ª vez: baixa ~6,5 GB de modelos do Hugging Face
.\tasks.ps1 daemon-status # espere o /health responderUm zip já baixado também serve (snapshot-restaurar C:\caminho\lex-rag-snapshot.zip);
-Forcar substitui um corpus existente. Em Linux/macOS:
make snapshot-restaurar ORIGEM=<zip ou URL> [FORCAR=1]. A URL releases/latest/download/…
aponta sempre para o Release mais recente; para um lote específico, use a página de Releases.
O zip traz um MANIFEST.json com a versão do qdrant-client que gerou o
índice — o formato do Qdrant embedded muda entre versões, então o
pyproject.toml fixa a versão exata e o restaurar avisa se a instalada for
outra. Depois de restaurado, o update semanal funciona normalmente: o
state.sqlite carrega os hashes, e só o que mudou no Planalto é reprocessado.
Para publicar um snapshot (mantenedor): pare o daemon, rode
.\tasks.ps1 snapshot-criar (ou make snapshot-criar) e anexe o
dist/lex-rag-snapshot.zip a um Release com a tag do lote (o nome do arquivo é
fixo de propósito, para a URL latest funcionar). O limite do GitHub é 2 GB por
arquivo.
Comandos principais (Windows)
.\tasks.ps1 bootstrap # carga do corpus (baixa as ~696 normas do Planalto)
.\tasks.ps1 update # delta incremental
.\tasks.ps1 serve # daemon de inferência (foreground)
.\tasks.ps1 daemon-start # daemon em background
.\tasks.ps1 daemon-stop # encerra o daemon
.\tasks.ps1 daemon-status # estado do daemon (/health)
.\tasks.ps1 mcp # inicia MCP server (stdio) — exige o daemon no ar
.\tasks.ps1 test # pytest (exclui marker 'network')
.\tasks.ps1 lint # ruff check
.\tasks.ps1 clean # remove cachesPare o daemon antes de
bootstrape desnapshot-criar/snapshot-restaurar(o daemon segura o lock do Qdrant).
Em Linux/macOS, o Makefile (com uv) expõe os mesmos alvos.
Agendamento (atualização semanal)
.\scripts\register_update_task.ps1 registra uma tarefa no Windows Task Scheduler (segunda, 03h) que roda scripts\weekly_update.ps1. O helper prefere o daemon (POST /update, reusando os modelos quentes) e cai para lex-rag-update --mode delta quando o daemon está fora do ar — evitando disputa pelo lock do Qdrant.
Registro no Claude Desktop / Claude Code
Com o corpus no lugar (snapshot ou bootstrap), registre o servidor MCP (stdio). Lembre-se de subir o daemon (.\tasks.ps1 serve ou daemon-start) antes de usar as ferramentas.
Claude Code (na pasta do projeto; o comando grava o caminho absoluto do .venv):
claude mcp add lex-rag -- "$PWD\.venv\Scripts\python.exe" -m lex_rag.mcp_server.serverclaude mcp add lex-rag -- "$PWD/.venv/bin/python" -m lex_rag.mcp_server.server # Linux/macOSClaude Desktop (%APPDATA%\Claude\claude_desktop_config.json), com o caminho absoluto do clone:
{
"mcpServers": {
"lex-rag": {
"command": "C:\\caminho\\para\\lex_rag\\.venv\\Scripts\\python.exe",
"args": ["-m", "lex_rag.mcp_server.server"]
}
}
}Ferramentas expostas: pesquisar_norma, buscar_por_assunto, obter_dispositivo, listar_alteracoes, health.
Estrutura
src/lex_rag/ingest/— descoberta (LexML), download (Planalto), parse, detecção de revogaçãosrc/lex_rag/index/— chunking, embedding, escrita no Qdrantsrc/lex_rag/retrieve/— busca híbrida, filtros, validação de groundingsrc/lex_rag/mcp_server/— tools MCP (cliente fino do daemon)src/lex_rag/service/— daemon de inferência (FastAPI) + cliente HTTPsrc/lex_rag/update/— pipeline incremental semanaldata/— Qdrant embedded + HTML cru + state SQLite (gitignored)
Status
Em desenvolvimento. Desenvolvido em Windows + GPU NVIDIA (CUDA); roda em CPU e, via Makefile, em Linux/macOS.
Licença
MIT — veja LICENSE. Os textos normativos indexados são de domínio público (Lei 9.610/1998, art. 8º, IV).
This server cannot be deployed
Maintenance
Related MCP Connectors
Busca e verifica jurisprudência brasileira real (+400 mil julgados) — anti-alucinação para IA.
Acervo jurídico brasileiro: busca, Markdown, grafo de normas e precedentes, citação verificável.
Case law search, court decisions and súmulas, across indexed public sources (STF, STJ, TST, state co
Open-source alternative to Jusbrasil for AI: find lawsuits by name, CPF, CNPJ or case number and bui
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA server implementing the Model Context Protocol to allow direct access to French legal resources (laws, codes, case law) from compatible Large Language Models like Claude, enabling interactive legal research through the Legifrance API.64MIT
- AlicenseNot gradedqualityDmaintenanceRAG-powered document search server that enables semantic search across large collections of legal and business documents (PDF, Word, Excel, PowerPoint) using local embeddings with no API costs.4MIT
- AlicenseAqualityBmaintenanceProvides offline access to the French legal corpus (Legifrance/DILA) with full-text search, verbatim article retrieval, and citation grounding to prevent hallucinations.422 npmMIT
- FlicenseNot gradedqualityBmaintenanceMCP server for handling large PDF legal documents (PJe, SEI) on macOS, providing local OCR, hybrid BM25+dense search, visual indexing, and citation validation.-