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):
| Herramienta | Descripción | Argumentos |
|---|---|---|
search_by_inn | Búsqueda por INN (10 dígitos — persona jurídica, 12 — empresario individual) | inn: str |
search_by_ogrn | Búsqueda por OGRN (13) u OGRNIP (15) | ogrn: str |
search_by_name | Búsqueda difusa por nombre (FTS5) | query: str, limit?: int, only_active?: bool |
get_full_card | Ficha completa con todas las secciones | inn?: str, ogrn?: str |
get_founders | Solo fundadores con participaciones | inn: str |
get_director | Solo el director actual | inn: str |
bulk_cards | Verificació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"(requierepip install atomno-mcp-egrulopipx 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ódigo | Significado |
|---|---|
| 0 | Importación exitosa |
| 2 | Configuración o argumento CLI no válido |
| 4 | Error de ingesta (XML dañado, directorio de dumps inexistente, error de BD) |
| 5 | nothing_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 hosted | Excepción del cliente | error.code |
|---|---|---|
| 200 | — | — |
| 400 | ValidationError | invalid_input |
| 401 | HostedAuthError | auth_required |
| 403 | ProRequiredError | pro_required |
| 404 (code=not_found) | NotFoundError | not_found |
| 404 (ruta incorrecta) | SourceUnavailableError | source_unavailable |
| 413 | BulkTooLargeError | bulk_too_large |
| 429 | RateLimitedError (+ Retry-After) | rate_limit |
| 5xx | SourceUnavailableError | source_unavailable |
| timeout / fallo DNS | SourceUnavailableError (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)
| Variable | Descripción | Por defecto |
|---|---|---|
MCP_EGRUL_DB | Ruta al archivo SQLite con la copia de EGRUL/EGRIP | ./mcp_egrul_data.sqlite |
MCP_EGRUL_USER_AGENT | User-Agent del cliente HTTP | mcp-egrul/0.1 (+https://github.com/atomno-mcp/mcp-egrul) |
MCP_EGRUL_HTTP_TIMEOUT | Timeout HTTP en segundos | 30 |
MCP_EGRUL_DUMPS_DIR | Directorio con dumps del FNS, estructura <dir>/<registry>/<YYYY-MM-DD>/*.zip | ./dumps |
MCP_EGRUL_LOG_LEVEL | Nivel de registro (logging) | INFO |
TZ | Zona 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.ru | no definido |
ATOMNO_API_BASE | (Pro) URL base del API hosted | https://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_ingesten all-happy/nothing_to_import/McpEgrulError, ciclo completo de_run_schedulerconasyncio.Eventsimulado; - 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, contextoasync with; además, enrutamiento desde las herramientas en modo hosted (cuando se defineATOMNO_API_KEY— la solicitud va aapi.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 estadosfinish_importinválidos); - idempotencia de reentrada
ServiceContext, limpiezaatexit,Config.from_envValidationError → código de salida 2 desde la CLIatomno-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.examplesin 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.