mcp-egrul

MCP-servidor para verificação de contrapartes via egrul.nalog.ru: obtenção de extrato EGRUL/EGRIP por INN/OGRN.

Documentação

mcp-egrul

Servidor MCP (Model Context Protocol — protocolo aberto para conectar assistentes de IA a ferramentas externas) para trabalhar com EGRUL (Registro Estadual Unificado de Pessoas Jurídicas da RF) e EGRIP (Registro Estadual Unificado de Empreendedores Individuais). Fonte — dumps oficiais de open-data da FNS (Serviço Fiscal Federal).

Status: v0.1.2 — versão open (self-host via SQLite) totalmente pronta + parte cliente do hosted Pro (cliente HTTP HostedClient para api.atomno-mcp.ru). Publicado no PyPI, indexado no Glama e Smithery. A própria infraestrutura hosted Pro — em desenvolvimento ativo. Cobertura 100.00% (345 testes, ruff limpo, fastmcp 3.2.4, aplicado via --cov-fail-under=100).

Projeto parceiro: mcp-fns-check (camada de verificação de risco sobre EGRUL).


O que é

Sete ferramentas MCP, visíveis ao assistente de IA (Cursor, Claude Desktop, Cline, qualquer cliente MCP):

FerramentaDescriçãoArgumentos
search_by_innBusca por INN (10 dígitos — pessoa jurídica, 12 — empreendedor individual)inn: str
search_by_ogrnBusca por OGRN (13) ou OGRNIP (15)ogrn: str
search_by_nameBusca difusa por nome (FTS5)query: str, limit?: int, only_active?: bool
get_full_cardCartão completo com todas as seçõesinn?: str, ogrn?: str
get_foundersApenas fundadores com participaçõesinn: str
get_directorApenas o diretor atualinn: str
bulk_cardsVerificação em massa (até 100 INN)inns: list[str]

Além disso, o ping de diagnóstico para verificar se o servidor está ativo.

Especificação completa dos payloads — em src/mcp_egrul/schemas.py (modelos Pydantic CompanyCard, IECard, SearchResult, BulkResult).


Instalação

Opção 1 — via PyPI (recomendado para usuários)

# Без локального clone — работает «из коробки»
uvx atomno-mcp-egrul

# Или установка глобально
pipx install atomno-mcp-egrul
atomno-mcp-egrul

# Или классический pip в venv
pip install atomno-mcp-egrul
atomno-mcp-egrul

Opção 2 — modo dev (para desenvolvedores)

Requer Python 3.11+ e uv (substituto rápido para pip, opcional).

git clone https://github.com/atomno-mcp/mcp-egrul
cd mcp-egrul
uv venv
uv pip install -e ".[dev]"

Alternativamente via pip:

python -m venv .venv
.venv/Scripts/activate    # Windows
# source .venv/bin/activate  # Linux/macOS
pip install -e ".[dev]"

Execução

atomno-mcp-egrul

Transporte padrão — stdio (entrada/saída padrão JSON-RPC). Adequado para conectar ao Cursor / Claude Desktop / Claude Code.

Claude Desktop (claude_desktop_config.json)

{
  "mcpServers": {
    "egrul": {
      "command": "uvx",
      "args": ["atomno-mcp-egrul"]
    }
  }
}

Cursor (.cursor/mcp.json no projeto ou ~/.cursor/mcp.json globalmente)

{
  "mcpServers": {
    "egrul": {
      "command": "uvx",
      "args": ["atomno-mcp-egrul"]
    }
  }
}

Se você não usa uv, substitua "command": "uvx", "args": ["atomno-mcp-egrul"] por "command": "atomno-mcp-egrul" (requer pip install atomno-mcp-egrul ou pipx install atomno-mcp-egrul).


Docker (self-host) — início rápido

# 1. Скачайте дампы ФНС (acceptance на сайте ФНС — раз в жизни).
#    Источники:
#      ЕГРЮЛ — https://www.nalog.gov.ru/opendata/7707329152-egrul/
#      ЕГРИП — https://www.nalog.gov.ru/opendata/7707329152-egrip/
#    Положите их в структуру:
mkdir -p dumps/egrul/2026-04-24 dumps/egrip/2026-04-24
cp ~/Downloads/EGRUL_*.zip dumps/egrul/2026-04-24/
cp ~/Downloads/EGRIP_*.zip dumps/egrip/2026-04-24/

# 2. Первоначальный полный импорт (однократно, ~30-60 минут):
docker compose --profile import run --rm \
    mcp-egrul-import atomno-mcp-egrul-import --registry egrul --full
docker compose --profile import run --rm \
    mcp-egrul-import atomno-mcp-egrul-import --registry egrip --full

# 3. Запустите сервер + фоновый cron-демон:
docker compose up -d
docker compose logs -f mcp-egrul-scheduler

Após ~10 minutos da importação, todas as ferramentas (search_by_inn, search_by_name etc.) já respondem com dados do snapshot local da FNS.

Esquema do volume /data dentro do contêiner:

/data/
├── mcp_egrul_data.sqlite     # SQLite + FTS5
└── dumps/                    # read-only монтируется из ./dumps
    ├── egrul/
    │   └── YYYY-MM-DD/*.zip
    └── egrip/
        └── YYYY-MM-DD/*.zip

O daemon cron (atomno-mcp-egrul-scheduler) baixa automaticamente a exportação mais recente depois que você a coloca em dumps/<registry>/<YYYY-MM-DD>/ — à noite às 03:00 Europe/Moscow. Se não houver nada novo — o job termina com nothing_to_import e não faz nenhum registro extra em import_log.


Importação de dumps da FNS (modo manual)

Fontes:

  • EGRUL open-data: https://www.nalog.gov.ru/opendata/7707329152-egrul/
  • EGRIP open-data: https://www.nalog.gov.ru/opendata/7707329152-egrip/

Formato: arquivos XML diários em ZIP, ~15 GB para um snapshot completo. Legalmente, eles precisam ser baixados do site da FNS após aceitar a licença — o servidor não baixa os arquivos por conta própria (estritamente).

CLI:

# Полный первоначальный импорт (однократно):
atomno-mcp-egrul-import --registry egrul --full
atomno-mcp-egrul-import --registry egrip --full

# Инкремент (cron / ручной): загружается только если появилась более
# свежая YYYY-MM-DD-папка, чем последний успешный `import_log.source_dump_date`.
# Если новее нет — exit-code 5 и сообщение `nothing_to_import`.
atomno-mcp-egrul-import --registry egrul --incremental

# Фоновой cron-демон с ежедневным 03:00 MSK (вызывать вручную редко;
# обычно запускается сервисом mcp-egrul-scheduler в docker-compose).
atomno-mcp-egrul-scheduler --run-now

Códigos de saída atomno-mcp-egrul-import:

CódigoSignificado
0Importação concluída com sucesso
2Configuração / argumento CLI inválido
4Erro de ingestão (XML corrompido, diretório de dumps ausente, erro de banco de dados)
5nothing_to_import — a data mais recente já está no banco de dados (incremental)

Modo Pro / hosted (proxy para api.atomno-mcp.ru)

Quando o usuário define ATOMNO_API_KEY, todas as sete ferramentas são automaticamente proxadas para a API hosted Pro (SPEC §5.4, §5.4.1). O SQLite local neste modo não é usado — o hosted Pro oferece:

  • Dados atualizados para hoje (sem o atraso diário do dump open-data): scrape direto egrul.nalog.ru + fallback Dadata no lado do servidor.
  • Endpoint bulk sem rate-limit (POST /companies/bulk) — uma única requisição em vez de N coletas locais.
  • Resumo de cartão com IA, histórico de alterações, busca por nome do diretor (ferramentas exclusivas do Pro — chegam junto com o servidor hosted na Fase 2, veja §5.4.1).

Preço: Pro — US$ 10/mês separadamente ou US$ 15/mês em conjunto com mcp-fns-check (chave bundle). Nível gratuito: 30 requisições/dia/IP sem registro (SPEC §1).

Configuração no Cursor (.cursor/mcp.json):

{
  "mcpServers": {
    "egrul": {
      "command": "uvx",
      "args": ["atomno-mcp-egrul"],
      "env": {
        "ATOMNO_API_KEY": "your-pro-key-here"
      }
    }
  }
}

Comportamento e erros — sem fallback silencioso: se a API hosted estiver indisponível, o cliente levanta uma exceção tipada, em vez de silenciosamente retornar dados do dump local desatualizado. Mapeamento de erro HTTP ↔ código MCP — na SPEC §5.4.1:

Resposta HTTP da API hostedExceção do clienteerror.code
200
400ValidationErrorinvalid_input
401HostedAuthErrorauth_required
403ProRequiredErrorpro_required
404 (code=not_found)NotFoundErrornot_found
404 (rota errada)SourceUnavailableErrorsource_unavailable
413BulkTooLargeErrorbulk_too_large
429RateLimitedError (+ Retry-After)rate_limit
5xxSourceUnavailableErrorsource_unavailable
timeout / falha de DNSSourceUnavailableError (cause=timeout/ConnectError)source_unavailable

A validação de INN/OGRN permanece no lado do cliente (os dígitos de verificação são validados antes da requisição HTTP — economia de round-trip em identificadores inválidos).


Configuração (variáveis de ambiente)

VariávelDescriçãoPadrão
MCP_EGRUL_DBCaminho para o arquivo SQLite com o snapshot EGRUL/EGRIP./mcp_egrul_data.sqlite
MCP_EGRUL_USER_AGENTUser-Agent do cliente HTTPmcp-egrul/0.1 (+https://github.com/atomno-mcp/mcp-egrul)
MCP_EGRUL_HTTP_TIMEOUTTimeout HTTP em segundos30
MCP_EGRUL_DUMPS_DIRDiretório com dumps da FNS, estrutura <dir>/<registry>/<YYYY-MM-DD>/*.zip./dumps
MCP_EGRUL_LOG_LEVELNível de logINFO
TZFuso horário para o agendador (cron 03:00)Europe/Moscow
ATOMNO_API_KEY(Pro) chave da assinatura hosted — ativa o proxy para api.atomno-mcp.runão definido
ATOMNO_API_BASE(Pro) URL base da API hostedhttps://api.atomno-mcp.ru/mcp-egrul/v1

Exemplo — veja .env.example.


Estrutura

apps/mcp-egrul/
├── pyproject.toml
├── LICENSE                             # MIT
├── README.md                           # ЭТОТ ФАЙЛ
├── Dockerfile
├── docker-compose.yml
├── .env.example
├── .gitignore
├── src/mcp_egrul/
│   ├── __init__.py
│   ├── server.py                       # FastMCP entrypoint, регистрация 7 тулзов + ping
│   ├── context.py                      # ServiceContext (DI: SQLiteStore + HTTP-клиент)
│   ├── config.py                       # Чтение env-vars в типизированные поля
│   ├── constants.py                    # Все магические числа и enum'ы
│   ├── validators.py                   # Контрольные цифры ИНН (10/12) и ОГРН (13/15)
│   ├── schemas.py                      # Pydantic-модели CompanyCard/IECard/SearchResult/...
│   ├── errors.py                       # McpEgrulError и подклассы
│   ├── db/
│   │   ├── __init__.py
│   │   └── sqlite.py                   # Async-клиент (aiosqlite), init/query/upsert/search + import_log
│   ├── sources/
│   │   ├── __init__.py
│   │   ├── base.py                     # Абстрактный интерфейс Source
│   │   ├── opendata.py                 # ФНС open-data адаптер (read-local → SQLite upsert)
│   │   ├── opendata_parser.py          # Потоковый lxml.iterparse парсер ЕГРЮЛ/ЕГРИП XML
│   │   └── hosted_adapter.py           # HTTP-клиент hosted Pro API (SPEC §5.4.1)
│   ├── tools/
│   │   ├── __init__.py
│   │   ├── search_by_inn.py
│   │   ├── search_by_ogrn.py
│   │   ├── search_by_name.py
│   │   ├── get_full_card.py
│   │   ├── get_founders.py
│   │   ├── get_director.py
│   │   └── bulk_cards.py
│   └── scripts/
│       ├── __init__.py
│       ├── import_opendata.py          # CLI `atomno-mcp-egrul-import` (ручной / одноразовый)
│       └── scheduler.py                # CLI `atomno-mcp-egrul-scheduler` (apscheduler cron 03:00 MSK)
└── tests/
    ├── __init__.py
    ├── conftest.py
    ├── fixtures/
    │   ├── egrul_sample.xml            # Мини-ЕГРЮЛ (2 валидных + 1 skip на неизвестный статус)
    │   └── egrip_sample.xml            # Мини-ЕГРИП (active + closed)
    ├── test_validators.py
    ├── test_schemas.py
    ├── test_config.py                  # Config.from_env + _parse_float_env (валидация env)
    ├── test_sqlite_store.py
    ├── test_cards.py                   # _cards.py: parse_iso_date/datetime + build_*card
    ├── test_server_ping.py             # FastMCP tool-layer + server.main()
    ├── test_tools.py                   # 7 тулзов: happy-path + validation + not_found
    ├── test_opendata_parser.py         # XML-парсер (zip, xml, skip-на-неизвестный-статус)
    ├── test_opendata_source.py         # OpenDataSource.run_ingest (full/incremental)
    ├── test_integration_import.py      # Полный цикл import → search → get_card
    ├── test_import_cli.py              # CLI `atomno-mcp-egrul-import`
    ├── test_scheduler_cli.py           # CLI `atomno-mcp-egrul-scheduler` + _run_scheduler
    └── test_hosted_adapter.py          # HostedClient + маршрутизация тулзов (respx-моки)

Testes

pytest -v --cov=src/mcp_egrul

Cobertura atual: 100.00% (345 tests passed, ruff limpo, 1529 declarações + 382 ramos, 0 falhas). Aplicado pela política --cov-fail-under=100 — qualquer regressão quebrará o CI. Os testes cobrem:

  • validadores de INN/OGRN/OGRNIP (dígitos de verificação);
  • Config.from_env + parser de variáveis float-env (validação, não fallback silencioso);
  • todas as 7 ferramentas MCP (caminho feliz + validação + not_found + bulk parcial);
  • armazenamento SQLite + FTS5 + import_log;
  • parser XML EGRUL/EGRIP (zip, xml, registro ignorado com status desconhecido);
  • OpenDataSource.run_ingest (completo/incremental/nothing_to_import);
  • ciclo de integração completo import fixture → search → get_card → bulk;
  • ambas as CLIs (atomno-mcp-egrul-import, atomno-mcp-egrul-scheduler) — registro de jobs cron, parsing de argumentos, _run_daily_ingest em all-happy/nothing_to_import/McpEgrulError, ciclo completo _run_scheduler com asyncio.Event simulado;
  • camada de ferramentas FastMCP via mcp.call_tool() — serialização de erros em dicts estruturados, server.main() com env válido e inválido;
  • HostedClient (proxy da API hosted Pro) — caminho feliz de todos os 7 métodos, todos os erros HTTP da SPEC §5.4.1 (401/403/404/413/429/5xx), timeout/ConnectError, JSON/payload inválido do servidor, validação bulk no cliente, contexto async with; além do roteamento das ferramentas no modo hosted (quando ATOMNO_API_KEY está definido — a requisição vai para api.atomno-mcp.ru, não para o SQLite, validação de INN antes do HTTP);
  • casos extremos do parser XML (75 testes unitários separados em _parse_company/_parse_ie/ _parse_share/_parse_director/_parse_founders/fallbacks de endereço/atributos legados/ comprimentos inválidos de INN/OGRN/KPP);
  • helpers privados do armazenamento SQLite (_wrap, _prepare_row, _row_to_dict, _normalize_bm25, auto-init via _ensure, rejeitando status finish_import inválidos);
  • idempotência de reentrada ServiceContext, limpeza atexit, Config.from_env ValidationError → código de saída 2 da CLI atomno-mcp-egrul-import.

APIs externas nunca são chamadas diretamente nos testes — apenas via respx (mock HTTP) e fixtures XML locais (tests/fixtures/).


Segurança e status legal

  • Todas as fontes — dados publicamente abertos da FNS (open-datasets EGRUL / EGRIP), cuja distribuição é permitida pela Lei Federal "Sobre Informação…" e normas específicas do EGRUL (veja SPEC §8).
  • Pessoas jurídicas não se enquadram na 152-FZ (Sobre Dados Pessoais).
  • Nomes de diretores e fundadores pessoas físicas são publicados pela própria FNS no registro aberto — o repasse desses dados é legal.
  • Nenhuma operação de escrita em qualquer API externa.
  • Segredos — apenas via variáveis de ambiente, no repositório — .env.example sem valores.

Aviso legal

O serviço é um agregador e interface conveniente sobre dados públicos da FNS. Não é afiliado à FNS. Use por sua conta e risco. As informações nas respostas do serviço não substituem uma avaliação jurídica ou financeira completa.


Licença

MIT. Arquivo LICENSE na raiz da pasta.