Skip to content

Commit bb2de68

Browse files
committed
feat: 新增 MCP 服务供外部 agent 调用
1 parent e9e24c6 commit bb2de68

17 files changed

Lines changed: 2154 additions & 29 deletions

‎.env.example‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ OPENCLAW_AUTH_MODE="credentials"
122122
# 生成方式: openssl rand -hex 32
123123
OPENCLAW_INTEGRATION_API_KEY=""
124124

125+
# MCP 服务(供外部 agent 调用本系统,可选)
126+
# 同时配置密钥与目标账号后开放 POST /api/mcp;详情见 doc/wiki/MCP-Server.md
127+
# 生成方式: openssl rand -hex 32
128+
MCP_API_KEY=""
129+
# 固定目标账号,填邮箱(也可填用户名)
130+
MCP_USER_EMAIL=""
131+
125132
# 自动化 E2E:npm run test:e2e 自动创建独立配置与数据库,使用本地模拟模型及固定假 Key。
126133
# E2E_RUN_FILE 由测试启动器生成并传给 Playwright,无需手工设置。
127134
# E2E_ALLOWED_PORTS 与 E2E_NETWORK_LOG 由启动器传给测试进程,用于限制和记录运行时外连。

‎README.en.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ Practice statistics show total practice, accuracy (correct / attempted) and acti
189189
- **📈 Anonymous telemetry and administrator agreement**: the administrator accepts the [agreement](doc/EULA.en.md) during initialization (on fnOS, in the installer wizard). The instance then sends a batch of anonymous usage statistics and error fingerprints to the Wrong Notebook collection service about every 6 hours, without user or instance identifiers, IP addresses, question content, AI conversations or error messages. Instances upgraded from older versions do not forward by default; administrators see a banner where they can review the agreement and turn it on. Under "Settings → User Management → Privacy & telemetry" an administrator can turn forwarding off, enable local recording (kept on this server for troubleshooting), point to a self-hosted collection service and see what the instance collected; `TELEMETRY_DISABLED=true` forces everything off. When the agreement changes, administrators must accept again and forwarding pauses meanwhile; ordinary users are not affected. See [Privacy](doc/PRIVACY.en.md) and the [design](doc/TELEMETRY_DESIGN.md).
190190
- **🐞 Debug logs**: when something goes wrong, an admin turns on debug mode under "Settings → User Management", reproduces the problem, then exports the debug log (JSON) and sends it to the author. Debug mode records every server log, including `debug` level, plus frontend errors; API keys, passwords and tokens are removed on export. The log lives in memory only, debug mode turns off after 24 hours, and a restart clears it.
191191
- **🔌 Openclaw integration**: an external Openclaw agent can upload question images in bulk via `POST /api/openclaw/batch-upload`; see [Environment variables](#-environment-variables).
192+
- **🧩 MCP server**: external agents can read and write notebooks, questions, knowledge tags and review data through the MCP Streamable HTTP endpoint `POST /api/mcp`. Set `MCP_API_KEY` and `MCP_USER_EMAIL` to enable it; tools and client setup are in [MCP Server](doc/wiki/en/MCP-Server-en.md).
192193

193194
## 🚀 Quick Start
194195

@@ -539,6 +540,13 @@ The most common variables are below; see the collapsed table and [`.env.example`
539540
| `OPENCLAW_AUTH_MODE` | Auth mode | `credentials` | `credentials` (username and password) or `apikey` |
540541
| `OPENCLAW_INTEGRATION_API_KEY` | This app's API key | None | Only for `apikey` mode, used by Openclaw to call this app. Generate with `openssl rand -hex 32` |
541542

543+
**MCP server** (optional)
544+
545+
| Variable | Description | Default | Notes |
546+
| :--- | :--- | :--- | :--- |
547+
| `MCP_API_KEY` | MCP integration key | None | External agents send it as `Authorization: Bearer` or `x-api-key`. Generate with `openssl rand -hex 32` |
548+
| `MCP_USER_EMAIL` | MCP target account | None | Fixes the notebook data to this account; use an email (a username also works), and the account must be enabled |
549+
542550
When adding environment variables, update `.env.example` as well.
543551

544552
</details>

‎README.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@
189189
- **📈 匿名遥测与使用协议**:管理员在初始化时同意[使用协议](doc/EULA.md)(飞牛OS 在安装向导中勾选),实例默认每 6 小时向错题本收集服务发送一批匿名的功能使用统计和错误指纹,不含用户或实例标识、IP、题目内容、AI 对话或错误原文;存量实例升级后默认不外发,管理员登录时可从提示横幅查看协议后开启。「设置 → 用户管理 → 隐私与遥测」可关闭外发、开启本地记录(只保存在本机,供排查问题)、改为自建收集服务,并查看本实例收集了什么;设置 `TELEMETRY_DISABLED=true` 强制全部关闭。协议升级后管理员需重新同意,期间暂停外发,普通用户不受影响。详见[隐私说明](doc/PRIVACY.md)与[设计](doc/TELEMETRY_DESIGN.md)。
190190
- **🐞 调试日志**:遇到问题时,管理员在「设置 → 用户管理」中打开调试模式,复现问题后导出调试日志(JSON)发给作者。调试模式下记录包括 debug 级别在内的全部服务端日志和前端错误,导出时自动去除 API Key、密码和令牌;日志只保存在内存中,24 小时后自动关闭,服务重启后清空。
191191
- **🔌 Openclaw 集成**:外部 Openclaw agent 可通过 `POST /api/openclaw/batch-upload` 批量上传题目图片,配置见[环境变量](#-环境变量)。
192+
- **🧩 MCP 服务**:外部 agent 可通过 MCP Streamable HTTP 端点 `POST /api/mcp` 读写错题本、错题、知识点与复习数据;配置 `MCP_API_KEY` 与 `MCP_USER_EMAIL` 后启用,工具与接入方式见 [MCP 服务](doc/wiki/MCP-Server.md)。
192193

193194
## 🚀 快速开始
194195

@@ -537,6 +538,13 @@ GeoGebra 的文字、不等式和标签参数按共用命令清单校验,重
537538
| `OPENCLAW_AUTH_MODE` | 认证方式 | `credentials` | `credentials`(用户名密码)或 `apikey` |
538539
| `OPENCLAW_INTEGRATION_API_KEY` | 本系统 API 密钥 | 无 | 仅 `apikey` 模式需要,供 Openclaw 调用本系统,可用 `openssl rand -hex 32` 生成 |
539540

541+
**MCP 服务**(可选)
542+
543+
| 环境变量 | 描述 | 默认值 | 说明 |
544+
| :--- | :--- | :--- | :--- |
545+
| `MCP_API_KEY` | MCP 集成密钥 | 无 | 外部 agent 通过 `Authorization: Bearer` 或 `x-api-key` 提交;可用 `openssl rand -hex 32` 生成 |
546+
| `MCP_USER_EMAIL` | MCP 目标账号 | 无 | 固定该账号的错题数据;填邮箱(也可填用户名),账号须启用 |
547+
540548
新增环境变量时需同步更新 `.env.example`。
541549

542550
</details>

‎doc/FORK_EXTENSION_POINTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ registerQuestionSaveHook(myHook);
169169
- 任何钩子抛错都会使整笔事务回滚(与 `afterWrite` 一致),并记录 `logger.error`。
170170
- 重复题(`duplicate: true`)同样触发钩子,此时 `errorItemId` 指向原有题目,未新建错题。
171171

172-
`origin` 字段区分入库路径:`manual`(单题保存 API)、`import-task`(识别导入任务)、`openclaw`(Openclaw 批量上传)。
172+
`origin` 字段区分入库路径:`manual`(单题保存 API)、`import-task`(识别导入任务)、`openclaw`(Openclaw 批量上传)、`mcp`(MCP 工具 `add_question`)。
173173

174174
注意:
175175

‎doc/operational_flow.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
3. **阈值设置**:在首页「设置 → 通用」中保存个人判重阈值,新账号默认 90%(2026-10-19 前创建的账号保持原值 99%,可自行修改),支持 1%~100%、最多两位小数。相似度**严格大于**阈值才判重;设为 100% 时不自动判重。
6666
4. **重复题目**:保留原题,不新建 `ErrorItem`;在原题的举一反三记录中新增一次「做错」,保存本次题目、答案、作答文字、错因和图片,并重新评估掌握情况。页面提示本次错误已记录。
6767
5. **新题目**:在 `ErrorItem` 表中创建记录,关联 `Subject` 和知识点标签;原图以 Base64 格式存储。没有可用题干或 OCR 文字的图片不会自动合并。
68-
6. 图片识别后导入、人工校对保存、直接录入、框选批量导入、Openclaw 批量上传和 JSON 数据导入均使用同一判重规则。
68+
6. 图片识别后导入、人工校对保存、直接录入、框选批量导入、Openclaw 批量上传、MCP `add_question` 和 JSON 数据导入均使用同一判重规则。
6969

7070
### 2.3 错题管理与复习 (Management & Review)
7171
* **错题本视图**:

‎doc/wiki/Home.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Smart Wrong Notebook(智能错题本)把拍照或文字录入的错题整理
1818
| 调整偏好、应用时区和用户权限 | [设置与用户管理](Settings-and-Users) |
1919
| 导出个人数据或备份整站 | [数据备份与恢复](Backup-and-Restore) |
2020
| 从外部 Openclaw agent 批量导题 | [Openclaw 集成](Openclaw-Integration) |
21+
| 让外部 agent 通过 MCP 读写错题、标签与复习数据 | [MCP 服务](MCP-Server) |
2122
| 了解代码结构、测试和贡献要求 | [开发与贡献](Development) |
2223
| 首次安装后如何登录,排查识别、公式或截图问题 | [常见问题](FAQ) |
2324

@@ -30,7 +31,7 @@ Smart Wrong Notebook(智能错题本)把拍照或文字录入的错题整理
3031
- 题库文件导入(JSON / Word / Excel / CSV / PDF,可「按原样入库」不调用 AI)与选中错题导出(JSON / Excel / Word)。
3132
- 举一反三与 AI 判题、今日复习、错题组卷、作答历史、掌握概率、学习统计和打印导出。
3233
- 共享真题库:从 [共享题库仓库](https://github.com/margrop/wrong-notebook-question-bank) 下载小学/初中/高中题库包,导入默认不进入错题;举一反三可按知识点从题库选题。
33-
- 多用户隔离、每日 AI 次数限制、管理员设置、个人偏好与 Openclaw 批量导入。
34+
- 多用户隔离、每日 AI 次数限制、管理员设置、个人偏好、Openclaw 批量导入与 MCP 服务。
3435
- 全新安装通过一次性初始化链接(飞牛OS 为安装向导)设置管理员,不预置固定密码;随后由安装向导引导配置 AI、创建错题本。
3536

3637
## 推荐使用流程

‎doc/wiki/MCP-Server.md‎

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# MCP 服务
2+
3+
外部 agent(Claude Code、Cursor、Claude Desktop、Openclaw 等)可通过 [Model Context Protocol](https://modelcontextprotocol.io/) 的 Streamable HTTP 调用本系统的错题本、错题、知识点与复习数据。
4+
5+
端点:`POST /api/mcp`。实现为无状态服务,每次请求返回 JSON 响应,不维护 `Mcp-Session-Id`;`GET` 返回 `405`(不提供独立 SSE 流)。目标账号固定,所有工具只读写该账号的数据。
6+
7+
## 数据流
8+
9+
```text
10+
外部 agent → POST /api/mcp(Bearer 或 x-api-key)
11+
→ MCP 工具(list_questions / add_question 等)
12+
→ 本系统数据库(固定账号的数据)
13+
```
14+
15+
## 服务端配置
16+
17+
```dotenv
18+
MCP_API_KEY=替换为随机生成的集成密钥
19+
MCP_USER_EMAIL=student@example.com
20+
```
21+
22+
- `MCP_API_KEY`:调用方提交的集成密钥,可用 `openssl rand -hex 32` 生成。
23+
- `MCP_USER_EMAIL`:固定目标账号,填邮箱(也可填用户名);账号须存在且启用。
24+
25+
两项都非空时端点才开放;缺失时返回 `503`。修改环境变量后需重启或重建服务。一个端点对应一个账号,多账号需要分别部署,或用不同账号的数据目录各跑一个实例。
26+
27+
## 认证
28+
29+
请求头任选其一:
30+
31+
- `Authorization: Bearer <MCP_API_KEY>`(推荐)
32+
- `x-api-key: <MCP_API_KEY>`
33+
34+
密钥比较使用定长比较。密钥错误或账号不存在/停用时返回 `401`。密钥会出现在请求头中,跨网络访问应使用 HTTPS,避免写入日志。
35+
36+
## 客户端配置
37+
38+
Claude Code:
39+
40+
```bash
41+
claude mcp add --transport http wrong-notebook http://localhost:3000/api/mcp \
42+
--header "Authorization: Bearer ${MCP_API_KEY}"
43+
```
44+
45+
其他支持 Streamable HTTP 的客户端(Claude Desktop、Cursor 等)按各自格式填写 URL 与请求头,例如:
46+
47+
```json
48+
{
49+
"mcpServers": {
50+
"wrong-notebook": {
51+
"type": "http",
52+
"url": "http://localhost:3000/api/mcp",
53+
"headers": { "Authorization": "Bearer 替换为MCP_API_KEY" }
54+
}
55+
}
56+
}
57+
```
58+
59+
各客户端的字段名可能不同(如 `streamable-http`),以 URL 与请求头为准。
60+
61+
## 手工验证
62+
63+
初始化:
64+
65+
```bash
66+
curl --fail-with-body http://localhost:3000/api/mcp \
67+
-H 'Content-Type: application/json' \
68+
-H 'Accept: application/json, text/event-stream' \
69+
-H "Authorization: Bearer ${MCP_API_KEY}" \
70+
--data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'
71+
```
72+
73+
列出工具:把 `method` 换成 `tools/list`。调用工具:
74+
75+
```json
76+
{
77+
"jsonrpc": "2.0",
78+
"id": 2,
79+
"method": "tools/call",
80+
"params": {
81+
"name": "add_question",
82+
"arguments": {
83+
"notebookId": "错题本ID",
84+
"questionText": "解方程 x+1=2",
85+
"answerText": "x=1",
86+
"analysis": "移项",
87+
"knowledgePoints": ["一元一次方程"],
88+
"gradeSemester": "七年级上",
89+
"difficultyStars": 2
90+
}
91+
}
92+
}
93+
```
94+
95+
`Accept` 可省略,服务会补齐;`Content-Type` 必须为 `application/json`。请求体上限 24 MiB,供含 Base64 原图的 `add_question` 使用。
96+
97+
## 工具
98+
99+
| 工具 | 作用 | 主要参数 |
100+
| --- | --- | --- |
101+
| `list_notebooks` | 列出错题本与题目数 | 无 |
102+
| `create_notebook` | 创建错题本 | `name`、`stage`、`subjectKey`、`tagSet` |
103+
| `list_questions` | 筛选、搜索与分页错题 | `notebookId`、`query`、`tag`、`chapter`、`mastery`、`timeRange`、`gradeSemester`、`paperLevel`、`questionTypes`、`page`、`pageSize` |
104+
| `get_question` | 读取单题正文、答案、解析、标签与掌握状态 | `id`(CUID 或 6 位短 ID)、`includeImage` |
105+
| `add_question` | 新增错题;未知知识点会按标签体系创建 | 题目文字/图片、`knowledgePoints`、`notebookId` 或 `subjectName`、`gradeSemester`、难度与题型等 |
106+
| `list_tags` | 列出知识点标签 | `subject`、`tagSet`、`query`、`flat`(默认叶子列表) |
107+
| `list_due_reviews` | 今日待复习错题 | `notebookId`、`page`、`pageSize` |
108+
| `get_weak_tags` | 薄弱知识点排行 | `notebookId`、`range`(`7d`/`30d`/`6m`/`all`)、`limit` |
109+
110+
补充约定:
111+
112+
- 工具结果均为 JSON 文本;客户端按 JSON 解析。调用失败返回 `isError: true`。
113+
- `add_question` 沿用「添加错题」接口的判重、年级与卷别规则;重复题返回 `duplicate` 并记录一次做错。未填 `gradeSemester` 且账号使用「AI 识别」年级规则时,会补充一次 AI 识别并计入每日用量;账号尚未同意 AI 数据授权时,需要 AI 的调用失败。
114+
- `get_question` 默认不返回原图;`includeImage: true` 时可能返回很大的 Base64 data URL。
115+
- `list_questions` 返回列表卡片字段(题干、标签、掌握状态等),不返回解答、动画和大图;`pageSize` 上限 1000。
116+
- `list_tags` 默认返回叶子知识点名称,可直接用于 `add_question` 的 `knowledgePoints`。
117+
118+
实现依据:[MCP 路由](https://github.com/margrop/wrong-notebook/blob/main/src/app/api/mcp/route.ts)、[工具注册](https://github.com/margrop/wrong-notebook/blob/main/src/lib/mcp/server.ts)、[数据访问](https://github.com/margrop/wrong-notebook/blob/main/src/lib/mcp/service.ts)。

‎doc/wiki/en/Home-en.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ This Wiki covers [margrop/wrong-notebook](https://github.com/margrop/wrong-noteb
1818
| Preferences, the app time zone and user permissions | [Settings and Users](Settings-and-Users-en) |
1919
| Export personal data or back up the whole site | [Backup and Restore](Backup-and-Restore-en) |
2020
| Batch-import questions from an external Openclaw agent | [Openclaw Integration](Openclaw-Integration-en) |
21+
| Let external agents read and write questions, tags and review data via MCP | [MCP Server](MCP-Server-en) |
2122
| Code structure, tests and contribution rules | [Development](Development-en) |
2223
| Sign in after a fresh install; troubleshoot recognition, formulas or screenshots | [FAQ](FAQ-en) |
2324

@@ -30,7 +31,7 @@ This Wiki covers [margrop/wrong-notebook](https://github.com/margrop/wrong-noteb
3031
- Question bank file import (JSON / Word / Excel / CSV / PDF, with an as-is mode that skips AI calls) and exporting selected questions as JSON, Excel or Word.
3132
- Similar-question practice with AI grading, daily review, exam papers built from mistakes, answer history, mastery probability, statistics and print export.
3233
- Shared question banks: download primary, junior-high and senior-high packages from the [shared bank repository](https://github.com/margrop/wrong-notebook-question-bank); imported questions stay in the bank by default, and practice can pick by knowledge point.
33-
- Per-user data isolation, daily AI limits, admin settings, personal preferences and Openclaw batch import.
34+
- Per-user data isolation, daily AI limits, admin settings, personal preferences, Openclaw batch import and an MCP server.
3435
- Fresh installs set up the admin with a one-time setup link (the install wizard on fnOS) instead of a fixed default password, then the setup wizard helps configure AI and create a notebook.
3536

3637
## Recommended workflow

0 commit comments

Comments
 (0)