后端 (book_mcp_server.py, 335 行, 15 个 MCP 工具):
- create_book / add_document / mark_html_ready / mark_json_ready / mark_failed
- update_book_status / soft_delete_book / retry_failed
- get_book / list_books / get_document / list_documents / get_document_url
- upload_to_rustfs / health
- 走 JSON-RPC + stateless_http + json_response(前端可直接调)
- launchd 守护 / 6 秒拉起(macOS)
- systemd 守护脚本(Linux/codelab)
存储:
- MongoDB (mongo:8.0 容器) - book/book_document/document_file 三表
- RustFS 对象存储(fs.code-lab.cn/scan/)- book/<id>/docs/<doc_id>/{docx,html,json}
- 幂等设计: zip_sha256 唯一 + (book_id+original_path) 唯一
前端 (Vue 3 + TS + Arco Design):
- 列表页 /book/list - 搜索 + 状态过滤 + 进度
- 详情页 /book/:id - 文档折叠 + 文件下载
- MCP 客户端 src/api/mcp.ts (JSON-RPC over fetch)
部署:
- deploy/install.sh (codelab 一键装 backend + systemd)
- deploy/install-frontend.sh (vite dev / 生产构建)
- docs/deploy.md (运维手册)
测试:
- tests/test_basic.py (sanity 7 项)
- tests/test_e2e.py (完整 e2e: docx→HTML→入库→上传→校验)
5.3 KiB
5.3 KiB
book-mcp 部署文档
架构
Agent (任意 Agent 客户端)
↓ HTTP/JSON-RPC
book-mcp (8100) ──┬─→ MongoDB (27018/book_mcp) ← docker container
└─→ RustFS (fs.code-lab.cn/scan/) ← 对象存储
└─→ wordparse (8089) ← docker container docx4j
组件
| 组件 | 位置 | 端口 | 启动方式 |
|---|---|---|---|
| book-mcp | ~/WorkSpace/book-mcp/book_mcp_server.py |
8100 | launchd ai.book-mcp.server |
| MongoDB | docker container book-mcp-mongo |
27018 | docker start book-mcp-mongo |
| RustFS | fs.code-lab.cn |
443 | 远程 |
| wordparse (docx4j) | docker container wordparse-test |
8089 | docker start wordparse-test |
安装(一次性)
1. MongoDB 容器
docker run -d \
--name book-mcp-mongo \
-p 27018:27017 \
-e MONGO_INITDB_ROOT_USERNAME=book_admin \
-e MONGO_INITDB_ROOT_PASSWORD=book_mongo_2026 \
-e MONGO_INITDB_DATABASE=book_mcp \
-v book-mcp-mongo-data:/data/db \
--restart unless-stopped \
mongo:8.0
2. Python venv(一次性)
python3.13 -m venv /tmp/wordparse_venv
/tmp/wordparse_venv/bin/pip install -r ~/WorkSpace/book-mcp/requirements.txt
依赖:fastmcp boto3 pymongo pyyaml
3. MongoDB 索引
/tmp/wordparse_venv/bin/python ~/WorkSpace/book-mcp/book_mcp_server.py --init-db
输出:
✓ MongoDB 已就绪(db: book_mcp, collections: [...])
✓ 8 个索引创建完成
4. LaunchAgent
# 装(已装好:~/Library/LaunchAgents/ai.book-mcp.server.plist)
launchctl load -w ~/Library/LaunchAgents/ai.book-mcp.server.plist
日常运维
状态查询
# launchd 状态
launchctl print gui/501/ai.book-mcp.server | grep -E "state|pid"
# 端口
lsof -i :8100
# 健康
curl http://127.0.0.1:8100/mcp
# fastmcp 在 /mcp 走 HTTP
# 实时日志
tail -f ~/.hermes/services/book-mcp/logs/server.log
重启
# 软重启(SIGTERM,launchd 30s ThrottleInterval)
kill $(lsof -ti :8100)
# launchd 自动拉起
sleep 5
ps aux | grep book_mcp_server | grep -v grep
调试
# 1. 跑 e2e 测试
/tmp/wordparse_venv/bin/python ~/WorkSpace/book-mcp/tests/test_e2e.py
# 2. 直接调 MCP 工具(fastmcp client)
/tmp/wordparse_venv/bin/python << 'PYEOF'
import asyncio
from fastmcp.client import Client
async def main():
async with Client("http://127.0.0.1:8100/mcp") as c:
r = await c.call_tool('health', {})
print(r.data)
asyncio.run(main())
PYEOF
# 3. mongo 直连
/tmp/wordparse_venv/bin/python << 'PYEOF'
from db import get_collection, COL_BOOK
print(f"books count: {get_collection(COL_BOOK).count_documents({})}")
PYEOF
配置
~/WorkSpace/book-mcp/config.yaml:
server:
port: 8100 # MCP server 端口
database:
url: mongodb://book_admin:book_mongo_2026@127.0.0.1:27018/book_mcp?authSource=admin
db_name: book_mcp
rustfs:
endpoint: https://fs.code-lab.cn
default_bucket: scan
wordparse:
url: http://127.0.0.1:8089/api/v3/server_office_file/file/parse
timeout: 600
MCP 工具列表(15 个)
| # | 工具 | 类别 |
|---|---|---|
| 1 | create_book | 写入 |
| 2 | add_document | 写入 |
| 3 | mark_html_ready | 写入 |
| 4 | mark_json_ready | 写入 |
| 5 | mark_failed | 写入 |
| 6 | update_book_status | 写入 |
| 7 | get_book | 查询 |
| 8 | list_books | 查询 |
| 9 | get_document | 查询 |
| 10 | list_documents | 查询 |
| 11 | get_document_url | 查询 |
| 12 | upload_to_rustfs | 辅助 |
| 13 | soft_delete_book | 辅助 |
| 14 | retry_failed | 辅助 |
| 15 | health | 诊断 |
数据流
zip 上传 RustFS
↓ create_book(zip_sha256)
→ book.id
↓ 循环每 docx
→ add_document(filename, path)
→ doc.doc_id = sha1(book_id|path)[:16]
→ wordparse.convert_one (cleaner + docx4j + MathJax)
→ RustFS upload → mark_html_ready(url)
→ Agent 解析 HTML → structure.json
→ RustFS upload → mark_json_ready(url)
→ update_book_status("done")
故障排查
| 现象 | 原因 | 解决 |
|---|---|---|
mongo health=False |
容器没起 | docker start book-mcp-mongo |
wordparse health=False |
docx4j 容器没起 | docker start wordparse-test |
| 8100 端口未 listen | 进程挂了 | kill $(lsof -ti :8100) 走 launchd 自动拉起 |
add_document 报 NoneType |
数据库索引问题(已修复) | 重跑 --init-db |
| 上传 403 Forbidden | 桶不存在 | 检查 default_bucket 是否在 RustFS 实际存在 |
e2e 测试报 uk_name_version |
同名教辅已存在 | 改 name 或 version 加时间戳 |
备份
- MongoDB 数据:
book-mcp-mongo-datadocker volume(在 docker 里) - RustFS 文件:
https://fs.code-lab.cn/scan/book/<book_id>/... - 代码:
~/WorkSpace/book-mcp/
升级路径
# 1. 拉新代码
cd ~/WorkSpace/book-mcp
git pull # 假设推到 git
# 2. 升级依赖
/tmp/wordparse_venv/bin/pip install -r requirements.txt --upgrade
# 3. 重启 launchd
kill $(lsof -ti :8100)
sleep 5
ps aux | grep book_mcp_server | grep -v grep
相关链接
- 设计文档:
docs/book-mcp-design.md - Schema:
db/schema_doc.md - wordparse 工具:
services/wordparse/ - 启动日志:
~/.hermes/services/book-mcp/logs/server.log - 错误日志:
~/.hermes/services/book-mcp/logs/server.error.log