mcp-egrul
Servidor MCP para verificar contrapartes a través de egrul.nalog.ru: obtención de extracto EGRUL/EGRIP por INN/OGRN.
Documentación
mcp-egrul
Servidor MCP de ЕГРЮЛ y ЕГРИП: datos de empresas e IP rusas según datos abiertos del servicio fiscal. Puedes instalarlo localmente o conectarlo a Cursor, Claude y cualquier cliente MCP.
Búsqueda en el registro de empresas ruso para agentes de IA.
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 clean, fastmcp 3.2.4, aplicado mediante --cov-fail-under=100).
Proyecto complementario: mcp-fns-check (capa de verificación de riesgos sobre ЕГРЮЛ).
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 — IP) | 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 dev (para desarrolladores)
Se requiere Python 3.11+ y uv (sustituto rápido de 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 usas
uv, reemplaza"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 de la ФНС.
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 exportación más reciente después de que la coloques 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 adicionales en import_log.
Importación de dumps de la ФНС (modo manual)
Fuentes:
- ЕГРЮЛ open-data:
https://www.nalog.gov.ru/opendata/7707329152-egrul/ - ЕГРИП open-data:
https://www.nalog.gov.ru/opendata/7707329152-egrip/
Formato: archivos XML diarios en ZIP, ~15 GB por copia completa. Legalmente deben descargarse desde el sitio web de la ФНС 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 | La importación se completó correctamente |
| 2 | Configuración o argumento CLI no válido |
| 4 | Error de ingesta (XML dañado, no existe el directorio de dumps, error de BD) |
| 5 | nothing_to_import — la fecha más reciente ya está en la BD (incremental) |
Modo Pro / hosted (proxy hacia api.atomno-mcp.ru)
Cuando el usuario establece 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 de hoy (sin el retraso diario del dump open-data): scraping directo de
egrul.nalog.ru+ fallback de Dadata en el lado del servidor. - Endpoint bulk sin rate-limit (
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 Pro-only — llegan junto 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 entre HTTP ↔ código de error 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 de 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 ЕГРЮЛ/ЕГРИП | ./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 de la ФНС, estructura <dir>/<registry>/<YYYY-MM-DD>/*.zip | ./dumps |
MCP_EGRUL_LOG_LEVEL | Nivel de logging | INFO |
TZ | Zona horaria para el scheduler (cron 03:00) | Europe/Moscow |
ATOMNO_API_KEY | (Pro) clave de suscripción hosted — activa el proxy hacia api.atomno-mcp.ru | no definida |
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 clean, 1529 sentencias + 382 ramas, 0 fallos). Aplicada mediante 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+ parser de variables float-env (validación, no fallback silencioso);- las 7 herramientas MCP (happy-path + validación + not_found + bulk parcial);
- store SQLite + FTS5 +
import_log; - parser XML de ЕГРЮЛ/ЕГРИП (zip, xml, salto de registro con estado desconocido);
OpenDataSource.run_ingest(full/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, parseo 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 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 de HTTP);- casos límite del parser XML (75 unit-tests separados sobre
_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 store 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 (mockeo HTTP) y fixtures XML locales (tests/fixtures/).
Seguridad y estatus legal
- Todas las fuentes son datos públicos de la ФНС (datasets abiertos de ЕГРЮЛ / ЕГРИП), cuya distribución está permitida por la ley federal «Sobre la información…» y las normas específicas de ЕГРЮЛ (ver SPEC §8).
- Las personas jurídicas no están sujetas a la 152-FZ (Sobre datos personales).
- Los nombres completos de directores y fundadores personas físicas son publicados por la propia ФНС en el registro abierto — la transmisión 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 de la ФНС. No está afiliado con la ФНС. Se utiliza bajo tu propio riesgo. La información en las respuestas del servicio no sustituye una evaluación jurídica o financiera completa.
Licencia
MIT. Archivo LICENSE en la raíz de la carpeta.