AugustusW/sharedoc-mcp

GitHub: AugustusW/sharedoc-mcp

一个 MCP stdio 服务器,让 AI agent 能够将生成的 Markdown 文档以可共享链接的形式发布、管理和撤销,支持 GitHub Gist 和本地自托管两种后端。

Stars: 4 | Forks: 0

# sharedoc-mcp English | [繁體中文](./README.zh-TW.md) [![npm](https://img.shields.io/npm/v/sharedoc-mcp?color=brightgreen)](https://www.npmjs.com/package/sharedoc-mcp) [![Release](https://img.shields.io/github/v/release/AugustusW/sharedoc-mcp?color=brightgreen)](https://github.com/AugustusW/sharedoc-mcp/releases) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Node](https://img.shields.io/badge/node-%E2%89%A522.13-blue.svg)](https://nodejs.org/) [![MCP](https://img.shields.io/badge/MCP-stdio%20server-orange.svg)](https://modelcontextprotocol.io/) [![Claude Code](https://img.shields.io/badge/Claude%20Code-compatible-orange.svg)](https://claude.com/claude-code) [![Codex](https://img.shields.io/badge/Codex-compatible-black.svg)](https://developers.openai.com/codex/) 一个 [MCP](https://modelcontextprotocol.io/) stdio server — 可在 [Claude Code](https://claude.com/claude-code)、Codex CLI 以及任何 MCP client 中运行 — 它为你的 agent 提供 **8 个工具,用于发布、更新、搜索和撤销可共享的文档**。在一个接口背后有两种可插拔的后端:**gist**(零配置,借用你已登录的 `gh` CLI)和 **selfhost**(你机器上的 SQLite,支持密码和强制过期)。 ## 为什么需要? AI agent 会不断生成 Markdown —— 报告、研究摘要、会议记录。要将这些内容传递给其他人,通常意味着将大段文本复制粘贴到聊天窗口中。 ``` Without sharedoc-mcp With sharedoc-mcp ──────────────────── ───────────────── copy a wall of text into chat "share this as a doc" paste again for each person one link for everyone content lives in chat scroll revoke / extend / append later "can you password it?" …no selfhost backend: bcrypt + expiry ``` ## 功能 - ✓ 8 个 MCP 工具:创建 / 追加 / 延长 / 重置密码 / 重命名 / 撤销 / 删除 / 搜索 - ✓ `sharedoc-mcp serve` daemon 模式 —— 即使 MCP client 关闭,selfhost 链接依然有效 - ✓ 内容搜索:根据文档内容查找旧的分享链接,而不仅仅是标题 - ✓ `GET /healthz` —— 支持身份验证的健康探针,用于外部监控 / 重启自动化 - ✓ 两种后端,一个接口 —— 只需一个环境变量即可切换,工具 schema 保持不变 - ✓ **Gist 后端**(默认):通过已登录的 `gh` CLI 创建 secret gist —— 无需管理 token,无需托管新内容 - ✓ **Selfhost 后端**:文档保留在你的机器上(通过内置的 `node:sqlite` 使用 SQLite —— 零原生模块) - ✓ 服务器端验证密码(bcrypt)并限制尝试频率 —— 每分钟 5 次,HTTP 429,计数器持久化在 SQLite 中,因此重启无法重置它们(selfhost) - ✓ 强制过期(410)和撤销,并设有 7 天的内容清除宽限期(selfhost);惰性过期清理(gist) - ✓ 通过 `marked` + `sanitize-html` 渲染 Markdown —— 共享内容中的 script、event handler 和 `javascript:` URL 都会被剔除 - ✓ Viewer 仅绑定 **127.0.0.1**,并带有严格的安全响应头(CSP `default-src 'none'`、nosniff、DENY framing、no-referrer、no-store) —— 暴露程度完全由你控制的 tunnel 决定(方案见下文) - ✓ 用于 `search_shared_docs` 的本地索引 + 创建去重(5 分钟内相同的无保护重试会返回相同的 URL;带有密码或过期时间的重试总是会创建一个新文档) - ✓ 两个 MCP client 可以共享同一个数据目录:SQLite WAL + busy timeout,支持优雅的端口共享 - ✓ 70 个离线测试;`npm test` 在干净的 checkout 上即可通过 ## 安装 要求 Node.js ≥ 22.13.0。Gist 后端还需要登录 [GitHub CLI](https://cli.github.com)(`gh auth login`)。 **选项 A —— Claude Code(一行命令):** ``` claude mcp add sharedoc --scope user -- npx -y sharedoc-mcp@^2 ``` **选项 B —— Codex CLI**(`~/.codex/config.toml`): ``` [mcp_servers.sharedoc] command = "npx" args = ["-y", "sharedoc-mcp@^2"] ``` **选项 C —— 任何其他 MCP client:** 运行 `npx -y sharedoc-mcp@^2` 作为 stdio server。 ## 选择你的后端 | | 🅰 `gist`(默认) | 🅱 `selfhost` | |---|---|---| | 设置 | 无 —— 使用你已登录的 `gh` CLI | 无需额外设置 —— 数据保留在你的机器上 | | 文档存储于 | GitHub(secret gist) | 你的机器(SQLite) | | 链接可访问性 | 随处可即时访问 | 仅限 localhost —— 添加 tunnel 可在外部共享 | | 密码 | ✗(secret URL 即为保护措施) | ✓ 服务器端验证(bcrypt),受频率限制 | | 过期 | 惰性 —— 过期的 gist 会在下次使用时被删除 | 强制 —— 过期链接返回 410 | | 撤销 | gist 立即被删除,不可逆 | 立即返回 410,内容在 7 天宽限期后被清除 | ### Gist 快速开始 让你的 agent “将其作为文档共享” —— 它会调用 `create_shared_doc` 并返回一个 secret gist URL。secret gist 不会被公开列出,且该 URL 是不可猜测的,但 **任何拥有该链接的人都可以读取它** —— 这就是该后端完整的安全模型。需要密码保护?请使用 `selfhost`。 本地索引(`~/.config/sharedoc-mcp/index.json`)会记录你共享过的内容,为搜索和过期清理提供支持。这里的过期机制是*惰性的*:过期的 gist 会在下次运行任何工具时被删除,而不是在确切的过期时刻。 ### Selfhost 快速开始 ``` claude mcp add sharedoc --scope user --env SHAREDOC_BACKEND=selfhost -- npx -y sharedoc-mcp@^2 ``` 文档存放在 `~/.local/share/sharedoc-mcp/` 的 SQLite 中;viewer 会在 `http://127.0.0.1:8377` 提供服务。要与本机之外的人共享,请在其前方放置一个 tunnel 并设置 `SHAREDOC_PUBLIC_URL`: | 方案 | 适用场景 | 设置方法 | |---|---|---| | **Tailscale private**(推荐) | 接收方是你自己的设备,或是你可以邀请加入你 tailnet 的人 | `tailscale serve --bg 8377` → `https://..ts.net`,**仅能在你的 tailnet 内部**访问 —— 不会暴露在公共互联网上 | | **Tailscale Funnel** | 与任何人共享,无需域名 | `tailscale funnel 8377` → 相同的稳定 URL,但是公开的 | | **Cloudflare named tunnel** | 你拥有一个域名 | 在 Cloudflare 上绑定域名,`cloudflared tunnel create` + 将 hostname 路由到 `http://127.0.0.1:8377` | | **cloudflared quick tunnel** | 一次性共享 | `cloudflared tunnel --url http://127.0.0.1:8377` → 随机 URL,每次重启都会改变 | #### 拥有域名?Cloudflare named tunnel 详细步骤 一个带品牌的、稳定的共享 URL,例如 `https://docs.example.com/docs/` —— TLS 由 Cloudflare 处理,甚至可以在 NAT 后运行: ``` # 一次性设置(domain 已添加到 Cloudflare —— free plan 足够) cloudflared tunnel login cloudflared tunnel create sharedoc cloudflared tunnel route dns sharedoc docs.example.com ``` `~/.cloudflared/config.yml`: ``` tunnel: sharedoc credentials-file: ~/.cloudflared/.json ingress: - hostname: docs.example.com service: http://127.0.0.1:8377 - service: http_status:404 ``` 运行 `cloudflared tunnel run sharedoc`(或将其安装为 service 以保持常驻),并使用公网 URL 注册 MCP server: ``` claude mcp add sharedoc --scope user \ --env SHAREDOC_BACKEND=selfhost \ --env SHAREDOC_PUBLIC_URL=https://docs.example.com \ -- npx -y sharedoc-mcp ``` 这能解锁的额外功能:免费获得 Cloudflare 的 DDoS protection;你可以叠加 WAF 规则,或者在除共享路径之外的所有内容前部署 [Cloudflare Access](https://www.cloudflare.com/zero-trust/products/access/)(SSO) —— 实现“内部 SSO,外部共享需密码保护”的分离。 **替代方案 —— 无需家用机器的常驻运行:** 在 VPS 上运行 sharedoc-mcp(你的 agent 也在此运行),并使用你的域名和自动 TLS 将 nginx/caddy 指向 `127.0.0.1:8377`;无需 tunnel。 环境变量: | 变量 | 默认值 | 含义 | |---|---|---| | `SHAREDOC_BACKEND` | `gist` | `gist` 或 `selfhost` | | `SHAREDOC_PORT` | `8377` | viewer 端口(selfhost) | | `SHAREDOC_PUBLIC_URL` | `http://127.0.0.1:` | 共享链接中的 URL 前缀 —— 设置为你的 tunnel hostname | | `SHAREDOC_DATA_DIR` | `~/.local/share/sharedoc-mcp` | SQLite 位置(selfhost) | | `SHAREDOC_INDEX_PATH` | `~/.config/sharedoc-mcp/index.json` | 本地索引(gist) | | `MCP_CALLER` | — | 所创建文档的默认作者署名 | ## 8 个工具 | 工具 | 功能 | |---|---| | `create_shared_doc` | 标题 + Markdown(+ 可选密码 / `expires_in_hours` / 作者) → 共享 URL | | `append_to_shared_doc` | 追加 Markdown(非幂等操作 —— 重试会追加两次) | | `extend_shared_doc` | 延长 N 小时的有效期 | | `reset_shared_doc_password` | 设置 / 更改 / 移除(设为 null)密码(仅限 selfhost) | | `update_shared_doc_title` | 重命名 | | `revoke_shared_doc` | 停用链接,保留记录(具体语义见后端表格) | | `delete_shared_doc` | 停用链接并擦除记录 —— 不可逆;需要 `confirm: true`(agent 应首先获得用户的明确批准) | | `search_shared_docs` | 无参数 = 列出最新链接;标题子串、正文文本搜索(selfhost:全内容;gist:开篇摘要)、状态过滤 | ## 隐私 各后端的数据流向: - **Gist 后端**:你的文档内容会作为你账号下的 secret gist 上传到 GitHub —— 适用 GitHub 的条款和保留策略。本地索引保留在 `~/.config/sharedoc-mcp/` 中 —— 它存储标题、URL、时间戳以及每个文档的前 200 个字符(用于本地内容搜索);绝不存储完整内容。除了你自己的 `gh` CLI 访问 GitHub 外,不会向任何地方发送数据。 - **Selfhost 后端**:除非你接入了 tunnel,否则内容永远不会离开你的机器 —— 此时的数据将服务于你提供链接的对象(以及 tunnel 提供商中继的流量)。密码仅以 bcrypt 哈希存储。 - sharedoc-mcp 本身没有任何遥测,也不会调用任何属于它自己的第三方服务。 ## 安全语义,实话实说 - **Gist 链接即不记名 token**:任何拥有该 URL 的人都能读取该文档。撤销操作会立即且不可逆地删除 gist。 - Selfhost 密码在提供内容之前会在服务器端进行验证;只有**错误的**尝试会受到频率限制(每个来源+文档每分钟 5 次;正确的解锁会清除计数器),计数器持久化在 SQLite 中 —— 重启服务器并不会重置它们。**在 tunnel 后端,所有外部访问者共享一个源地址**,因此实际限制为每个文档每分钟 5 次 —— 这比针对单个访问者的限制更严格;一个人输错密码可能会短暂地为其他人锁定该文档。 - 刻意**不提供文件共享工具**:一个允许任意路径的“共享此文件”工具是一个典型的 prompt injection 数据泄露途径(如 `.env`、密钥) —— 被劫持的 agent 可能会发布机密。我们选择移除它而不是进行白名单过滤。 - viewer 绝不会绑定到 127.0.0.1 以外的地方。它是否以及如何接入互联网,完全取决于你的 tunnel 配置。 ## 开发 ``` git clone https://github.com/AugustusW/sharedoc-mcp.git cd sharedoc-mcp npm install npm test # builds, then runs 70 offline tests — gh CLI is mocked, HTTP tests hit 127.0.0.1 only ``` 版本控制:每次发布都会提升 `package.json` 中的 `version`,添加 [CHANGELOG](./CHANGELOG.md) 条目,并以 git tag + [GitHub Release](https://github.com/AugustusW/sharedoc-mcp/releases) + [npm](https://www.npmjs.com/package/sharedoc-mcp) 的形式发布。 **获取更新通知**:关注此仓库(Custom → Releases)。`npx -y` 在每次冷运行时都会获取最新发布的版本;你的索引和文档数据库独立于包之外 —— 更新永远不会触及它们。 ## 状态 v2.1.0 ([CHANGELOG](./CHANGELOG.md)) —— 核心逻辑由 70 个离线单元/集成测试覆盖(`gh` CLI 已被 mock;HTTP 测试仅针对 127.0.0.1 运行;无需网络)。完整的流程已手动验证(2026-07-25:通过基于 stdio JSON-RPC 的构建服务器执行真实的 secret-gist 创建/索引/删除,以及完整的 selfhost 密码流程端到端测试 —— 表单 → 密码错误 401 → 密码正确 200 → 频率限制 429 → 撤销 410 —— 外加 `lsof` 对仅绑定 127.0.0.1 的确认),测试环境包括: - macOS (Apple Silicon)、Node v25 —— gist + selfhost 后端 Tunnel 方案是根据工具的标准行为的;Windows/Linux 以及真实 tunnel 的端到端运行**尚未经过验证** —— 欢迎提供反馈报告。 ## 许可证 MIT © AugustusW
标签:AI, GNU通用公共许可证, MCP, MITM代理, Node.js, SOC Prime, SQLite, 开发工具, 文档分享, 自动化代码审查, 自动化攻击