内容
<!-- mcp-name: io.github.atomno-mcp/mcp-egrul -->
# mcp-egrul
> **MCP 服务器(模型上下文协议)**,用于与 **AI 助手** 连接到外部工具,以与 **统一国家法律实体注册簿(ЕГРЮЛ)** 和 **统一国家个体创业者注册簿(ЕГРИП)** 进行交互。数据源来自 **俄罗斯联邦税务局(ФНС)** 的官方开放数据转储。
**状态:** `v0.1.2` — 开放版本(自托管,通过 SQLite)已完全准备就绪 + 客户端托管专业版(`HostedClient` HTTP 客户端,用于 `api.atomno-mcp.ru`)。已发布到 [PyPI](https://pypi.org/project/atomno-mcp-egrul/),索引到 [Glama](https://glama.ai/mcp/servers) 和 [Smithery](https://smithery.ai/)。托管专业版基础设施正在积极开发中。**覆盖率 `100.00%`**(345 个测试,ruff clean,fastmcp 3.2.4,通过 `--cov-fail-under=100` 强制执行)。
**配套项目:** [`mcp-fns-check`](https://github.com/atomno-mcp/mcp-fns-check) (基于 ЕГРЮЛ的风险检查层)。
---
## 什么是 mcp-egrul
七种 MCP 工具,可见于 AI 助手(Cursor,Claude Desktop,Cline,任何 MCP 客户端):
| 工具 | 描述 | 参数 |
|---|---|---|
| `search_by_inn` | 按 **税务识别号(ИНН)** 搜索(10 位数字 - 法人,12 位 - 个体经营者) | `inn: str` |
| `search_by_ogrn` | 按 **主要工商注册号(ОГРН)** 或 **个体经营者注册号(ОГРНИП)** 搜索(13 位或 15 位) | `ogrn: str` |
| `search_by_name` | 按名称模糊搜索(FTS5) | `query: str, limit?: int, only_active?: bool` |
| `get_full_card` | 带有所有部分的完整卡片 | `inn?: str, ogrn?: str` |
| `get_founders` | 仅创始人与股份 | `inn: str` |
| `get_director` | 仅当前负责人 | `inn: str` |
| `bulk_cards` | 批量检查(最多 100 个税务识别号) | `inns: list[str]` |
此外,还有一个用于检查服务器是否存活的诊断 `ping` 工具。
完整的数据有效载荷规范在 `src/mcp_egrul/schemas.py` 中(Pydantic 模型 `CompanyCard`、`IECard`、`SearchResult`、`BulkResult`)。
---
## 安装
### 方式 1 - 通过 PyPI(推荐用户)
```bash
# 无本地克隆 - 直接运行
uvx atomno-mcp-egrul
# 或全局安装
pipx install atomno-mcp-egrul
atomno-mcp-egrul
# 或在虚拟环境中使用经典 pip
pip install atomno-mcp-egrul
atomno-mcp-egrul
```
### 方式 2 - 开发模式(适用于开发者)
需要 Python 3.11+ 和 [`uv`](https://docs.astral.sh/uv/) (快速替代 pip,可选)。
```bash
git clone https://github.com/atomno-mcp/mcp-egrul
cd mcp-egrul
uv venv
uv pip install -e ".[dev]"
```
或者使用 pip:
```bash
python -m venv .venv
.venv/Scripts/activate # Windows
# source .venv/bin/activate # Linux/macOS
pip install -e ".[dev]"
```
---
## 运行
```bash
atomno-mcp-egrul
```
默认传输方式为 **标准输入/输出(stdio)** (JSON-RPC)。适用于连接到 Cursor / Claude Desktop / Claude Code。
### Claude Desktop (`claude_desktop_config.json`)
```json
{
"mcpServers": {
"egrul": {
"command": "uvx",
"args": ["atomno-mcp-egrul"]
}
}
}
```
### Cursor (`.cursor/mcp.json` 在项目中或 `~/.cursor/mcp.json` 在全局)
```json
{
"mcpServers": {
"egrul": {
"command": "uvx",
"args": ["atomno-mcp-egrul"]
}
}
}
```
> 如果您不使用 `uv`,请将 `"command": "uvx", "args": ["atomno-mcp-egrul"]` 替换为 `"command": "atomno-mcp-egrul"` (需要 `pip install atomno-mcp-egrul` 或 `pipx install atomno-mcp-egrul`)。
---
## Docker(自托管)- 快速入门
```bash
# 1. 下载税务局的数据转储(在税务局网站上接受许可后,每生一次)。
# 来源:
# ЕГРЮЛ - 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
```
容器内 `/data` 卷的结构:
```
/data/
├── mcp_egrul_data.sqlite # SQLite + FTS5
└── dumps/ # 只读挂载到 ./dumps
├── egrul/
│ └── YYYY-MM-DD/*.zip
└── egrip/
└── YYYY-MM-DD/*.zip
```
cron 守护进程(`atomno-mcp-egrul-scheduler`)会在您将新数据转储放入 `dumps/<registry>/<YYYY-MM-DD>/` 后自动获取最新的数据转储 - 在凌晨 03:00 Europe/Moscow 时区。如果没有新数据,作业将以 `nothing_to_import` 完成,不会在 `import_log` 中创建任何额外的记录。
---
## 手动导入税务局数据转储
来源:
- ** ЕГРЮЛ 开放数据:** `https://www.nalog.gov.ru/opendata/7707329152-egrul/`
- ** ЕГРИП 开放数据:** `https://www.nalog.gov.ru/opendata/7707329152-egrip/`
格式:每日 XML 存档的 ZIP 文件,约 15 GB 每个完整快照。依法,您需要从税务局网站下载 **接受许可** 后才能下载这些文件 - 服务器不会自行下载存档(严格)。
CLI:
```bash
# 完整初始导入(一次性):
atomno-mcp-egrul-import --registry egrul --full
atomno-mcp-egrul-import --registry egrip --full
# 增量导入(cron / 手动):只加载如果有更新的 YYYY-MM-DD 文件夹比最后成功的 `import_log.source_dump_date` 新。
# 如果没有更新 - 退出代码 5 和 `nothing_to_import` 消息。
atomno-mcp-egrul-import --registry egrul --incremental
# 后台 cron 守护进程,带每日 03:00 MSK(手动调用很少;
# 通常由 docker-compose 中的 mcp-egrul-scheduler 服务启动)。
atomno-mcp-egrul-scheduler --run-now
```
`atomno-mcp-egrul-import` 的退出代码:
| 代码 | 含义 |
|---|---|
| 0 | 导入成功 |
| 2 | 无效配置 / CLI 参数 |
| 4 | 摄入错误(损坏的 XML,无 dump 目录,DB 错误) |
| 5 | `nothing_to_import` - 最新日期已经在数据库中(增量) |
---
## 专业版 / 托管模式(`api.atomno-mcp.ru` 代理)
当用户设置 `ATOMNO_API_KEY` 时,**所有七种工具** 自动代理到托管专业版 API(SPEC §5.4,§5.4.1)。本地 SQLite 不在此模式下使用 - 托管专业版提供:
- **今日最新数据** (无开放数据转储的每日延迟):直接爬取 `egrul.nalog.ru` + 服务器端的 Dadata 备用方案。
- **批量端点无速率限制** (`POST /companies/bulk`)- 一个请求而不是 N 个本地收集器。
- **AI 摘要卡片** ,变更历史,董事姓名搜索(仅专业版工具 - 随托管服务器在第 2 阶段到来,参见 §5.4.1)。
**价格**:专业版 - $10/月独立或 $15/月与 `mcp-fns-check` 捆绑(捆绑密钥)。免费套餐:每天 30 次查询/IP,无需注册(SPEC §1)。
**Cursor 配置** (`.cursor/mcp.json`):
```json
{
"mcpServers": {
"egrul": {
"command": "uvx",
"args": ["atomno-mcp-egrul"],
"env": {
"ATOMNO_API_KEY": "your-pro-key-here"
}
}
}
}
```
**行为和错误** - 没有静默回退:如果托管 API 不可用,客户端会引发类型化的异常,而不是默默地返回旧本地快照。HTTP ↔ MCP 错误代码映射在 SPEC §5.4.1 中:
| 托管 API HTTP 响应 | 客户端异常 | `error.code` |
|---|---|---|
| 200 | - | - |
| 400 | `ValidationError` | `invalid_input` |
| 401 | `HostedAuthError` | `auth_required` |
| 403 | `ProRequiredError` | `pro_required` |
| 404(code=not_found) | `NotFoundError` | `not_found` |
| 404(wrong route) | `SourceUnavailableError` | `source_unavailable` |
| 413 | `BulkTooLargeError` | `bulk_too_large` |
| 429 | `RateLimitedError` (+ `Retry-After`) | `rate_limit` |
| 5xx | `SourceUnavailableError` | `source_unavailable` |
| timeout / DNS 失败 | `SourceUnavailableError`(原因=`timeout`/`ConnectError`) | `source_unavailable` |
税务识别号/主要工商注册号验证仍然在 **客户端** 进行(校验数字在 HTTP 请求之前检查 - 节省无效标识符的往返)。
---
## 配置(环境变量)
| 变量 | 描述 | 默认值 |
|---|---|---|
| `MCP_EGRUL_DB` | 带 ЕГРЮЛ/ЕГРИП 快照的 SQLite 文件路径 | `./mcp_egrul_data.sqlite` |
| `MCP_EGRUL_USER_AGENT` | HTTP 客户端的 User-Agent | `mcp-egrul/0.1 (+https://github.com/atomno-mcp/mcp-egrul)` |
| `MCP_EGRUL_HTTP_TIMEOUT` | 秒为单位的 HTTP 超时 | `30` |
| `MCP_EGRUL_DUMPS_DIR` | 带税务局数据转储的目录,结构为 `<dir>/<registry>/<YYYY-MM-DD>/*.zip` | `./dumps` |
| `MCP_EGRUL_LOG_LEVEL` | 日志级别 | `INFO` |
| `TZ` | 调度器(cron 03:00)的时区 | `Europe/Moscow` |
| `ATOMNO_API_KEY` | (专业版)托管订阅密钥 - 启用 `api.atomno-mcp.ru` 代理 | 未设置 |
| `ATOMNO_API_BASE` | (专业版)托管 API 基本 URL | `https://api.atomno-mcp.ru/mcp-egrul/v1` |
示例 - 参见 `.env.example`。
---
## 结构
```
apps/mcp-egrul/
├── pyproject.toml
├── LICENSE # MIT
├── README.md # 本文
├── Dockerfile
├── docker-compose.yml
├── .env.example
├── .gitignore
├── src/mcp_egrul/
│ ├── __init__.py
│ ├── server.py # FastMCP 入口,7 种工具注册 + ping
│ ├── context.py # ServiceContext(依赖注入:SQLiteStore + HTTP 客户端)
│ ├── config.py # 从 env-vars 读取到键入字段
│ ├── constants.py # 所有魔术数字和枚举
│ ├── validators.py # 税务识别号(10/12)和主要工商注册号(13/15)的校验数字
│ ├── schemas.py # Pydantic 模型 CompanyCard/IECard/SearchResult/...
│ ├── errors.py # McpEgrulError 和子类
│ ├── db/
│ │ ├── __init__.py
│ │ └── sqlite.py # 异步客户端(aiosqlite),init/query/upsert/search + import_log
│ ├── sources/
│ │ ├── __init__.py
│ │ ├── base.py # 源抽象接口
│ │ ├── opendata.py # 税务局开放数据适配器(读取本地 → SQLite upsert)
│ │ ├── opendata_parser.py # 流式 lxml.iterparse 解析 ЕГРЮЛ/ЕГРИП XML
│ │ └── hosted_adapter.py # HTTP 客户端托管专业版 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
├── fixtures/
│ ├── egrul_sample.xml # 小型 ЕГРЮЛ(2 个有效 + 1 个未知状态的跳过)
│ └── 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 工具层 + server.main()
├── test_tools.py # 7 种工具:happy-path + validation + not_found
├── test_opendata_parser.py # XML 解析器(zip, xml, 跳过未知状态记录)
├── test_opendata_source.py # OpenDataSource.run_ingest(full/incremental)
├── test_integration_import.py # 完整导入循环 → 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 + 1 个工具路由(respx 模拟)
```
---
## 测试
```bash
pytest -v --cov=src/mcp_egrul
```
当前覆盖率:**100.00%** (`345 tests passed`, ruff clean,1529 条语句 + 382 个分支,
**0 个遗漏**)。强制执行策略 `--cov-fail-under=100` - 任何回归都会破坏 CI。测试涵盖:
* 校验器税务识别号/主要工商注册号(校验数字)。
* `Config.from_env` + 浮点 env 变量解析器(验证,而不是静默回退)
* 7 种工具(happy-path + validation + not_found + bulk partial)
* SQLite 存储 + FTS5 + `import_log`
* XML 解析器(zip, xml, 跳过未知状态的记录)
* `OpenDataSource.run_ingest`(full/incremental/`nothing_to_import`)
* 完整的导入循环 `import fixture → search → get_card → bulk`
* 2 个 CLI(`atomno-mcp-egrul-import`,`atomno-mcp-egrul-scheduler`)- cron 作业注册,参数解析, `_run_daily_ingest` 在 all-happy/`nothing_to_import`/`McpEgrulError`,完整的 `_run_scheduler` 循环带有模拟 `asyncio.Event`
* FastMCP 工具层通过 `mcp.call_tool()` - 错误序列化为结构化字典,`server.main()` 带有有效和无效 env
* `HostedClient`(托管专业版 API 代理)- 所有 7 种工具的 happy-path,SPEC §5.4.1 中的 HTTP 错误(401/403/404/413/429/5xx),超时/连接错误,服务器返回的无效 JSON/payload,客户端批量验证,`async with` 上下文;另外,还包括工具路由到托管模式(设置 `ATOMNO_API_KEY` - 请求发送到 `api.atomno-mcp.ru` 而不是 SQLite,税务识别号验证在 HTTP 之前)
* 边情况 XML 解析器(75 个单元测试 `_parse_company`/`_parse_ie`/`_parse_share`/`_parse_director`/`_parse_founders`/地址备用方案/旧属性/无效税务识别号/主要工商注册号长度)
* 私有 SQLite 存储帮助器(_wrap,_prepare_row,_row_to_dict,_normalize_bm25,自动初始化 `_ensure`,拒绝无效 `finish_import` 状态)
* `ServiceContext` 可重入-幂等,`atexit` 清理,`Config.from_env` 验证错误 → 从 `atomno-mcp-egrul-import` CLI 退出代码 2。
在测试中绝不直接调用外部 API - 仅通过 `respx`(HTTP 模拟)和本地 XML 固件(`tests/fixtures/`)。
---
## 安全性和法律地位
- 所有来源均为 **俄罗斯联邦税务局公开数据** (ЕГРЮЛ / ЕГРИП 开放数据集),其分发得到了 ФЗ «Об информации…» 和 ЕГРЮЛ 特定规范的允许(参见 SPEC §8)。
- 法人并不受 152-ФЗ(关于个人数据)约束。
- 企业领导人和创始人的姓名在公开的税务局登记册中公布 - 将这些数据传输是合法的。
- 没有对任何外部 API 进行写操作。
- 秘密仅通过环境变量存储,在存储库中 - `.env.example` 文件中没有值。
---
## 免责声明
该服务是 **公共数据和便捷接口的聚合器** ,基于俄罗斯联邦税务局的公开数据。不隶属于俄罗斯联邦税务局。使用风险自负。服务响应中的信息不能替代全面法律或财务评估。
---
## 许可
MIT。文件夹根目录中的 `LICENSE` 文件。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器