Skip to main content
Glama
AI1379
by AI1379
README.md
# mihoyo-mcp

独立的米哈游 MCP Server —— 同时面向**米游社(国服)**与 **HoYoLAB(国际服)**,底层依赖
[seriaati/genshin.py](https://github.com/seriaati/genshin.py)(MIT)。任何 MCP 客户端
(nahida-bot、Claude Desktop、Codex……)都可以直接使用。

## 设计边界

> **MCP 管「怎么和米哈游说话」;客户端管「什么时候去问,以及问完之后告诉谁」。**

- 调度(cron)、阈值策略、消息推送 → 客户端(nahida-bot 已有 Scheduler / Channel)
- 登录、凭据存储、API 调用、告警去重 → 本服务
- **凭据永远不出安全边界**:Cookie 全程存在服务内部(Fernet 加密),工具结果里只有
  `account_id`,Agent context 里不会出现任何 token

```text
                ┌─────────────────────┐
                │     nahida-bot      │
                │  Cron / Scheduler   │
                │       │             │
                │       ▼             │
                │  MCP Client ───────────────┐
                │       ▼             │     │ MCP (stdio)
                │  QQ Channel         │     ▼
                └─────────────────────┘ ┌──────────────────┐
                                       │    mihoyo-mcp     │
                                       │ QR login          │
                                       │ credential vault  │
                                       │ daily notes       │
                                       │ alert dedup state │
                                       └────────┬──────────┘
                                                │
                                         genshin.py
                                                │
                                     米游社 / HoYoLAB API
```

## 当前能力

| 能力 | 状态 |
| --- | --- |
| 米游社扫码登录(非阻塞 start/poll) | ✅ 复用 genshin.py web QR 链路 |
| 多账号 + 游戏角色(uid)发现 | ✅ |
| 星穹铁道实时便笺 | ✅ `starrail_daily_note` |
| 原神实时便笺 | ✅ `genshin_daily_note` |
| 绝区零实时便笺 | ✅ `zzz_daily_note` |
| 星铁告警检查(跨轮去重) | ✅ `starrail_check_alerts` |
| HoYoLAB 登录 | ⏳ 未接入(见路线图) |

## 工具一览

| 工具 | 说明 |
| --- | --- |
| `auth_start_qr_login(platform)` | 创建扫码登录,返回 `login_url` + base64 PNG 二维码 + `session_id` |
| `auth_poll_qr_login(session_id)` | 轮询扫码状态:`pending` / `scanned` / `confirmed`(确认后自动保存凭据并发现游戏角色) |
| `auth_status()` | 已登录账号数、待完成登录会话 |
| `accounts_list()` | 列出账号及其游戏角色(uid),不含任何凭据 |
| `accounts_refresh(account_id?)` | 重新发现账号下的游戏角色 |
| `starrail_daily_note(account_id?)` | 开拓力(含备用)、每日实训、模拟宇宙、派遣 |
| `genshin_daily_note(account_id?)` | 树脂、洞天宝钱、每日委托、派遣 |
| `zzz_daily_note(account_id?)` | 电量、活跃度、录像店等 |
| `starrail_check_alerts(account_id?, stamina_threshold=200)` | 只返回「值得通知的变化」;空列表 = 保持安静 |

`account_id` 在只有一个账号时可省略。

> **命名说明**:设计稿里用的是 `mihoyo.auth.start_qr_login` 这类点号命名,但 MCP 规范
> (SEP-986)要求工具名匹配 `^[a-zA-Z0-9_-]{1,64}$`,点号会导致部分客户端拒绝加载,
> 因此采用扁平蛇形命名,用 `auth_` / `accounts_` / `starrail_` 等前缀充当命名空间。

### 为什么 `check_alerts` 在 MCP 里

体力阈值判断(`217 >= 200 && recovery <= 1800`)不需要烧 LLM token,而「派遣回来了」
每次轮询都报一遍是不可接受的。告警去重状态(armed/re-arm)属于米游社集成状态,天然属于
本服务。客户端的 cron 只需要:

```text
starrail_check_alerts() → alerts == [] → 静默
                      → alerts != [] → 推送消息
```

## 快速开始

```bash
uv sync                       # 安装依赖
uv run pytest                 # 运行测试
uv run python scripts/smoke_stdio.py   # stdio 握手冒烟测试
uv run mihoyo-mcp             # 启动 stdio server
```

客户端配置示例(Claude Desktop / 任何支持 stdio MCP 的客户端):

```json
{
  "mcpServers": {
    "mihoyo": {
      "command": "uv",
      "args": ["run", "--directory", "D:/Projects/mihoyo-mcp", "mihoyo-mcp"]
    }
  }
}
```

## 配置(环境变量)

| 变量 | 默认 | 说明 |
| --- | --- | --- |
| `MIHOYO_MCP_DATA_DIR` | `~/.mihoyo-mcp` | 数据目录(账号 / 凭据 / 告警状态) |
| `MIHOYO_MCP_FERNET_KEY` | 自动生成 | 凭据加密 key;生产环境建议放入 secret store |
| `MIHOYO_MCP_STAMINA_THRESHOLD` | `200` | `starrail_check_alerts` 默认体力阈值 |
| `MIHOYO_MCP_LOG_LEVEL` | `INFO` | 日志级别(日志走 stderr,stdout 保留给 MCP 协议) |

数据目录内容:

```text
~/.mihoyo-mcp/
├── accounts.json     # 公开账号元数据(无秘密)
├── credentials.enc   # Fernet 加密的 Cookie/token 库
├── alert_state.json  # 告警去重状态
├── fernet.key        # 未设置环境变量时自动生成的 key(带告警日志)
└── .lock             # 数据目录独占锁:一个目录只允许一个活进程,重复启动直接报错退出
```

所有落盘文件都走原子写(temp + `os.replace`),进程写一半崩溃不会留下半截文件。

## 目录结构

```text
src/mihoyo_mcp/
├── server.py          # MCPServer 装配 + stdio 入口
├── config.py          # 环境变量配置
├── context.py         # AppContext 单例装配
├── errors.py          # 领域错误(映射为 MCP tool error)
├── accounts/          # 账号模型 / 注册表 / 加密凭据库
├── auth/              # 扫码登录(start/poll 会话)
├── games/             # genshin.py 客户端工厂 + 便笺获取/归一化
├── alerts/            # 告警去重状态机(纯逻辑,可测)
└── tools/             # MCP 工具注册(auth / accounts / notes)
```

## 登录流程(米游社)

1. `auth_start_qr_login("miyoushe")` → 把 `qr_png_base64`(或 `login_url`)生成的二维码发给用户
2. 用户用米游社 App 扫码并在手机上确认
3. `auth_poll_qr_login(session_id)` 轮询直到 `confirmed`
4. 服务内部保存 v2 cookies(`account_id_v2` / `account_mid_v2` / `ltoken_v2` / `cookie_token_v2`…)
   并自动发现游戏角色;之后 Agent 只会看到 `account_id` 形如 `miyoushe:123456`

## 路线图

按消费方(nahida-bot #52 等)优先级排序:

1. ✅ Account / Auth —— 米游社扫码、多账号、角色发现
2. ✅ Daily Note + 告警 —— 星铁/原神/绝区零便笺、`check_alerts`
3. ⏳ HoYoLAB 登录 —— 邮箱密码(genshin.py 已支持)或 OS 扫码(endpoint 待验证)
4. 签到 / 兑换码(`check_in` / `codes.list` / `codes.redeem`)
5. Profile / 角色展示(Enka、面板查询)
6. 游戏资料 / Build / 养成计算(hakush.in / Yatta / Ambr)
7. Gacha 导入与统计
8. Renderer(可选的图片卡片生成,工具返回结构化数据 + 独立渲染工具)

## 参考项目与许可证

| 项目 | 许可证 | 本项目中的角色 |
| --- | --- | --- |
| [seriaati/genshin.py](https://github.com/seriaati/genshin.py) | MIT | **直接依赖**:API 封装、DS、cookie、扫码链路 |
| [seriaati/hoyo-buddy](https://github.com/seriaati/hoyo-buddy) | GPL-3.0 | 架构参考(账号/凭据/提醒),**不复制代码** |
| [Ljzd-PRO/nonebot-plugin-mystool](https://github.com/Ljzd-pro/nonebot-plugin-mystool) | MIT | 国服行为参考(错误处理、便笺字段坑) |
| [UIGF-org/mihoyo-api-collect](https://github.com/UIGF-org/mihoyo-api-collect) | CC BY-NC 4.0 | 协议字典,仅用于查询验证,不搬运实现 |
| [Marchen-orz/MiyoQian](https://github.com/Marchen-orz/MiyoQian) | 未标明 | 现代国服扫码登录参考 |

本项目采用 [MIT License](LICENSE)。

TDQS

A4/5.0

Scored across 9 tools

Disambiguation4/5

Most tools have sharply distinct purposes: auth tools, account tools, and per-game note tools are clearly separated. However, auth_status and accounts_list both relate to logged-in accounts, and starrail_daily_note vs starrail_check_alerts could be confused if not read carefully.

Naming Consistency4/5

Names follow a consistent lower_snake_case, domain-prefixed pattern like auth_start_qr_login, accounts_refresh, and genshin_daily_note. The main deviation is that 'daily_note' is a noun rather than a verb phrase like 'get_daily_note', but the pattern remains predictable.

Tool Count5/5

Nine tools is a well-scoped size for this server: QR login lifecycle, account listing/refresh, and three per-game real-time note endpoints plus one alert helper. Each tool has a distinct role and none feels redundant or excessive.

Completeness4/5

The core workflow is covered: login, poll login, list accounts, refresh roles, and retrieve daily notes for all three supported games. Minor gaps exist such as no explicit logout/account removal and alert-polling only for Star Rail, but agents can work around these by using the existing notes tools.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive