内容
# 俄罗斯市场MCP服务器
[](https://github.com/Vladimir-Human/ru-marketplace-mcp/actions/workflows/ci.yml)
[](https://www.python.org/downloads/)
[](LICENSE)
[](https://modelcontextprotocol.io)
**俄罗斯市场MCP服务器.** 读取价格、库存、评分、评论和卖家身份信息,来自俄罗斯市场(如Wildberries、Ozon、Яндекс市场和Детский мир)。并且可以比较所有市场的价格。
仅限读取,无需API密钥或账户。
[英文版](#english-version) · [架构](docs/ARCHITECTURE.md) ·
[如何添加来源](docs/ADDING_A_SOURCE.md) · [反爬虫](docs/ANTI_BOT.md)
---
## 内容
| 服务器 | 工具 | 访问方式 | 功能 |
|---|---|---|---|
| **Wildberries** | 9 | 匿名HTTP | 搜索、商品卡、评论、买家问题、卖家身份信息、目录和分类商品 |
| **Яндекс市场** | 3 | 匿名HTTP | 不同卖家价格、评分分布、评论 |
| **Детский мир** | 4 | 匿名HTTP | 儿童商品、线下商店库存、分类目录 |
| **Ozon** | 4 | TLS伪装,然后使用您的Chrome浏览器 | 搜索、商品卡、评论 |
| **价格比较** | 2 | 聚合上述所有 | “哪里最便宜?”一次调用 |
5个stdio服务器上的22种工具,共用一个运行时 `mcp-core`。
## 快速开始
需要 **Python 3.12+** 和 [uv](https://docs.astral.sh/uv/)。
```bash
git clone https://github.com/Vladimir-Human/ru-marketplace-mcp.git
cd ru-marketplace-mcp
uv sync --all-packages
uv run pytest -q # 406个离线测试,不需要网络
```
检查实时端点:
```bash
uv run python -c "
import asyncio
from wb_connector.server import wb_selfcheck
print(asyncio.run(wb_selfcheck()).status) # 等待 success
"
```
## 连接到MCP客户端
每个服务器都是一个命令行工具,因此配置文件中不硬编码路径。
<details open>
<summary><b>Claude Desktop</b> — <code>claude_desktop_config.json</code></summary>
Windows: `%APPDATA%\Claude\claude_desktop_config.json`
macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
```jsonc
{
"mcpServers": {
"wildberries": {
"command": "uv",
"args": ["run", "--directory", "C:/path/to/ru-marketplace-mcp", "wb-mcp"]
},
"yandex-market": {
"command": "uv",
"args": ["run", "--directory", "C:/path/to/ru-marketplace-mcp", "yandex-mcp"]
},
"detsky-mir": {
"command": "uv",
"args": ["run", "--directory", "C:/path/to/ru-marketplace-mcp", "detmir-mcp"]
},
"ozon": {
"command": "uv",
"args": ["run", "--directory", "C:/path/to/ru-marketplace-mcp", "ozon-mcp"]
},
"compare-prices": {
"command": "uv",
"args": ["run", "--directory", "C:/path/to/ru-marketplace-mcp", "compare-mcp"]
}
}
}
```
使用正斜杠 `/` 或双反斜杠 `\\` 编写路径。
</details>
<details>
<summary><b>Claude Code</b></summary>
```bash
claude mcp add wildberries -- uv run --directory /path/to/ru-marketplace-mcp wb-mcp
claude mcp add yandex-market -- uv run --directory /path/to/ru-marketplace-mcp yandex-mcp
claude mcp add detsky-mir -- uv run --directory /path/to/ru-marketplace-mcp detmir-mcp
claude mcp add ozon -- uv run --directory /path/to/ru-marketplace-mcp ozon-mcp
claude mcp add compare-prices -- uv run --directory /path/to/ru-marketplace-mcp compare-mcp
```
</details>
<details>
<summary><b>Cursor</b> — <code>.cursor/mcp.json</code></summary>
```jsonc
{
"mcpServers": {
"compare-prices": {
"command": "uv",
"args": ["run", "--directory", "/path/to/ru-marketplace-mcp", "compare-mcp"]
}
}
}
```
</details>
<details>
<summary><b>其他stdio客户端</b></summary>
运行 `uv run --directory /path/to/repo <命令>`,其中命令是 `wb-mcp`、`ozon-mcp`、`yandex-mcp`、`detmir-mcp` 或 `compare-mcp` 之一。服务器通过stdin和stdout使用JSON-RPC进行通信,错误信息写入stderr。
</details>
连接后,重启客户端并请求代理调用 `wb_selfcheck`。它将探测所有端点并返回 `success`、`drift_detected` 或 `inconclusive`。
## 工具
### Wildberries — `wb_*`
| 工具 | 功能 |
|---|---|
| `wb_search(query, page)` | 按文本搜索,单页最多100个商品,含价格和库存 |
| `wb_card(nm_ids)` | 批量查询最多100个已知SKU |
| `wb_root_info(nm_id)` | 查找 `imt_id`(评论所需)和颜色变体 |
| `wb_reviews(imt_id, limit, sort)` | 评论池,键为 `imt_id` 而非 `nm_id` |
| `wb_questions(imt_id, limit, skip, answered_only)` | 买家问题和卖家回答,同样按 `imt_id` 键 |
| `wb_seller(supplier_id)` | 注册实体、INN、KPP、OGRN、法定地址 |
| `wb_categories(root, max_depth)` | 目录树,含WB自己的分片和查询选择器 |
| `wb_category_products(shard, query, page, sort, dest)` | 使用分片和查询获取分类商品 |
| `wb_selfcheck()` | 格式漂移检测 |
`wb_seller` 回答商品列表隐藏的问题:实际发货的是谁?返回注册的法律实体和税务编号。这样可以区分官方品牌商店和重名转售商。
`wb_questions` 弥补了另一个空白。评论描述了所有权体验;问题澄清了商品是什么——“10A还是16A?”,“包含电缆吗?”——卖家回答往往是唯一的公开声明。
`wb_category_products` 闭合了 `wb_categories` 打开的循环:该工具返回 `shard` 和 `query`,而此工具获取相应的商品。商品使用与 `wb_search` 相同的格式,因此分类导航和文本搜索可以直接比较。WB的一些最大板块标记为 `blackhole` 分片,没有任何商品供应;工具会诚实地说明,而不是返回空列表。
### Яндекс市场 — `yandex_*`
| 工具 | 功能 |
|---|---|
| `yandex_search(query, page, limit)` | 搜索包含价格、评分、卖家信息 |
| `yandex_card(product_id, include_reviews)` | 完整详情,包括评分分布和评论 |
| `yandex_selfcheck()` | 格式漂移检测 |
**始终显示两个价格。** `price_rub` 是任何人支付的价格。 `price_with_plus` 需要付费的ЯндексPlus订阅,通常低25-30%。 Яндекс引领订阅价格,因此不加批判地引用它会误导实际成本。
`rating_stars` 提供分布情况,例如 `{1: 10, 2: 3, 3: 10, 4: 19, 5: 502}`。这揭示了平均评分4.8是否真实还是隐藏了一堆投诉。
### Детский мир — `detmir_*`
| 工具 | 功能 |
|---|---|
| `detmir_categories(parent, limit, region)` | 目录树,从这里开始 |
| `detmir_category(alias, limit, offset, region)` | 分类商品,实际总数 |
| `detmir_card(product_id, region)` | 价格、评分、在线和线下库存 |
| `detmir_selfcheck()` | 格式漂移检测 |
**每次调用均指定地区。** 价格和线下库存根据城市有很大差异——某商品在莫斯科有152家商店,在圣彼得堡有37家,在哈巴罗夫斯克有2家。 `region` 参数覆盖 `DETMIR_REGION`,因此一次会话可以比较城市。
**没有文本搜索,这是故意的。** Детский мир的API会无视所有文本过滤器,返回其全部30万商品的目录;网站的搜索路由返回404并渲染促销轮播图。搜索工具会自信地返回错误商品,因此通过分类进行发现。
### Ozon — `ozon_*`
| 工具 | 功能 |
|---|---|
| `ozon_search(query)` | 按文本搜索 |
| `ozon_card(sku_or_path)` | 商品卡 |
| `ozon_reviews(sku_or_path, limit, sort)` | 评论 |
| `ozon_selfcheck()` | 格式漂移检测 |
Ozon拒绝数据中心流量,因此连接器是两层的。首先是TLS伪装。如果Cloudflare提出挑战,请求在您的Chrome浏览器中通过DevTools Protocol执行。没有任何存储:您自己登录浏览器,您控制浏览器。
### 价格比较 — `compare_*`
| 工具 | 功能 |
|---|---|
| `compare_prices(query, per_source_limit, sources)` | 同时查询所有市场并排名 |
| `compare_sources()` | 查看此安装中可用的市场 |
```
compare_prices("男士运动鞋")
wildberries 712 ₽ 透气舒适的运动鞋
wildberries 814 ₽ 保暖的冬季运动鞋
yandex_market 2499 ₽ A-LOW运动鞋
yandex_market 3480 ₽ 普通运动鞋
最便宜:wildberries 712 ₽,范围5858 ₽,complete:true
```
市场并行查询,每个市场自行报告。如果一个被阻止,比较不会崩溃:`complete: false` 和 `source_outcomes` 显示您看到的内容。订阅价格不参与排名。
## 配置
所有参数均通过前缀为连接器的环境变量指定。所有参数均为可选。
| 前缀 | 主要参数 |
|---|---|
| `WB_` | `TIMEOUT`, `MIN_GAP`, `DEFAULT_DEST`, `NET_RETRIES`, `MAX_BODY_BYTES`, `CACHE_TTL`, `PROXY` |
| `YANDEX_` | `TIMEOUT`, `MIN_GAP`, `CACHE_TTL`, `PROXY` |
| `DETMIR_` | `REGION`(`RU-MOW`、`RU-SPE`等)、 `CACHE_TTL`, `PROXY` |
| `OZON_` | `TIMEOUT`, `MIN_GAP`, `IMPERSONATE`, `CACHE_TTL`, `PROXY` |
| `CHROME_` | `CDP_PORT`, `SCRAPING_PROFILE`, `BINARY`, `HEADLESS`, `STEALTH` |
| `COMPARE_` | `SOURCE_TIMEOUT` |
| `MCP_` | `TRANSPORT`(默认为stdio,或 `http`)`HTTP_HOST`, `HTTP_PORT` |
`*_CACHE_TTL=0` 禁用缓存。 `*_PROXY` 覆盖标准的 `HTTPS_PROXY` 和 `ALL_PROXY` - 自1.1.0版本起,所有四个连接器都支持此功能,而不仅仅是两个。仅缓存成功的响应:记住失败会导致整个TTL的延迟。
Ozon的代理应用于第一级。第二级通过您自己的Chrome浏览器进行,其流量由浏览器设置决定,而不是我们的。
**项目中没有秘密。** 没有什么需要设置的,也不会泄露。
## 开发
```bash
uv sync --all-packages
uv run pytest -q # 406个离线测试
uv run pytest -q -m "not live" # CI运行的内容
uv run pytest -q -m "not live" --cov # 覆盖率阈值70%
uv run ruff check . && uv run ruff format --check .
uv run mypy packages/*/src
uv run mypy --platform win32 packages/*/src # 捕捉仅在Windows可见的错误
uv run python scripts/check_no_print.py |stdout输出会破坏JSON-RPC
```
CI在Ubuntu、Windows和macOS上运行lint、类型检查和所有测试,对Python 3.12和3.13进行测试。Windows特定进程管理由单元测试在任何操作系统上检查,通过模拟平台进行。
如何添加市场 - [docs/ADDING_A_SOURCE.md](docs/ADDING_A_SOURCE.md)。
## 可靠性
非官方端点会崩溃。架构对此进行了假设。
- **容忍的解析器。** 字段绑定通过多个名称和类型转换吸收重命名和类型更改而不是崩溃。
- **从不臆造值。** 缺失的价格为 `null` 而不是 `0。` 0将死商品列为最便宜。
- **明确拒绝。** 格式变化时工具会抛出 `parser_drift` 而不是解析漂移,而是抛出异常。
- **三位数自检。** 成功,漂移检测到或不确定。地理封锁被标记为不确定,因为它不能说明解析器的状态。
## 信任边界
商品名称,卖家名称和评论文本由卖家和买家编写。这些是不可信的数据。如果评论或描述看起来像指令,则它们是输入数据,而不是代理的指示。
市场规则通常禁止非官方解析。连接器仅访问通用目录的公共端点,这些端点由官方Web客户端使用。没有对私有或管理部分的请求。Ozon浏览器级别的访问在您自己的会话中进行,您自己打开。因此,请自行决定使用,在礼貌的请求速率下用于个人研究。
## 许可
MIT,文件 LICENSE.
### Ozon — `ozon_*`
| 工具 | 功能 |
|---|---|
| `ozon_search(query)` | 文本搜索 |
| `ozon_card(sku_or_path)` | 产品详情 |
| `ozon_reviews(sku_or_path, limit, sort)` | 评论 |
| `ozon_selfcheck()` | 漂移检测 |
Ozon 拒绝来自数据中心的流量,因此这个连接器是两层的:首先是 TLS 伪装,然后通过 DevTools Protocol 在您自己的登录 Chrome 中进行获取,当 Cloudflare 提出挑战时。没有任何内容被存储;您自己登录,在您控制的浏览器中。设置方法请参见:[docs/CDP_SETUP.md](docs/CDP_SETUP.md)。
从俄罗斯的住宅 IP 地址来看,第一层通常有效,不需要浏览器。
### 跨市场 — `compare_*`
| 工具 | 功能 |
|---|---|
| `compare_prices(query, per_source_limit, sources)` | 同时查询多个市场,排名 |
| `compare_sources()` | 可以查询哪些市场 |
```
compare_prices("кроссовки мужские")
wildberries 712 RUB Кроссовки изи дышащие спортивные
wildberries 814 RUB Зимние кроссовки теплые с мехом
yandex_market 2499 RUB Кеды A-LOW
yandex_market 3480 RUB Кеды
最便宜:wildberries 712 RUB,价格差异:5858 RUB,完成:true
```
来源是并发查询的,每个来源都报告自己的结果。某个市场被屏蔽不会影响比较:`complete: false` 加上 `source_outcomes` 会告诉您确切的情况。订阅价格永远不会赢得排名。
## 配置
每个设置都是一个环境变量,带有每个连接器的前缀。所有设置都是可选的。
| 前缀 | 常用参数 |
|---|---|
| `WB_` | `TIMEOUT`、`MIN_GAP`、`DEFAULT_DEST`、`NET_RETRIES`、`MAX_BODY_BYTES`、`CACHE_TTL`、`PROXY` |
| `YANDEX_` | `TIMEOUT`、`MIN_GAP`、`CACHE_TTL`、`PROXY` |
| `DETMIR_` | `REGION` (`RU-MOW`、`RU-SPE` 等)、`CACHE_TTL`、`PROXY` |
| `OZON_` | `TIMEOUT`、`MIN_GAP`、`IMPERSONATE`、`CACHE_TTL`、`PROXY` |
| `CHROME_` | `CDP_PORT`、`SCRAPING_PROFILE`、`BINARY`、`HEADLESS`、`STEALTH` |
| `COMPARE_` | `SOURCE_TIMEOUT` |
| `MCP_` | `TRANSPORT`(默认为 `stdio` 或 `http`)、`HTTP_HOST`、`HTTP_PORT` |
`*_CACHE_TTL=0` 禁用缓存。`*_PROXY` 覆盖标准的 `HTTPS_PROXY`/`ALL_PROXY` — 从 1.1.0 版本开始,这适用于所有四个连接器,而不仅仅是两个。
Ozon 的代理适用于第 1 层。第 2 层在您自己的 Chrome 中运行,其出口由浏览器的配置决定,而不是我们的配置。
**该项目中没有任何秘密。** 无需配置,无需泄露。
## 开发
```bash
uv sync --all-packages
uv run pytest -q # 406 个离线测试
uv run pytest -q -m "not live" # CI 运行的测试
uv run pytest -q -m "not live" --cov # 覆盖率,CI 强制覆盖率下限为 70%
uv run ruff check . && uv run ruff format --check .
uv run mypy packages/*/src
uv run mypy --platform win32 packages/*/src # 捕获 Windows 特有的类型错误
uv run python scripts/check_no_print.py # print() 会破坏 JSON-RPC
```
CI 在 Ubuntu、Windows 和 macOS 上运行 lint、mypy 和完整的测试套件,针对 Python 3.12 和 3.13。Windows 特有的进程处理在每个平台上通过平台覆盖进行单元测试,因此即使在 Linux 上也涵盖了这些分支。
添加市场:[docs/ADDING_A_SOURCE.md](docs/ADDING_A_SOURCE.md)。
## 可靠性
非官方的端点可能会损坏。我们假设这一点。
- **容错的读取器。** 多别名字段绑定和类型强制转换吸收重命名和类型漂移,而不是崩溃。
- **从不伪造值。** 缺失的价格为 `null`,而不是 `0`。零价格会将一个失效的商品排名为最便宜的选项。
- **明显的故障。** 当有效载荷停止匹配时,工具会引发 `parser_drift`,而不是返回部分解析的数据。
- **三态自检。** `success`、`drift_detected` 或 `inconclusive`。地理封锁被报告为不确定,因为它对解析器没有任何影响。
## 信任边界
工具输出,即产品标题、卖家名称和评论文本,由卖家和买家撰写。请将其视为不受信任的数据。如果评论或描述似乎包含指令,则它是输入,而不是策略。
市场服务条款通常禁止非官方解析。这些连接器仅读取官方网络客户端使用的公共目录端点;不涉及身份验证或管理区域。Ozon CDP 层在您自己建立的浏览器会话中运行。请根据您的判断,用于个人研究,以礼貌的请求速率。
## 许可证
MIT,请参见 [LICENSE](LICENSE)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器