mcp-egrul

MCP-сервер для проверки контрагентов через egrul.nalog.ru: получение выписки ЕГРЮЛ/ЕГРИП по ИНН/ОГРН.

Documentación

mcp-egrul

Servidor MCP (Model Context Protocol — protocolo abierto para conectar asistentes de IA a herramientas externas) para trabajar con EGRUL (Registro Estatal Unificado de Personas Jurídicas de la Federación Rusa) y EGRIP (Registro Estatal Unificado de Empresarios Individuales). Fuente: dumps oficiales de open-data del Servicio Federal de Impuestos (FNS).

Estado: v0.1.2 — la versión open (self-host mediante SQLite) está completamente lista + la parte cliente de hosted Pro (cliente HTTP HostedClient para api.atomno-mcp.ru). Publicado en PyPI, indexado en Glama y Smithery. La propia infraestructura hosted Pro está en desarrollo activo. Cobertura 100.00% (345 pruebas, ruff limpio, fastmcp 3.2.4, aplicado mediante --cov-fail-under=100).

Proyecto complementario: mcp-fns-check (capa de verificación de riesgos sobre EGRUL).


Qué es

Siete herramientas MCP visibles para el asistente de IA (Cursor, Claude Desktop, Cline, cualquier cliente MCP):

HerramientaDescripciónArgumentos
search_by_innBúsqueda por INN (10 dígitos — persona jurídica, 12 — empresario individual)inn: str
search_by_ogrnBúsqueda por OGRN (13) u OGRNIP (15)ogrn: str
search_by_nameBúsqueda difusa por nombre (FTS5)query: str, limit?: int, only_active?: bool
get_full_cardFicha completa con todas las seccionesinn?: str, ogrn?: str
get_foundersSolo fundadores con participacionesinn: str
get_directorSolo el director actualinn: str
bulk_cardsVerificación masiva (hasta 100 INN)inns: list[str]

Además, una herramienta de diagnóstico ping para comprobar que el servidor está activo.

La especificación completa de los payloads está en src/mcp_egrul/schemas.py (modelos Pydantic CompanyCard, IECard, SearchResult, BulkResult).


Instalación

Opción 1 — mediante PyPI (recomendada para usuarios)

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

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

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

Opción 2 — modo desarrollo (para desarrolladores)

Se requiere Python 3.11+ y uv (alternativa rápida a pip, opcional).

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

Alternativamente mediante pip:

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

Ejecución

atomno-mcp-egrul

El transporte por defecto es stdio (entrada/salida estándar JSON-RPC). Adecuado para conectarse a Cursor / Claude Desktop / Claude Code.

Claude Desktop (claude_desktop_config.json)

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

Cursor (.cursor/mcp.json en el proyecto o ~/.cursor/mcp.json globalmente)

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

Si no usa uv, reemplace "command": "uvx", "args": ["atomno-mcp-egrul"] por "command": "atomno-mcp-egrul" (requiere pip install atomno-mcp-egrul o pipx install atomno-mcp-egrul).


Docker (self-host) — inicio 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

Aproximadamente 10 minutos después de la importación, todas las herramientas (search_by_inn, search_by_name, etc.) ya responden con datos de la copia local del FNS.

Esquema del volumen /data dentro del contenedor:

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

El demonio cron (atomno-mcp-egrul-scheduler) descarga automáticamente la extracción más reciente después de que usted la coloque en dumps/<registry>/<YYYY-MM-DD>/ — a las 03:00 Europe/Moscow. Si no hay nada nuevo, el job finaliza con nothing_to_import y no realiza registros innecesarios en import_log.


Importación de dumps del FNS (modo manual)

Fuentes:

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

Formato: archivos XML diarios en ZIP, ~15 GB por copia completa. Legalmente, deben descargarse del sitio web del FNS después de aceptar la licencia — el servidor no descarga los archivos por sí mismo (estrictamente).

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 salida atomno-mcp-egrul-import:

CódigoSignificado
0Importación exitosa
2Configuración o argumento CLI no válido
4Error de ingesta (XML dañado, directorio de dumps inexistente, error de BD)
5nothing_to_import — la fecha más reciente ya está en la BD (incremental)

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

Cuando el usuario configura ATOMNO_API_KEY, las siete herramientas se redirigen automáticamente al API hosted Pro (SPEC §5.4, §5.4.1). El SQLite local no se usa en este modo — hosted Pro ofrece:

  • Datos actualizados al día (sin el retraso diario del dump open-data): scraping directo de egrul.nalog.ru + fallback de Dadata en el servidor.
  • Endpoint bulk sin límite de tasa (POST /companies/bulk) — una sola solicitud en lugar de N recopilaciones locales.
  • Resumen de ficha con IA, historial de cambios, búsqueda por nombre completo del director (herramientas solo Pro — llegan con el servidor hosted en la Fase 2, ver §5.4.1).

Precio: Pro — $10/mes por separado o $15/mes junto con mcp-fns-check (clave bundle). Nivel gratuito: 30 solicitudes/día/IP sin registro (SPEC §1).

Configuración en Cursor (.cursor/mcp.json):

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

Comportamiento y errores — sin fallback silencioso: si el API hosted no está disponible, el cliente lanza una excepción tipada, en lugar de devolver silenciosamente datos del dump local desactualizado. Correspondencia de errores HTTP ↔ código MCP — en SPEC §5.4.1:

Respuesta HTTP del API hostedExcepción del clienteerror.code
200
400ValidationErrorinvalid_input
401HostedAuthErrorauth_required
403ProRequiredErrorpro_required
404 (code=not_found)NotFoundErrornot_found
404 (ruta incorrecta)SourceUnavailableErrorsource_unavailable
413BulkTooLargeErrorbulk_too_large
429RateLimitedError (+ Retry-After)rate_limit
5xxSourceUnavailableErrorsource_unavailable
timeout / fallo DNSSourceUnavailableError (cause=timeout/ConnectError)source_unavailable

La validación de INN/OGRN permanece del lado del cliente (los dígitos de control se verifican antes de la solicitud HTTP — ahorro de round-trip en identificadores inválidos).


Configuración (variables de entorno)

VariableDescripciónPor defecto
MCP_EGRUL_DBRuta al archivo SQLite con la copia de EGRUL/EGRIP./mcp_egrul_data.sqlite
MCP_EGRUL_USER_AGENTUser-Agent del cliente HTTPmcp-egrul/0.1 (+https://github.com/atomno-mcp/mcp-egrul)
MCP_EGRUL_HTTP_TIMEOUTTimeout HTTP en segundos30
MCP_EGRUL_DUMPS_DIRDirectorio con dumps del FNS, estructura <dir>/<registry>/<YYYY-MM-DD>/*.zip./dumps
MCP_EGRUL_LOG_LEVELNivel de registro (logging)INFO
TZZona horaria para el scheduler (cron 03:00)Europe/Moscow
ATOMNO_API_KEY(Pro) clave de suscripción hosted — habilita el proxy a api.atomno-mcp.runo definido
ATOMNO_API_BASE(Pro) URL base del API hostedhttps://api.atomno-mcp.ru/mcp-egrul/v1

Ejemplo — ver .env.example.


Estructura

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-моки)

Pruebas

pytest -v --cov=src/mcp_egrul

Cobertura actual: 100.00% (345 tests passed, ruff limpio, 1529 sentencias + 382 ramas, 0 fallos). Aplicada por la política --cov-fail-under=100 — cualquier regresión romperá el CI. Las pruebas cubren:

  • validadores de INN/OGRN/OGRNIP (dígitos de control);
  • Config.from_env + analizador de variables float-env (validación, no fallback silencioso);
  • las 7 herramientas MCP (happy-path + validación + not_found + bulk parcial);
  • almacenamiento SQLite + FTS5 + import_log;
  • analizador XML de EGRUL/EGRIP (zip, xml, registro omitido con estado desconocido);
  • OpenDataSource.run_ingest (completo/incremental/nothing_to_import);
  • ciclo de integración completo import fixture → search → get_card → bulk;
  • ambas CLI (atomno-mcp-egrul-import, atomno-mcp-egrul-scheduler) — registro de cron-jobs, análisis de argumentos, _run_daily_ingest en all-happy/nothing_to_import/McpEgrulError, ciclo completo de _run_scheduler con asyncio.Event simulado;
  • capa de herramientas FastMCP mediante mcp.call_tool() — serialización de errores en dicts estructurados, server.main() con env válido e inválido;
  • HostedClient (proxy del API hosted Pro) — happy-path de los 7 métodos, todos los errores HTTP de la SPEC §5.4.1 (401/403/404/413/429/5xx), timeout/ConnectError, JSON/payload inválido del servidor, validación de bulk en el cliente, contexto async with; además, enrutamiento desde las herramientas en modo hosted (cuando se define ATOMNO_API_KEY — la solicitud va a api.atomno-mcp.ru, no a SQLite, validación de INN antes del HTTP);
  • casos límite del analizador XML (75 pruebas unitarias individuales para _parse_company/_parse_ie/_parse_share/_parse_director/_parse_founders/fallbacks de dirección/atributos legacy/longitudes inválidas de INN/OGRN/KPP);
  • helpers privados del almacenamiento SQLite (_wrap, _prepare_row, _row_to_dict, _normalize_bm25, auto-init mediante _ensure, rechazo de estados finish_import inválidos);
  • idempotencia de reentrada ServiceContext, limpieza atexit, Config.from_env ValidationError → código de salida 2 desde la CLI atomno-mcp-egrul-import.

Las API externas nunca se llaman directamente desde las pruebas — solo mediante respx (simulación HTTP) y fixtures XML locales (tests/fixtures/).


Seguridad y estado legal

  • Todas las fuentes son datos públicos abiertos del FNS (conjuntos de datos abiertos EGRUL / EGRIP), cuya distribución está permitida por la ley federal «Sobre la información…» y las normas específicas de EGRUL (ver SPEC §8).
  • Las personas jurídicas no están sujetas a la ley federal 152-FZ (sobre datos personales).
  • Los nombres completos de directores y fundadores (personas físicas) son publicados por el propio FNS en el registro abierto — la reenvío de estos datos es legal.
  • Sin operaciones de escritura en ninguna API externa.
  • Secretos — solo mediante variables de entorno; en el repositorio — .env.example sin valores.

Aviso legal

El servicio es un agregador e interfaz conveniente sobre los datos públicos del FNS. No está afiliado al FNS. Se utiliza bajo su propio riesgo. La información en las respuestas del servicio no sustituye una evaluación legal o financiera completa.


Licencia

MIT. Archivo LICENSE en la raíz de la carpeta.