关于 medium-ops
medium-ops 是用于读取和管理 Medium 文章、回复、拍手、信息流及个人资料的 Python 命令行工具和 MCP 服务。它可由 IDE 宿主的大模型起草回复,无需单独的 AI API 密钥,并通过去重和审计日志支持写入审核。
主要功能
- 01读取文章、信息流和个人资料
- 02发布文章和回复
- 03起草并审批回复
- 04写入默认试运行并去重
- 05审计操作并查看状态
- 06安装 MCP 宿主配置
适用场景
- 01查找尚未回复的评论
- 02发布前起草并审核回复
- 03发布 Medium 文章
- 04查看文章统计和拍手数
MCP 相关
stdio MCP 服务通过 22 个工具提供 Medium 操作,并可为支持的宿主安装配置。回复由宿主大模型起草,发布操作可先暂存以供审批。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx medium-opsMEDIUM_INTEGRATION_TOKEN密钥Legacy Medium Integration Token (api.medium.com/v1/*). Optional. Generate at medium.com/me/settings → 'Integration tokens' (note: Medium stopped issuing new tokens in 2023).MEDIUM_SID密钥Medium 'sid' cookie value from medium.com (Application → Cookies). Used for authenticated reads + dashboard GraphQL.MEDIUM_UIDMedium 'uid' cookie value. Required alongside sid for some authenticated endpoints.MEDIUM_XSRF密钥Medium 'xsrf' cookie value. Required for any dashboard write (post_response, publish_post, delete_post, draft updates).MEDIUM_CF_CLEARANCE密钥Cloudflare 'cf_clearance' cookie. Only required when Cloudflare challenges your IP for dashboard write calls.MEDIUM_USERNAMEYour Medium handle (without the @). Required for the public RSS read path so the client knows whose feed to fetch.MEDIUM_OPS_MCP_PATHOverride path to the mcp.json file the auth layer reads. Defaults to ~/.cursor/mcp.json.MEDIUM_OPS_LLM_CMDOptional: override the host CLI used by the unattended daemon path (default: auto-detect claude / cursor-agent / codex on PATH). Use {prompt} placeholder if your CLI takes the prompt as an arg.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
medium-ops
独立的 Medium 命令行工具 + 22 工具 MCP 服务,适用于 Cursor MCP、Claude MCP、OpenCode MCP 及任何 stdio MCP 主机。由你的 IDE 起草回复。无需 AI API 密钥。
文章、回复、拍手、动态、个人资料、统计数据、回复引擎、MCP 服务。 一次 Python 安装,一个二进制文件,采用 MIT 许可证。与 substack-ops 同属一系列项目。
简而言之 — 原生支持 MCP(无需 API 密钥,一条命令)
uvx medium-ops mcp install cursor # or claude-desktop, claude-code, opencode, print
# Restart your host. Then in chat:
# "list unanswered responses on post abc123def456"
# "draft a warm reply to response r1"
# "post that draft"
由主机的大模型(Cursor 的、Claude 的)通过
propose_reply / confirm_reply 工具起草回复。无需 ANTHROPIC_API_KEY /
OPENAI_API_KEY。
安装错了?
本项目在 PyPI 上的名称是 medium-ops — 请使用 uv / uvx 安装,而不是从“Medium MCP”搜索结果中找到的、不相关的 npx 包。权威列表:Glama — 06ketan/medium-ops。
兼容平台(MCP)
以下条目有助于搜索发现(搜索关键词);升级前请确认各主机当前的 MCP 文档。
面向开源的平台
| 主机 | 文档 | 常见接入方式 |
|---|---|---|
| OpenCode | OpenCode MCP servers | uvx medium-ops mcp install opencode |
| Continue | Continue | uvx medium-ops mcp install print — 将代码片段粘贴到 Continue 的 MCP 设置中 |
| Zed | Zed | 按照 Zed 文档配置 stdio MCP |
| Cline | Cline | 按照扩展程序 / 市场文档配置 MCP |
| Goose | Goose | 按照 Goose 文档配置 MCP 扩展 |
大型商业技术栈
| 主机 | 文档 | 常见接入方式 |
|---|---|---|
| Cursor | Cursor MCP | uvx medium-ops mcp install cursor |
| Claude(Desktop / Code) | Claude Desktop、Claude Code | mcp install claude-desktop / claude-code |
| GitHub Copilot | Copilot | 在支持 MCP 的 VS Code 中使用 — 搭配 print 和主机文档 |
| ChatGPT | OpenAI | 连接器流程 — 不支持 MCP 的工具通常使用 REST |
| Google Gemini | Gemini | 按照 Google 文档使用 Gemini CLI / IDE 功能 |
OpenCode(复制并粘贴)
自动安装:
uvx medium-ops mcp install opencode
手动安装(~/.config/opencode/opencode.json):
{
"mcp": {
"medium-ops": {
"type": "local",
"command": ["uvx", "medium-ops", "mcp", "serve"],
"enabled": true
}
}
}
可选的版本固定:["uvx", "medium-ops==0.1.2", "mcp", "serve"](请替换为 PyPI 上的当前版本)。
为什么采用混合方案
Medium 提供了三种可用接口,我们都使用:
- 公开 RSS(读取,无需认证)。
medium.com/feed/@{user}会返回作者最近约 10 篇文章,包含body_html、pubDate、tags、主图和dc:creator。无需任何凭据,速度比 GraphQL 快,且稳定。默认用于list_posts/get_post/get_post_content。灵感来自 Portfolio_V2 的博客页面。 - Dashboard GraphQL(认证后读取)。
medium.com/_/graphql+medium.com/_/api/*,使用sidCookie。当你请求的文章超过约 10 篇、文章不在 RSS 窗口内,或需要 RSS 无法提供的信息(回复、鼓掌数、信息流、统计数据、搜索)时,作为回退方案使用。 - 官方 REST(写入)。
api.medium.com/v1/*,使用集成令牌。支持createPost、createPostInPublication、getUser、getPublications,仅此而已。
在 posts list、posts show 和 posts content 命令中使用 --source rss|graphql|auto,即可强制指定传输方式。Dashboard 和 GraphQL 端点没有公开文档,Medium 随时可能更改它们。请参阅已知差距。
设置(开发 / 从源代码构建)
git clone https://github.com/06ketan/medium-ops && cd medium-ops
uv sync
uv sync --extra mcp # mcp SDK for the MCP server (recommended)
uv sync --extra tui # textual for the TUI
认证信息从 ~/.cursor/mcp.json 的 mcpServers.medium-ops.env(或
medium-api / medium)读取。可使用环境变量或 .env 覆盖。
uv run medium-ops auth verify
uv run medium-ops quickstart
命令概览
所有写入操作默认使用 --dry-run。使用 --no-dry-run 切换。所有写入记录都会写入 .cache/audit.jsonl,并通过 .cache/actions.db 进行去重检查。
认证(3)
| 命令 | 功能 |
|---|---|
auth verify | 检查集成令牌(/me)和 sid Cookie(GraphQL Viewer)。 |
auth test | 功能相同,但失败时以非零状态码退出(适用于 CI)。 |
auth setup | 交互式地将令牌 / sid / uid / 用户名粘贴到 .env。 |
读取 — 文章(5)
| 命令 | 功能 |
|---|---|
posts list [--user] [--limit] | 列出某位用户的最新文章(默认:自己)。 |
posts show <id_or_url> | 文章元数据(标题、鼓掌数、回复数)。 |
posts content <id> [--md] | 正文 HTML(或使用 --md 获取 Markdown)。 |
posts search <query> [--limit] | 在 Medium 端进行全文搜索。 |
| `posts publish -t "..." -f body.md [--pub] [--status draft | public |
读取 + 写入 — 回复(3)
| 命令 | 功能 |
|---|---|
responses list <post_id> [--limit] | 顶层回复列表。 |
responses tree <post_id> [--out file.json] | 完整的回复及其回复树 JSON。 |
responses add <post_id> "body" [--parent <r_id>] [--no-dry-run] | 发布回复或对回复进行答复。 |
读取 + 写入 — 鼓掌(2)
| 命令 | 功能 |
|---|---|
claps count <post_id> | 鼓掌总数。 |
claps give <post_id> [--claps N] [--no-dry-run] | 鼓掌 1-50 次。受去重保护。 |
读取 — 发现 + 个人资料(5)
| 命令 | 功能 |
|---|---|
feed list [--tab home|following|tag-{slug}] [--limit] | 阅读器信息流。 |
profile me | 你的完整个人资料(GraphQL)。 |
profile get <username> | 任意用户的公开个人资料。 |
profile stats [--days N] | 每篇文章的浏览量 / 阅读量 / 粉丝数(抓取 Dashboard 数据)。 |
profile publications | 你可以发布文章的刊物(集成令牌)。 |
回复引擎(3)
| 命令 | 功能 |
|---|---|
reply template <post_id> --template thanks | 基于规则的回复(无需大模型)。 |
reply bulk <post_id> --out drafts.json | 将每条回复草稿写入文件。 |
reply bulk-send drafts.json [--no-dry-run] | 仅发布 action=approved 的行。会进行去重检查。 |
运维 + 安全(2)
| 命令 | 功能 |
|---|---|
audit search [--kind] [--target] [--status] [--since 7d] | 查询 JSONL 审计日志。 |
audit dedup-status | 统计去重 SQLite 数据库中的记录数。 |
MCP 服务(3)
| 命令 | 功能 |
|---|---|
mcp install <cursor|claude-desktop|claude-code|opencode|print> [--dry-run] | 自动将配置合并到你的宿主中。 |
mcp serve | stdio MCP 服务(22 个工具)。 |
mcp list-tools | 打印工具注册表。 |
其他(1)
| 命令 | 功能 |
|---|---|
quickstart | 打印快速入门清单。 |
回复模式
| 模式 | 功能 | 安全性 |
|---|---|---|
template | src/medium_ops/templates/*.yaml 下的 YAML 关键词规则 | 默认 dry-run |
bulk | 大模型将每条回复草拟到 drafts.json。编辑后,将 action: "approved" | 离线审核,发送时进行去重检查 |
bulk-send | 仅发布 action: "approved" 的条目 | 默认 dry-run;去重数据库可防止重复回复 |
MCP propose_reply → confirm_reply | 宿主大模型草拟,你逐条批准,并通过令牌验证 | 令牌 TTL 为 5 分钟,幂等,无需 API 密钥 |
MCP 服务
medium-ops mcp install opencode # ~/.config/opencode/opencode.json
medium-ops mcp install cursor # auto-add to ~/.cursor/mcp.json
medium-ops mcp install claude-desktop # auto-add to claude_desktop_config.json
medium-ops mcp install claude-code # uses `claude mcp add`
medium-ops mcp install print # print the snippet only
medium-ops mcp serve # stdio server
medium-ops mcp list-tools # 22 tools
手动配置片段:
{
"mcpServers": {
"medium-ops": {
"command": "medium-ops",
"args": ["mcp", "serve"]
}
}
}
如果未安装 mcp SDK,服务会回退到精简的
stdin/stdout JSON 行分发器:
echo '{"tool":"list_posts","args":{"limit":3}}' | medium-ops mcp serve
MCP 原生草拟流程(无需 API 密钥)
让无人值守模式安全运行的安全与草拟机制:
| 工具 | 功能 |
|---|---|
get_unanswered_responses | 待处理列表——你尚未回复的内容。 |
propose_reply | 仅 dry-run。返回 token 和载荷预览。 |
confirm_reply | 按令牌发布暂存的回复。通过去重数据库实现幂等。令牌 TTL 为 5 分钟。 |
bulk_draft_replies / send_approved_drafts | 基于文件的离线审核流程。 |
audit_search / dedup_status | 读取审计日志和去重计数。 |
大模型策略
两种方式,均免费:
- MCP 原生(默认)。 宿主大模型通过
propose_reply/confirm_reply草拟。无需环境变量,也无需 API 密钥。用于交互式回复。 - 子进程 CLI(守护进程路径)。 当没有人工参与时,用于
reply bulk。 自动检测 PATH 上的claude(Claude Code)、cursor-agent或codex。 使用MEDIUM_OPS_LLM_CMD覆盖。
不提供付费 API 密钥路径。
身份验证设置
Medium 有两层身份验证,分别对应不同的功能:
- Integration Token —
Authorization: Bearer <token>。用于访问api.medium.com/v1/*。可使用:publish_post、list_own_publications。在以下位置生成令牌: https://medium.com/me/settings → “Integration tokens”。 注意:Medium 自 2023 年起停止发放新令牌。 如果你从未 生成过令牌,写入路径将返回 401,任何写入操作都必须使用 sid Cookie 路径。 - sid Cookie — 来自
medium.com(Application → Cookies →sid)。 用于访问medium.com/_/graphql和medium.com/_/api/*。可使用: 所有读取功能(文章、回复、拍手、动态、统计数据、个人资料),以及clap_post和post_response(不稳定——未公开文档)。
medium-ops auth verify
medium-ops auth test
medium-ops auth setup
medium-ops auth har ./medium.har # ingest a Chrome devtools HAR export
从 HAR 刷新身份验证信息
当 Cookie 轮换或 Medium 更改 GraphQL 架构时,最快的修复方法是:
- 在 Chrome 中打开
medium.com,并打开开发者工具 → Network 面板。 - 重现失败的操作(发布草稿、发布回复等)。
- 右键点击任意请求 → “Save all as HAR with content”。
- 运行
medium-ops auth har ./medium.har
此操作会:
- 将最新的
sid、uid、xsrf、cf_clearanceCookie 合并到.env(保留其他所有内容) - 将经过脱敏的快照写入
.cache/har-snapshot.json,列出检测到的每个 Medium GraphQL 操作,以及其请求变量/响应数据的键结构——便于与client.py中硬编码的查询进行差异对比,在用户遇到问题之前发现架构变更。
还没有这些信息? 请参阅 docs/AUTH-SETUP.md,查看 5 分钟的浏览器开发者工具操作指南。Medium Integration Token API 自 2023 年起已弃用——如今大多数用户都通过 Cookie 进行身份验证,使用
MEDIUM_SID。
环境变量(或 ~/.cursor/mcp.json → mcpServers.medium-ops.env):
MEDIUM_INTEGRATION_TOKEN=2fb00... # optional, for writes
MEDIUM_SID=1:... # optional, for reads
MEDIUM_UID=... # optional
MEDIUM_USERNAME=yourhandle # optional but recommended
架构
mcp.json | env → auth.py
│
MediumConfig (token? sid? uid? username?)
│
MediumClient (httpx)
┌───────┼──────────┐
▼ ▼ ▼
api.medium.com medium.com/ medium.com/_/
/v1/* (REST) _/graphql api/* (dashboard)
│ │ │
Bearer token sid cookie sid cookie
│
┌──────┬──────┬────────────┬──────┬────────┬──────────┐
▼ ▼ ▼ ▼ ▼ ▼ ▼
posts responses claps profile stats feed reply_engine
│
┌───────────────────┼───────────────┐
▼ ▼ ▼
template ai_bulk MCP propose/confirm
└───────────────────┬───────────────┘
▼
base.post_response
│
┌─────────┼─────────┐
▼ ▼ ▼
dedup audit dry_run
(SQLite) (jsonl)
mcp/server.py ──── 22 tools ─── all share MediumClient
使用的端点
| 操作 | 方法 + URL |
|---|---|
| 身份验证:集成令牌 | GET https://api.medium.com/v1/me |
| 身份验证:sid Cookie | POST https://medium.com/_/graphql (Viewer) |
| 用户资料 | POST /_/graphql (UserProfileQuery) |
| 故事列表 | POST /_/graphql (UserStreamOverview) |
| 故事元数据 | POST /_/graphql (PostViewer) |
| 故事正文 | POST /_/graphql (PostContent) |
| 搜索故事 | POST /_/graphql (SearchPosts) |
| 回复 | POST /_/graphql (PostResponses) |
| 信息流 | POST /_/graphql (HomeFeed / FollowingFeed / TagFeed) |
| 发布故事 | POST https://api.medium.com/v1/users/{id}/posts |
| 发布到 publication | POST https://api.medium.com/v1/publications/{pub_id}/posts |
| 自己的 publication | GET https://api.medium.com/v1/users/{id}/publications |
| 拍手 | POST https://medium.com/_/api/posts/{id}/clap(未公开文档) |
| 发布回复 | POST https://medium.com/_/api/posts(未公开文档) |
| 统计数据 | GET https://medium.com/@{username}/stats?count=...(未公开文档) |
相关 MCP
- slideshot — HTML → 幻灯片(PNG / PDF / PPTX);npm
slideshot-mcp。 - substack-ops — Substack 帖子、笔记、评论 + MCP(PyPI
substack-ops)。
测试
uv run pytest -q
覆盖范围:身份验证加载、客户端传输 + XSSI 剥离、去重数据库、审计日志搜索、MCP 工具注册表 + 分发器、MCP 安装主机配置合并、提议/确认流程 + 令牌过期、回复引擎模板匹配 + 去重与审计流程、子进程大模型检测。
已知不足
- Medium 于 2023 年停止发放新的集成令牌。 如果你从未获得过令牌,
publish_post/list_own_publications会返回 401。读取、回复和拍手路径仍可通过 sid 使用。RSS 读取路径完全不需要凭据。 - RSS 最多仅提供约 10 篇帖子,且不包含拍手/回复数量和统计数据。需要更多内容时,传入
--source graphql(需要 sid),或设置--limit > 10,客户端会自动回退到 GraphQL。 - GraphQL 操作名称和架构会悄然变化。
client.py中的查询与当前仪表板使用的查询一致——预计每隔几个月就会出现问题。请固定此软件包的版本。 post_response使用 GraphQLsavePostResponse(deltas: [Delta!]!, inResponseToPostId: ID!)。Delta 结构为{type: 1, index: N, paragraph: {type: 1, text, markups: []}}(type=1 表示插入;paragraph.type=1 表示 P)。根据错误消息逆向分析得出。update_draft_content使用仪表板的POST /p/{id}/deltas,请求体为{baseRev, rev, deltas}。对于全新的草稿,baseRev=-1, rev=0。 后续编辑应同时递增这两个值。clap_post仍使用未公开文档的/_/api/posts/{id}/clap格式; 尚未针对新的 GraphQL 接口重新验证。请先进行试运行。- 仅限会员阅读的故事会返回付费墙预览,除非
sid属于付费会员。 - 没有“restack”的等效操作。 Medium 不支持转发;最接近的操作是拍手 + 回复。可以同时使用
clap_post+post_response来实现。 - 没有笔记/短内容。 Medium 于 2018 年取消了短内容功能。
- 尚未实现 Chrome Cookie 自动获取(substack-ops 中的
auth_chrome流程)。目前请将你的sid粘贴到.env中。 - 尚未实现 TUI;目前保留了 extras 固定项,供未来开发使用。
许可证
MIT。参见 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。