{
  "markdown": "<!-- mcp-name: io.github.atomno-mcp/mcp-egrul -->\n\n# mcp-egrul\n\nMCP-сервер ЕГРЮЛ и ЕГРИП: реквизиты российских компаний и ИП по открытым данным налоговой службы. Можно поставить у себя или подключить к Cursor, Claude и любому клиенту MCP.\n\nRussian company registry lookup for AI agents.\n\n[![Glama](https://img.shields.io/badge/Glama-listed-7c3aed.svg)](https://glama.ai/mcp/servers/atomno-mcp/mcp-egrul)\n\n<a href=\"https://glama.ai/mcp/servers/atomno-mcp/mcp-egrul\">\n  <img width=\"380\" height=\"200\" src=\"https://glama.ai/mcp/servers/atomno-mcp/mcp-egrul/badge\" alt=\"mcp-egrul MCP server\" />\n</a>\n\n**Статус:** `v0.1.2` — open-версия (self-host через SQLite) полностью готова + клиентская часть hosted Pro (HTTP-клиент `HostedClient` для `api.atomno-mcp.ru`). Опубликована на [PyPI](https://pypi.org/project/atomno-mcp-egrul/), индексирована в [Glama](https://glama.ai/mcp/servers) и [Smithery](https://smithery.ai/). Сама hosted Pro-инфра — в активной разработке. **Coverage `100.00%`** (345 тестов, ruff clean, fastmcp 3.2.4, enforced через `--cov-fail-under=100`).\n\n**Парный проект:** [`mcp-fns-check`](https://github.com/atomno-mcp/mcp-fns-check) (risk-чек-слой поверх ЕГРЮЛ).\n\n---\n\n## Что это\n\nСемь MCP-тулзов, видимых AI-ассистенту (Cursor, Claude Desktop, Cline, любой MCP-клиент):\n\n| Tool | Описание | Аргументы |\n|---|---|---|\n| `search_by_inn` | Поиск по ИНН (10 цифр — юр.лицо, 12 — ИП) | `inn: str` |\n| `search_by_ogrn` | Поиск по ОГРН (13) или ОГРНИП (15) | `ogrn: str` |\n| `search_by_name` | Fuzzy-поиск по названию (FTS5) | `query: str, limit?: int, only_active?: bool` |\n| `get_full_card` | Полная карточка со всеми секциями | `inn?: str, ogrn?: str` |\n| `get_founders` | Только учредители с долями | `inn: str` |\n| `get_director` | Только текущий руководитель | `inn: str` |\n| `bulk_cards` | Массовая проверка (до 100 ИНН) | `inns: list[str]` |\n\nПлюс диагностический `ping` для проверки что сервер жив.\n\nПолная спецификация payload'ов — в `src/mcp_egrul/schemas.py` (Pydantic-модели `CompanyCard`, `IECard`, `SearchResult`, `BulkResult`).\n\n---\n\n## Установка\n\n### Вариант 1 — через PyPI (рекомендуется для пользователей)\n\n```bash\n# Без локального clone — работает «из коробки»\nuvx atomno-mcp-egrul\n\n# Или установка глобально\npipx install atomno-mcp-egrul\natomno-mcp-egrul\n\n# Или классический pip в venv\npip install atomno-mcp-egrul\natomno-mcp-egrul\n```\n\n### Вариант 2 — dev-режим (для разработчиков)\n\nТребуется Python 3.11+ и [`uv`](https://docs.astral.sh/uv/) (быстрая замена pip, опционально).\n\n```bash\ngit clone https://github.com/atomno-mcp/mcp-egrul\ncd mcp-egrul\nuv venv\nuv pip install -e \".[dev]\"\n```\n\nАльтернативно через pip:\n\n```bash\npython -m venv .venv\n.venv/Scripts/activate    # Windows\n# source .venv/bin/activate  # Linux/macOS\npip install -e \".[dev]\"\n```\n\n---\n\n## Запуск\n\n```bash\natomno-mcp-egrul\n```\n\nТранспорт по умолчанию — **stdio** (стандартный ввод/вывод JSON-RPC). Подходит для подключения к Cursor / Claude Desktop / Claude Code.\n\n### Claude Desktop (`claude_desktop_config.json`)\n\n```json\n{\n  \"mcpServers\": {\n    \"egrul\": {\n      \"command\": \"uvx\",\n      \"args\": [\"atomno-mcp-egrul\"]\n    }\n  }\n}\n```\n\n### Cursor (`.cursor/mcp.json` в проекте или `~/.cursor/mcp.json` глобально)\n\n```json\n{\n  \"mcpServers\": {\n    \"egrul\": {\n      \"command\": \"uvx\",\n      \"args\": [\"atomno-mcp-egrul\"]\n    }\n  }\n}\n```\n\n> Если не используете `uv`, замените `\"command\": \"uvx\", \"args\": [\"atomno-mcp-egrul\"]` на `\"command\": \"atomno-mcp-egrul\"` (требует `pip install atomno-mcp-egrul` или `pipx install atomno-mcp-egrul`).\n\n---\n\n## Docker (self-host) — quick start\n\n```bash\n# 1. Скачайте дампы ФНС (acceptance на сайте ФНС — раз в жизни).\n#    Источники:\n#      ЕГРЮЛ — https://www.nalog.gov.ru/opendata/7707329152-egrul/\n#      ЕГРИП — https://www.nalog.gov.ru/opendata/7707329152-egrip/\n#    Положите их в структуру:\nmkdir -p dumps/egrul/2026-04-24 dumps/egrip/2026-04-24\ncp ~/Downloads/EGRUL_*.zip dumps/egrul/2026-04-24/\ncp ~/Downloads/EGRIP_*.zip dumps/egrip/2026-04-24/\n\n# 2. Первоначальный полный импорт (однократно, ~30-60 минут):\ndocker compose --profile import run --rm \\\n    mcp-egrul-import atomno-mcp-egrul-import --registry egrul --full\ndocker compose --profile import run --rm \\\n    mcp-egrul-import atomno-mcp-egrul-import --registry egrip --full\n\n# 3. Запустите сервер + фоновый cron-демон:\ndocker compose up -d\ndocker compose logs -f mcp-egrul-scheduler\n```\n\nЧерез ~10 минут после импорта все тулзы (`search_by_inn`, `search_by_name` и пр.) уже отвечают данными из локального слепка ФНС.\n\nСхема тома `/data` внутри контейнера:\n\n```\n/data/\n├── mcp_egrul_data.sqlite     # SQLite + FTS5\n└── dumps/                    # read-only монтируется из ./dumps\n    ├── egrul/\n    │   └── YYYY-MM-DD/*.zip\n    └── egrip/\n        └── YYYY-MM-DD/*.zip\n```\n\nCron-демон (`atomno-mcp-egrul-scheduler`) сам забирает самую свежую выгрузку после\nтого как вы положите её в `dumps/<registry>/<YYYY-MM-DD>/` — ночью в 03:00\nEurope/Moscow. Если ничего нового нет — job завершится с `nothing_to_import`\nи никаких лишних записей в `import_log` не сделает.\n\n---\n\n## Импорт дампов ФНС (ручной режим)\n\nИсточники:\n\n- **ЕГРЮЛ open-data:** `https://www.nalog.gov.ru/opendata/7707329152-egrul/`\n- **ЕГРИП open-data:** `https://www.nalog.gov.ru/opendata/7707329152-egrip/`\n\nФормат: суточные архивы XML в ZIP, ~15 ГБ на полный слепок. Юридически их\nнужно скачать **с сайта ФНС после acceptance лицензии** — сервер не качает\nархивы сам (строго).\n\nCLI:\n\n```bash\n# Полный первоначальный импорт (однократно):\natomno-mcp-egrul-import --registry egrul --full\natomno-mcp-egrul-import --registry egrip --full\n\n# Инкремент (cron / ручной): загружается только если появилась более\n# свежая YYYY-MM-DD-папка, чем последний успешный `import_log.source_dump_date`.\n# Если новее нет — exit-code 5 и сообщение `nothing_to_import`.\natomno-mcp-egrul-import --registry egrul --incremental\n\n# Фоновой cron-демон с ежедневным 03:00 MSK (вызывать вручную редко;\n# обычно запускается сервисом mcp-egrul-scheduler в docker-compose).\natomno-mcp-egrul-scheduler --run-now\n```\n\nExit-коды `atomno-mcp-egrul-import`:\n\n| Код | Значение |\n|---|---|\n| 0 | Импорт прошёл успешно |\n| 2 | Невалидный конфиг / аргумент CLI |\n| 4 | Ошибка ингеста (битый XML, нет каталога дампов, DB error) |\n| 5 | `nothing_to_import` — самая свежая дата уже в БД (инкремент) |\n\n---\n\n## Pro / hosted-режим (прокси на `api.atomno-mcp.ru`)\n\nКогда пользователь задаёт `ATOMNO_API_KEY`, **все семь тулзов** автоматически\nпроксируются на hosted Pro API (SPEC §5.4, §5.4.1). Локальный SQLite в этом\nрежиме не используется — hosted Pro даёт:\n\n- **Актуальные данные на сегодня** (без суточной задержки open-data дампа): прямой scrape `egrul.nalog.ru` + Dadata fallback на стороне сервера.\n- **Bulk-эндпойнт без rate-limit** (`POST /companies/bulk`) — один запрос вместо N локальных gather'ов.\n- **AI-summary карточки**, история изменений, поиск по ФИО директора (Pro-only тулзы — приезжают вместе с hosted-сервером в Phase 2, см. §5.4.1).\n\n**Цена**: Pro — $10/мес отдельно или $15/мес в паре с `mcp-fns-check` (bundle-ключ). Free tier: 30 запросов/день/IP без регистрации (SPEC §1).\n\n**Настройка в Cursor** (`.cursor/mcp.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"egrul\": {\n      \"command\": \"uvx\",\n      \"args\": [\"atomno-mcp-egrul\"],\n      \"env\": {\n        \"ATOMNO_API_KEY\": \"your-pro-key-here\"\n      }\n    }\n  }\n}\n```\n\n**Поведение и ошибки** — никакого silent fallback: если hosted API недоступен, клиент поднимает типизированное исключение, а не молча отдаёт данные из устаревшего локального дампа. Сопоставление HTTP ↔ MCP-код ошибки — в SPEC §5.4.1:\n\n| HTTP-ответ hosted API | Исключение клиента | `error.code` |\n|---|---|---|\n| 200 | — | — |\n| 400 | `ValidationError` | `invalid_input` |\n| 401 | `HostedAuthError` | `auth_required` |\n| 403 | `ProRequiredError` | `pro_required` |\n| 404 (code=not_found) | `NotFoundError` | `not_found` |\n| 404 (wrong route) | `SourceUnavailableError` | `source_unavailable` |\n| 413 | `BulkTooLargeError` | `bulk_too_large` |\n| 429 | `RateLimitedError` (+ `Retry-After`) | `rate_limit` |\n| 5xx | `SourceUnavailableError` | `source_unavailable` |\n| timeout / DNS fail | `SourceUnavailableError` (cause=`timeout`/`ConnectError`) | `source_unavailable` |\n\nВалидация ИНН/ОГРН остаётся **клиент-саид** (контрольные цифры проверяются до HTTP-запроса — экономия round-trip на битых идентификаторах).\n\n---\n\n## Конфигурация (переменные окружения)\n\n| Переменная | Описание | По умолчанию |\n|---|---|---|\n| `MCP_EGRUL_DB` | Путь к SQLite-файлу со слепком ЕГРЮЛ/ЕГРИП | `./mcp_egrul_data.sqlite` |\n| `MCP_EGRUL_USER_AGENT` | User-Agent HTTP-клиента | `mcp-egrul/0.1 (+https://github.com/atomno-mcp/mcp-egrul)` |\n| `MCP_EGRUL_HTTP_TIMEOUT` | Таймаут HTTP в секундах | `30` |\n| `MCP_EGRUL_DUMPS_DIR` | Каталог с дампами ФНС, структура `<dir>/<registry>/<YYYY-MM-DD>/*.zip` | `./dumps` |\n| `MCP_EGRUL_LOG_LEVEL` | Уровень логирования | `INFO` |\n| `TZ` | Таймзона для scheduler (cron 03:00) | `Europe/Moscow` |\n| `ATOMNO_API_KEY` | (Pro) ключ hosted-подписки — включает проксирование на `api.atomno-mcp.ru` | не задан |\n| `ATOMNO_API_BASE` | (Pro) базовый URL hosted-API | `https://api.atomno-mcp.ru/mcp-egrul/v1` |\n\nПример — см. `.env.example`.\n\n---\n\n## Структура\n\n```\napps/mcp-egrul/\n├── pyproject.toml\n├── LICENSE                             # MIT\n├── README.md                           # ЭТОТ ФАЙЛ\n├── Dockerfile\n├── docker-compose.yml\n├── .env.example\n├── .gitignore\n├── src/mcp_egrul/\n│   ├── __init__.py\n│   ├── server.py                       # FastMCP entrypoint, регистрация 7 тулзов + ping\n│   ├── context.py                      # ServiceContext (DI: SQLiteStore + HTTP-клиент)\n│   ├── config.py                       # Чтение env-vars в типизированные поля\n│   ├── constants.py                    # Все магические числа и enum'ы\n│   ├── validators.py                   # Контрольные цифры ИНН (10/12) и ОГРН (13/15)\n│   ├── schemas.py                      # Pydantic-модели CompanyCard/IECard/SearchResult/...\n│   ├── errors.py                       # McpEgrulError и подклассы\n│   ├── db/\n│   │   ├── __init__.py\n│   │   └── sqlite.py                   # Async-клиент (aiosqlite), init/query/upsert/search + import_log\n│   ├── sources/\n│   │   ├── __init__.py\n│   │   ├── base.py                     # Абстрактный интерфейс Source\n│   │   ├── opendata.py                 # ФНС open-data адаптер (read-local → SQLite upsert)\n│   │   ├── opendata_parser.py          # Потоковый lxml.iterparse парсер ЕГРЮЛ/ЕГРИП XML\n│   │   └── hosted_adapter.py           # HTTP-клиент hosted Pro API (SPEC §5.4.1)\n│   ├── tools/\n│   │   ├── __init__.py\n│   │   ├── search_by_inn.py\n│   │   ├── search_by_ogrn.py\n│   │   ├── search_by_name.py\n│   │   ├── get_full_card.py\n│   │   ├── get_founders.py\n│   │   ├── get_director.py\n│   │   └── bulk_cards.py\n│   └── scripts/\n│       ├── __init__.py\n│       ├── import_opendata.py          # CLI `atomno-mcp-egrul-import` (ручной / одноразовый)\n│       └── scheduler.py                # CLI `atomno-mcp-egrul-scheduler` (apscheduler cron 03:00 MSK)\n└── tests/\n    ├── __init__.py\n    ├── conftest.py\n    ├── fixtures/\n    │   ├── egrul_sample.xml            # Мини-ЕГРЮЛ (2 валидных + 1 skip на неизвестный статус)\n    │   └── egrip_sample.xml            # Мини-ЕГРИП (active + closed)\n    ├── test_validators.py\n    ├── test_schemas.py\n    ├── test_config.py                  # Config.from_env + _parse_float_env (валидация env)\n    ├── test_sqlite_store.py\n    ├── test_cards.py                   # _cards.py: parse_iso_date/datetime + build_*card\n    ├── test_server_ping.py             # FastMCP tool-layer + server.main()\n    ├── test_tools.py                   # 7 тулзов: happy-path + validation + not_found\n    ├── test_opendata_parser.py         # XML-парсер (zip, xml, skip-на-неизвестный-статус)\n    ├── test_opendata_source.py         # OpenDataSource.run_ingest (full/incremental)\n    ├── test_integration_import.py      # Полный цикл import → search → get_card\n    ├── test_import_cli.py              # CLI `atomno-mcp-egrul-import`\n    ├── test_scheduler_cli.py           # CLI `atomno-mcp-egrul-scheduler` + _run_scheduler\n    └── test_hosted_adapter.py          # HostedClient + маршрутизация тулзов (respx-моки)\n```\n\n---\n\n## Тесты\n\n```bash\npytest -v --cov=src/mcp_egrul\n```\n\nТекущий coverage: **100.00%** (`345 tests passed`, ruff clean, 1529 statements + 382 branches,\n**0 misses**). Enforced политикой `--cov-fail-under=100` — любая регрессия сломает CI. Тесты покрывают:\n\n* валидаторы ИНН/ОГРН/ОГРНИП (контрольные цифры);\n* `Config.from_env` + парсер float-env-переменных (валидация, а не silent fallback);\n* все 7 MCP-тулзов (happy-path + validation + not_found + bulk partial);\n* SQLite store + FTS5 + `import_log`;\n* XML-парсер ЕГРЮЛ/ЕГРИП (zip, xml, skip-запись с неизвестным статусом);\n* `OpenDataSource.run_ingest` (full/incremental/`nothing_to_import`);\n* полный интеграционный цикл `import fixture → search → get_card → bulk`;\n* обе CLI (`atomno-mcp-egrul-import`, `atomno-mcp-egrul-scheduler`) — регистрация cron-job'ов, парсинг\n  аргументов, `_run_daily_ingest` на all-happy/`nothing_to_import`/`McpEgrulError`, полный цикл\n  `_run_scheduler` с mock-ed `asyncio.Event`;\n* FastMCP tool-layer через `mcp.call_tool()` — сериализация ошибок в структурированные dict'ы,\n  `server.main()` с валидным и невалидным env;\n* `HostedClient` (hosted Pro API proxy) — happy-path всех 7 методов, все HTTP-ошибки из\n  SPEC §5.4.1 (401/403/404/413/429/5xx), timeout/ConnectError, невалидный JSON/payload от\n  сервера, клиентская валидация bulk, `async with`-контекст; плюс маршрутизация из тулзов\n  в hosted-режиме (при задан `ATOMNO_API_KEY` — запрос идёт в `api.atomno-mcp.ru`, не в SQLite,\n  валидация ИНН до HTTP);\n* edge-case'ы XML-парсера (75 отдельных unit-тестов на `_parse_company`/`_parse_ie`/\n  `_parse_share`/`_parse_director`/`_parse_founders`/address fallback'ы/legacy-атрибуты/\n  невалидные длины ИНН/ОГРН/КПП);\n* приватные helper'ы SQLite-стора (`_wrap`, `_prepare_row`, `_row_to_dict`, `_normalize_bm25`,\n  auto-init через `_ensure`, rejecting invalid `finish_import` статусов);\n* `ServiceContext` reentry-идемпотентность, `atexit`-cleanup, `Config.from_env` ValidationError\n  → exit-code 2 из `atomno-mcp-egrul-import` CLI.\n\nВнешние API **никогда не вызываются напрямую** из тестов — только через `respx` (HTTP-мокинг) и\nлокальные XML-фикстуры (`tests/fixtures/`).\n\n---\n\n## Безопасность и юридический статус\n\n- Все источники — **публично открытые данные ФНС** (ЕГРЮЛ / ЕГРИП open-datasets), распространение которых разрешено ФЗ «Об информации…» и ЕГРЮЛ-специфичными нормами (см. SPEC §8).\n- Юридические лица не подпадают под 152-ФЗ (О персональных данных).\n- ФИО физлиц-руководителей и учредителей публикуются самой ФНС в открытом реестре — пересылка этих данных легальна.\n- Никаких write-операций ни в один внешний API.\n- Секреты — только через переменные окружения, в репозитории — `.env.example` без значений.\n\n---\n\n## Дисклеймер\n\nСервис — **агрегатор и удобный интерфейс над публичными данными ФНС**. Не аффилирован с ФНС. Используется на ваш риск. Информация в ответах сервиса не является заменой полноценной юридической или финансовой оценки.\n\n---\n\n## Лицензия\n\nMIT. Файл `LICENSE` в корне папки.\n",
  "bytes": 15229,
  "sha": "aab194597b4dc096a44a5c08c6e8d4bc8d30f38bc84b8f6ed464521c6f311b73",
  "repo_slug": "atomno-mcp/mcp-egrul",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_atomno_mcp_mcp_egrul_1f492604/readme"
}