zaydiscold/goodreads-cli-mcp-api
GitHub: zaydiscold/goodreads-cli-mcp-api
一个非官方的 Goodreads Web 界面映射项目,通过共享引擎的 CLI 与 MCP 服务器,解决官方 API 关闭后的数据读取与自动化操作问题。
Stars: 0 | Forks: 0
# Goodreads CLI (MCP + API)
一个非官方的 **API 映射 + CLI + MCP 服务器**,用于已登录的 Goodreads Web 界面 —— 包含书架、书籍、评分、书评、语录以及 Kindle 笔记与高亮 —— 可直接从终端或你的 Agent 驱动,无需打开网站。Amazon 在 2020 年 12 月关闭了面向新 Key 的公共 Goodreads API,因此本项目通过手动映射的 OpenAPI 规范来驱动 Web 界面:一个共享相同引擎的 TypeScript CLI **和** MCP 服务器。**映射才是核心;CLI 和 MCP 只是证明它真实有效的工具。**
## ⚠️ 免责声明
**这是一个独立的、非官方的项目。它不隶属于 Goodreads 或 Amazon,也未获得其认可或批准。**
- **非官方界面。** Amazon 在 2020 年 12 月关闭了面向新 Key 的公共 Goodreads API。本工具驱动的是*已登录的 Web 界面*(包含 HTML 页面、RSS、CSV 导出、Rails-UJS 表单 POST 以及较新的 AppSync GraphQL 操作),这些都是由手动映射完成的。Goodreads 可以在不通知的情况下重命名或轮换其中的任何内容 —— 请信任实时读取的数据,而非记忆中的数据。
- **使用你自己的账号,风险自负。** 它作用于你已经登录的账号,使用你自己的浏览器 Cookie + CSRF token。自动化或非浏览器访问可能违反 Goodreads 的服务条款。请在你自己的账号上使用,并自行承担风险。
- **写入操作会更改你的账号。** 公开/隐藏笔记、移动书架和编辑语录都会真实修改你的账号。每次写入默认均为 dry-run(预演);笔记工作流通过三重门控进行限制(见下文)。
- **无保修。** 按“原样”提供。详见 [LICENSE](LICENSE)。
## 安装说明
```
git clone https://github.com/zaydiscold/goodreads-cli-mcp-api.git
cd goodreads-cli-mcp-api
pnpm install
pnpm build
node cli/dist/index.js --help # or link the bin: goodreads-cli --help
```
需要 **Node ≥ 20** 和 **pnpm**。MCP 服务器通过 `node mcp/dist/server.js` 运行。
## 功能说明
支持对 Goodreads 进行全面的读取**和**写入:
- **书架** — 发现你的书架清单及数量;列出并导出书架(通过 HTML 分页或 RSS),按书籍去重并保留各书架的归属信息。
- **书籍** — 解析任何公开的书籍页面(JSON-LD + Next.js 元数据)。
- **Kindle 笔记与高亮** — 检查笔记元数据,规划并执行公开/隐藏操作(受限门控),并将你的当前/已读书架与笔记索引关联起来。
- **标注** — 提供每条高亮的标注元数据(可见性、剧透、persist endpoint),但不包含原始高亮文本。
- **语录** — 添加、删除和重新排序你的语录(上移/下移/置顶/置底)。
- **评分与书评** — 通过现代 AppSync **GraphQL** 操作(`RateBook`/`UnrateBook`)以及映射的书评写入路由。
- **评论与消息** — 检查评论/消息路由及表单结构,但不发送具体请求体。
- **原始路由驱动** — 直接规划或执行任何已映射的路由。
一切皆**重脱敏优先**:输出内容仅包含数量、状态、耗时、链接结构和路由元数据 —— 绝不包含原始高亮文本、评论正文、Cookie、CSRF token 或私密 URL。
## CLI ↔ MCP 一致性 — 同一引擎,零偏移
让本项目超越了普通脚本的原因在于:**CLI 和 MCP 服务器共享同一个引擎** ([`cli/src/engine.ts`](./cli/src/engine.ts))。每个命令都是调用引擎函数的轻量级包装器;每个 MCP 工具也是如此。它们输出**完全相同**的封装 JSON,因此 Agent 和人类能以相同方式获得相同的答案 —— 并且这两个接口**绝不会产生偏移**。
这种不变性由代码强制保证,而非依赖人为谨慎:引擎中的 `CAPABILITIES` 注册表会受到 [`cli/test/parity.test.ts`](./cli/test/parity.test.ts) 的**双向**检查 —— 每一项能力都必须同时具备 CLI 命令**和** MCP 工具,任何一方都不允许存在孤立项。如果你添加了命令却没有为其配置 MCP 孪生工具,CI 就会报错。
实时工具的准确数量始终以 `tools/list` 为准(目前为 **28 个工具**),绝不是一个硬编码的数字。
## 命令导览 — 用于解答什么问题
所有读取操作均为实时且免费的。所有写入操作默认为 dry-run;笔记工作流需要通过下文提及的三重显式门控。
| 命令 | 解答的问题 |
|---|---|
| `api-map routes` / `api-map search "
"` | "这能驱动什么?" — 已映射的 Goodreads 界面 (89 个路由) | | `api-map browser-routes` | "认证后的 CDP 捕获看到了什么?" — 经过脱敏的路由模板 | | `shelves discover` | "我有哪些书架,每个书架里有多少本书?" | | `books list --shelf` | "列出一个书架" — 来自经过认证的 HTML 固定数据或公开 RSS | | `books export --fixture-dir` | "导出我的书架" — 按书籍去重,并保留各书架归属信息 + 完整性标志 | | `book show ` | "解析这个书籍页面" — JSON-LD + Next.js 元数据 | | `recent-reading list / notes` | "将我当前/已读的书架与 Kindle 笔记索引关联" | | `recent-reading publicize-plan / publicize` | "规划并公开我最近阅读书籍的高亮" (受限门控) | | `notes inspect` | "这个笔记页面里有什么?" — 包含数量 + 可见性,无高亮文本 | | `notes publicize-plan` | "为一本书的笔记构建经过验证的计划" | | `notes publicize` / `notes hide` | "公开 / 隐藏一本书的所有高亮" (受限门控) | | `annotations list / thoughts-plan` | "每条高亮的标注元数据;规划针对单条笔记的想法" | | `quotes add / remove / reorder` | "管理我的语录" (除非使用 `--execute`,否则均为 dry-run) | | `comments list` / `messages folders` / `messages list` | "检查评论/消息页面结构,不含请求体" | | `write-plan books move` / `write-plan notes publicize` | "静态的 dry-run 变更计划" | | `request plan` / `request execute` | "直接驱动任何已映射路由" (execute 具备实时写入能力;传递 `--dry-run` 进行预览) | ## 安全模型 ``` # Reads:实时且免费 goodreads-cli shelves discover --fixture ./fixtures/shelf-read.html goodreads-cli api-map search "publicize notes" # Quote 写入:默认 dry-run;--execute 触发实时的 Rails-UJS POST goodreads-cli quotes reorder --quote-id --direction top # dry-run plan goodreads-cli quotes reorder --quote-id --direction top --execute # live # Notes 公开/隐藏:通过三种方式限制 —— --execute + 精确的 --approved-book-id + env flag GOODREADS_ALLOW_NOTES_PUBLICIZE=1 \ GOODREADS_COOKIE="session-id=..." GOODREADS_CSRF_TOKEN="..." \ goodreads-cli notes publicize --book-id --approved-book-id --execute --json ``` 每次实时变更都会向 stderr 输出一条 `[WRITES TO LIVE GOODREADS]` 警告,其原则是**每次写入后必须验证** —— 永远不要盲目相信 HTTP 200 响应;应重新加载笔记页面并确认可见的数量变动。 ## 从 Agent 中使用 (MCP) ``` pnpm --filter @zaydiscold/goodreads-mcp build # Claude Code: claude mcp add goodreads-cli -s user -- node /abs/path/to/goodreads-cli-mcp-api/mcp/dist/server.js # Hermes: hermes mcp add goodreads --command node --args /abs/path/to/goodreads-cli-mcp-api/mcp/dist/server.js ``` 这 28 个 MCP 工具以 `mcp__goodreads-cli__*` 的形式暴露,并继承与 CLI **相同**的引擎、认证、路由映射和写入门控 —— 因此 `goodreads_notes_publicize` 运行的门控工作流与 `notes publicize` 完全一致。请在服务器环境中传入 `GOODREADS_COOKIE`、`GOODREADS_CSRF_TOKEN` 以及 `GOODREADS_ALLOW_NOTES_PUBLICIZE=1` 以执行实时写入操作。 ## 示例:由 Agent 驱动的笔记公开 向 Agent 发起请求以公开一本书的 Kindle 高亮时,它的操作流程如下:发现路由、检查数量、制定计划,然后在门控机制下执行: ``` $ goodreads-cli api-map search notes # 1. find the route $ goodreads-cli notes publicize-plan --book-id 218134959 \ # 2. preflight counts --detail-fixture ./fixtures/notes-218134959.html --approved-book-id 218134959 --json # => { "detail": { "noteCount": 47, "visibleNoteCount": 0, "hiddenNoteCount": 47 }, # "action": "publicize-notes", "blockers": [] } $ goodreads-cli notes publicize --book-id 218134959 --dry-run --json # 3. dry-run shows the gates $ GOODREADS_ALLOW_NOTES_PUBLICIZE=1 goodreads-cli notes publicize \ # 4. execute --book-id 218134959 --approved-book-id 218134959 --execute --json # 5. 重新加载 /notes/{book_slug}/{user_slug} 并验证 visibleNoteCount === noteCount ``` Agent 绝不会输出原始高亮文本,也不会泄露 Cookie 或 token,即使在自主驱动的情况下,每一次写入也都经过门控。 ## 映射才是核心 真正的工件位于 [`api-map/`](./api-map/): - 记录了未公开 Goodreads Web 界面的 **OpenAPI 3.1** 规范。 - 位于 [`api-map/markdown/`](./api-map/markdown/) 下的**各 endpoint Markdown** 文档。 - 一份 **curl** 参考,确保无需本 CLI 也能复现其中任何操作。 它覆盖了读取界面(HTML 页面、RSS、CSV 导出)和写入 endpoint(从 `data-remote` 操作中捕获的 Rails-UJS 表单 POST),外加用于现代书籍/评分/订阅小组件的 **AppSync GraphQL** 操作。2026 年 6 月 8 日的加固阶段对所有读取路由进行了实时测试,并对可逆的写入操作进行了试火,还完善了语录写入界面(添加/删除/重新排序)。详见 [`docs/write-operations.md`](./docs/write-operations.md)。 ## 架构与扩展 ``` api-map/ ─ the mapped surface (the product) │ cli/src/engine.ts ─ THE SHARED ENGINE (every operation, enveloped output) ├── cli/src/commands/* ─ thin commander wrappers └── mcp/src/server.ts ─ thin MCP tool adapters ``` 发现了被我遗漏的 endpoint?将其添加到 OpenAPI 规范以及 `api-map/` 下的 Markdown 页面中,然后接入**一个引擎函数 + 一个 `CAPABILITIES` 条目**,并添加对应的 CLI 命令和 MCP 工具。一致性测试会告诉你是否漏掉了其中任何一个。完整的开发者操作手册:[`AGENTS.md`](./AGENTS.md)。Agent 操作指南:[`SKILL.md`](./SKILL.md)。 基于由 [Matt Van Horn's Printing Press](https://github.com/mvanhorn/cli-printing-press) 开创的三元组模式(CLI + skill + MCP)构建。 由 Zayd Khan // cold 映射并构建 (@ColdCooks / zaydiscold / zayd.wtf)。MIT © Zayd Khan。
标签:API, Goodreads, MCP, MITM代理, TypeScript, URL抓取, 安全插件, 数据抓取, 自动化攻击