[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-82278":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":14,"forks30d":14,"starsTrendScore":12,"compositeScore":18,"rankGlobal":9,"rankLanguage":9,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":9,"pushedAt":9,"updatedAt":24,"readmeContent":25,"aiSummary":26,"trendingCount":14,"starSnapshotCount":14,"syncStatus":27,"lastSyncTime":28,"discoverSource":29},82278,"co-reading-mcp","idleprocesscc\u002Fco-reading-mcp","idleprocesscc","A local co-reading MCP server for chunked books, reading progress, search, and margin annotations.",null,"JavaScript",46,12,21,0,4,20,24,63.74,"MIT License",false,"main",true,[],"2026-06-12 04:01:37","# Co-Reading MCP\n\nA local MCP server that gives Claude a durable reading room:\n\n- import EPUB or plain text into stable chunks while preserving EPUB spine\u002Fchapter boundaries\n- list books and chunks\n- read chunk-by-chunk with `prevId` \u002F `nextId`\n- continue directly from the next unread chunk\n- search across a book with cached chunk text\n- write margin annotations\n- stage user notes, submit them to Claude once, and attach Claude replies under them\n- track reading progress\n- surface small shared-margin cards when human and Claude stop at the same passage\n- return a small finish ritual when a book is completed\n\nThe goal is not one-shot summarization. The goal is a shared reading surface where a human and Claude can both read, leave anchored notes, and resume smoothly. Human notes can also stay private until the reader chooses to share them with Claude.\n\nFor a step-by-step setup and usage flow, see [docs\u002Fuser-guide.md](docs\u002Fuser-guide.md).\n\n## Quick Start\n\nRequirements:\n\n- Node.js 18+\n- Python 3.10+ for the import scripts\n\n```bash\ncd co-reading-mcp\ncp -R data.example data\nnode src\u002Fserver.js\n```\n\nIf you also want a human-friendly reading surface, start the bundled reader:\n\n```bash\nnpm run reader\n```\n\nOpen `http:\u002F\u002F127.0.0.1:8787`. This serves a small reference reader and local HTTP API while also keeping the MCP stdio server active in the same process. In Claude Desktop \u002F Claude Code you can point the MCP command at `src\u002Fhttp.js` instead of `src\u002Fserver.js` when you want one process to handle both:\n\n```json\n{\n  \"mcpServers\": {\n    \"co-reading\": {\n      \"command\": \"node\",\n      \"args\": [\"\u002Fabsolute\u002Fpath\u002Fto\u002Fco-reading-mcp\u002Fsrc\u002Fhttp.js\"],\n      \"env\": {\n        \"READING_MCP_DATA_DIR\": \"\u002Fabsolute\u002Fpath\u002Fto\u002Fco-reading-mcp\u002Fdata\",\n        \"READING_HTTP_PORT\": \"8787\"\n      }\n    }\n  }\n}\n```\n\nThe reader's Library header includes an import button for EPUB, TXT, or Markdown files. Browser imports upload the file directly to the co-reading server, so they also work with remote claude.ai setups where chat attachments are isolated from the MCP server filesystem.\n\nFor Claude Desktop \u002F Claude Code, configure the MCP server as a stdio command:\n\n```json\n{\n  \"mcpServers\": {\n    \"co-reading\": {\n      \"command\": \"node\",\n      \"args\": [\"\u002Fabsolute\u002Fpath\u002Fto\u002Fco-reading-mcp\u002Fsrc\u002Fserver.js\"],\n      \"env\": {\n        \"READING_MCP_DATA_DIR\": \"\u002Fabsolute\u002Fpath\u002Fto\u002Fco-reading-mcp\u002Fdata\"\n      }\n    }\n  }\n}\n```\n\n## Remote Server\n\nFor VPS, reverse-proxy, tunnel, or remote MCP clients, run one process:\n\n```bash\nREADING_MCP_DATA_DIR=.\u002Fdata MCP_AUTH_TOKEN=\"change-me\" npm run start:sse\n```\n\nThe same port serves the human reader, REST API, and remote MCP transports:\n\n- `https:\u002F\u002Fyour-domain.example\u002F`: reference reader UI\n- `https:\u002F\u002Fyour-domain.example\u002F?token=change-me`: reader UI with auth saved in a cookie (convenience shortcut — the token appears in the first request URL; avoid on shared devices or high-security setups)\n- `https:\u002F\u002Fyour-domain.example\u002Fapi\u002F*`: reader REST API\n- `https:\u002F\u002Fyour-domain.example\u002Fmcp`: remote MCP JSON-RPC endpoint for custom connectors\n- `https:\u002F\u002Fyour-domain.example\u002Fsse`: legacy MCP SSE transport\n- `https:\u002F\u002Fyour-domain.example\u002F.well-known\u002Foauth-protected-resource\u002Fmcp`: MCP resource metadata for connector discovery\n\nEnvironment variables:\n\n- `MCP_SSE_PORT` or `PORT`: listen port, default `3100`\n- `MCP_SSE_HOST`: listen host, default `0.0.0.0`\n- `MCP_AUTH_TOKEN`: bearer token required by remote clients\n- `MCP_CORS_ORIGIN`: CORS origin. When `MCP_AUTH_TOKEN` is set, defaults to `*`; when unset, defaults to no CORS headers (blocks cross-origin requests)\n- `MCP_MAX_BODY_BYTES`: max JSON-RPC POST body size, default `25000000`\n- `READING_IMPORT_MAX_BYTES`: max EPUB\u002FTXT upload size, default `25000000`\n\nFor Claude custom connectors, prefer the `\u002Fmcp` URL. `\u002Fsse` remains available for older MCP clients that still expect the SSE + `\u002Fmessages` flow.\n\nDo not expose the remote server on the public internet without HTTPS and `MCP_AUTH_TOKEN`. When `MCP_AUTH_TOKEN` is set, the reader, static assets, `\u002Fapi\u002F*`, `\u002Fsse`, `\u002Fmessages`, `\u002Fmcp`, and `\u002Fhealth` require the token. Open the reader once with `\u002F?token=...`; the server sets a same-site cookie and the reader stores the token for API calls. If you use nginx, Caddy, or cloudflared, proxy `\u002F`, `\u002Fapi\u002F*`, `\u002Fsse`, `\u002Fmessages`, `\u002Fmcp`, and `\u002F.well-known\u002F*` to the same local process and make sure streaming responses are not buffered.\n\n## Import Books\n\nPlain text:\n\n```bash\npython3 scripts\u002Fimport_text.py .\u002Fbook.txt --title \"Book Title\" --author \"Author\" --out .\u002Fdata\u002Fbooks\n```\n\nPlain text can also preserve section headings with a multiline regex:\n\n```bash\npython3 scripts\u002Fimport_text.py .\u002Fbook.txt \\\n  --title \"Book Title\" \\\n  --heading-regex \"^第[一二三四五六七八九十百零〇0-9]+[章节回].*$\"\n```\n\nIf a loose heading regex catches navigation labels or other tiny sections, add\n`--min-section-chars 100` or a similar threshold.\n\nEPUB:\n\n```bash\npython3 scripts\u002Fimport_epub.py .\u002Fbook.epub --out .\u002Fdata\u002Fbooks\n```\n\nClaude can also import books through MCP, which is useful on claude.ai or mobile devices where the user cannot SSH into the server:\n\n- `reading_import_book`: one EPUB\u002FTXT as a base64 payload\n- `reading_import_begin` \u002F `reading_import_part` \u002F `reading_import_finish`: chunked upload for larger files\n\nFor example, after a user drops `book.epub` into a Claude chat, Claude can read the file, base64-encode it, and call `reading_import_book`:\n\n```json\n{\n  \"filename\": \"book.epub\",\n  \"dataBase64\": \"...\",\n  \"bookId\": \"optional-stable-id\"\n}\n```\n\nTXT imports can pass the same heading options as the command-line script:\n\n```json\n{\n  \"filename\": \"book.txt\",\n  \"dataBase64\": \"...\",\n  \"title\": \"Book Title\",\n  \"headingRegex\": \"^Chapter\\\\s+\\\\w+\"\n}\n```\n\nThe import tools write into `data\u002Fbooks` immediately; no server restart is needed.\n\nBoth importers create:\n\n```text\ndata\u002Fbooks\u002F\u003Cbook-id>\u002F\n  manifest.json\n  chunks\u002F\n    ch00.txt\n    ch01.txt\n```\n\nEPUB imports keep each spine item as a section boundary. If an EPUB stores the whole book in a single spine item, the importer falls back to internal `h1`\u002F`h2`\u002F`h3` headings. If a chapter is longer than `--max-chars`, only that chapter is split into `Chapter Title Part 1\u002FN`, `Part 2\u002FN`, and so on.\n\nRuntime state is stored outside book content:\n\n```text\ndata\u002F\n  annotations.jsonl\n  progress.json\n  reading_sessions.json\n```\n\n`reading_submit_user_notes` includes full chunk text once per `sessionId` by default, then sends only new notes for the same chunk in that session. Use a new `sessionId` when Claude starts a new conversation\u002Fsession so the relevant chunk context is sent again.\n\n## Tools\n\n- `reading_list_books`\n- `reading_list_chunks`\n- `reading_read_chunk`\n- `reading_continue`\n- `reading_search_chunks`\n- `reading_import_book`\n- `reading_import_begin`\n- `reading_import_part`\n- `reading_import_finish`\n- `reading_import_cancel`\n- `reading_delete_book`\n- `reading_annotate_passage`\n- `reading_list_annotations`\n- `reading_submit_user_notes`\n- `reading_list_submissions`\n- `reading_read_submission`\n- `reading_reply_to_annotation`\n- `reading_mark_read`\n- `reading_card_inbox`\n- `reading_open_card`\n- `reading_save_card`\n- `reading_dismiss_card`\n- `reading_list_cards`\n- `reading_collect_card`\n- `reading_get_progress`\n\nSee [docs\u002Fmcp-tools.md](docs\u002Fmcp-tools.md) and [docs\u002Fdata-format.md](docs\u002Fdata-format.md).\nFor the intended Claude workflow, see [docs\u002Fclaude-workflow.md](docs\u002Fclaude-workflow.md).\n\n## Frontend Integration\n\nThe bundled reader is intentionally small: it is a reference UI, not a required frontend. Existing apps can talk to the same local HTTP API:\n\n- `GET \u002Fapi\u002Fbooks`\n- `DELETE \u002Fapi\u002Fbooks\u002F:bookId`\n- `GET \u002Fapi\u002Fbooks\u002F:bookId\u002Fchunks`\n- `GET \u002Fapi\u002Fbooks\u002F:bookId\u002Fchunks\u002F:chunkId`\n- `GET \u002Fapi\u002Fcontinue?bookId=...`\n- `GET \u002Fapi\u002Fannotations?bookId=...&chunkId=...`\n- `POST \u002Fapi\u002Fannotations`\n- `POST \u002Fapi\u002Freplies`\n- `POST \u002Fapi\u002Fsubmit-notes`\n- `POST \u002Fapi\u002Fmark-read`\n- `GET \u002Fapi\u002Fsearch?q=...&bookId=...`\n- `POST \u002Fapi\u002Fimport`\n\nHuman notes are saved as open local notes first. Pressing \"Send to Claude\" calls `reading_submit_user_notes`, includes chunk context according to the session policy, marks those notes submitted, and avoids resending the same open notes.\n\nDeleting a book removes it from the active library and archives the book folder plus related progress, annotations, submissions, and cards under `data\u002Ftrash\u002Fbooks\u002F...`. Trash is pruned after 30 days by default; set `READING_TRASH_RETENTION_DAYS=0` to keep trash forever.\n\nSmall ritual cards\u002Fbookmarks can be collected with `reading_collect_card`. Claude can then use `reading_card_inbox` like a quiet bookmark inbox, open a visual card with `reading_open_card`, save it as a local image with `reading_save_card`, or clear it with `reading_dismiss_card`. They are meant for completed sections, shared-margin moments, quiet passages worth carrying forward, and a separate `Last Fold` card when the final chunk of a book is marked read.\n\nBy default the card renderer stays zero-dependency and falls back to SVG. For the polished PNG cards, install Playwright's Chromium renderer once:\n\n```sh\nnpm i -D playwright\nnpm run install:card-renderer\n```\n\n## Privacy\n\nThis repo is designed so private content stays in `data\u002F`, which is ignored by git. `data.example\u002F` contains only toy text.\n\n## Contributors\n\n- GPT\n- Claude\n- Koshi\n","Co-Reading MCP 是一个本地的多用户协同阅读服务器，支持分块书籍、阅读进度跟踪、搜索及边注功能。它能够将EPUB或纯文本导入为稳定的章节块，并保留EPUB的目录结构；提供逐章浏览、继续未读部分、全文搜索以及添加边注等功能。此外，该系统还支持用户笔记与Claude（AI助手）之间的交互，允许用户在适当时候分享笔记给Claude并接收反馈。此项目适用于需要深度阅读和批注场景下的个人或团队使用，尤其是当人们希望与AI协作探索文献时。基于JavaScript开发，易于部署于Node.js环境。",2,"2026-06-11 04:08:14","CREATED_QUERY"]