关于 Substack MCP Server
Substack MCP Server 可让 AI 助手或终端管理 newsletter 内容和账户数据。长文仅保存为草稿,须手动审核并发布;Notes 则会立即发布。
主要功能
- 01创建和更新长文草稿
- 02搜索并导出文章
- 03发布短篇 Notes
- 04查看分析数据
- 05管理明确同意的免费订阅者
适用场景
- 01在 Substack 准备文章以供审核
- 02查找并导出存档文章
- 03发布 Note
- 04查看 newsletter 数据或管理主动订阅者
MCP 相关
它通过本地 stdio 或自托管 HTTP 向 MCP 客户端提供 Substack 操作。长文工具只能创建或编辑草稿;Note 工具会立即公开发布。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y @conorbronsdon/substack-mcpSUBSTACK_PUBLICATION_URLYour Substack publication URL (e.g., https://yourblog.substack.com)SUBSTACK_SESSION_TOKEN密钥connect.sid cookie value from your Substack sessionSUBSTACK_USER_IDYour Substack user ID本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
substack-mcp
通过 AI 助手或终端创建和管理你的 Substack 新闻简报。准备丰富的草稿、搜索存档、发布 Notes、查看分析数据,并管理在明确同意后订阅的免费订阅者。审核并在 Substack 中发布长篇文章。

演示会使用离线示例数据运行实际的 MCP 处理程序,不会进行实时 API 调用,也不会发布内容。按照草稿工作流创建、查找、导出并审核文章。
**长篇文章仅能创建草稿;公开操作须明确进行:**此服务无法发布或删除长篇文章。文章工具只能创建和编辑草稿;你需要通过 Substack 编辑器手动审核并发布。公开社区评论/restack 操作则是独立的实验性功能,且需征得同意。Substack Notes 也会公开发布:create_note 和 create_note_with_link 会立即发布短篇 Notes,因为 Substack 不提供 Notes 草稿状态。请将 Note 工具视为公开发布操作——没有预览步骤,也无法通过此服务撤销。这样的区分是与风险相称的审核机制,也是此服务最重视的 Agent 信任基础设施:高风险操作设有人为审核关卡,并明确说明例外情况。
此服务不要求账号具备畅销书作者身份。请使用有权管理该出版物的已认证账号;具体操作取决于你的 Substack 访问权限。可通过本地 stdio 或可自托管的 HTTP 连接。
有关 1.0 版本的设置支持范围和账号资格,请参阅兼容性。运行 substack-mcp compatibility report 可生成离线、可分享的诊断报告;另请参阅报告指南。维护者可使用发布清单和分发清单。
目录:快速开始 · 设置 · 工具 · 操作员 CLI · 草稿工作流 · 从分析数据到草稿 · 导出 · Markdown · 多个出版物 · 传输方式 · 兼容性
快速开始
-
安装并登录。 浏览器登录需要可选的 Playwright 依赖:
npm install @conorbronsdon/substack-mcp playwright npx playwright install chromium npx substack-mcp login https://yourblog.substack.com --user-id 12345使用你自己账号的用户 ID(如何查找)。只有在成功完成一次有界的 身份验证读取后,才会保存会话。如要改为粘贴凭据,请参阅 选项 B。
-
验证读取。
npx substack-mcp doctor --json --check-auth会针对每个出版物执行一次 有界读取。它确认你有读取权限,但不会确认你的用户 ID 或写入权限。 -
连接 MCP 客户端。 将服务添加到 Claude Desktop 或 Claude Code,或使用 Codex 插件。环境变量优先级更高;省略它们即可使用已保存的浏览器登录会话。然后询问你的助手: “我有多少 Substack 订阅者?”
-
准备草稿以供审核。 按照草稿工作流操作:
create_draft、search_posts、export_draft、preflight_draft,然后 执行plan_draft_update和update_draft。长篇文章会保持为未发布草稿,直到你在 Substack 编辑器中发布。create_note和create_note_with_link会立即发布。
社区实践指南
Jonathan Price 的我用 Codex 将 ChatGPT 连接到 Substack。然后它起草了这篇文章。 介绍了如何使用 Codex 在本地安装 MCP,通过 OpenAI 的 Secure MCP Tunnel 连接 ChatGPT,以及创建私密草稿以供手动发布。 他使用该连接创建了这篇指南的草稿。
该指南记录了他在 2026 年 9 月 18 日使用 1.2.0 版本进行的配置。报告的
get_post 404 问题已在 1.2.1 版本中修复。客户端界面和访问要求可能会发生变化;有关此软件包的当前配置,请参阅下方的设置说明。
这是社区实践指南,并非本项目提供的托管服务。
设置
需要 Node.js 22 或更高版本(CI 覆盖 Node 22 和 24)。浏览器登录还需要 Playwright。
你可以通过两种方式提供凭据:将它们粘贴为环境变量(见下文),或运行可选的浏览器登录,由它为你捕获并保存凭据。
选项 A — 浏览器登录(可选,无需手动复制 Cookie)
在本地工具目录中同时安装服务和可选的 Playwright 依赖,然后登录:
npm install @conorbronsdon/substack-mcp playwright
npx playwright install chromium
npx substack-mcp login https://yourblog.substack.com --user-id 12345
substack-mcp-login 仍是受支持的别名。系统会提示输入缺失的出版物 URL 和用户 ID。请提供你自己账户的用户 ID(步骤见下文);文章作者署名不能证明你的身份。浏览器会打开供你登录,包括处理任何 CAPTCHA。
登录后,浏览器会打开 <publication>/publish/home,并等待出版物会话 Cookie;在自定义域名上,该 Cookie 是自定义域名下的 connect.sid。
保存前,必须成功完成有范围限制的身份验证读取。默认流程会验证读取权限,不会验证配置的用户 ID 或写入权限。
若要从所选出版物的已验证会话中推导用户 ID,而不是手动输入,请使用:
npx substack-mcp login https://yourblog.substack.com --verify-identity --profile work
--verify-identity 会使用该主机的 Cookie 请求出版物主机上的 /api/v1/user/profile/self,要求顶层 ID 为正的安全整数,然后在保存前执行现有的已验证身份草稿列表检查。如果同时提供 --user-id,该参数就会作为断言:若不匹配,则停止操作,不保存也不替换配置文件,即使使用 --force 也一样。不会将公开个人资料、文章作者署名、其他主机的 Cookie 或其他主机的端点作为备用来源。已验证模式的 JSON 结果会报告 user_identity: "verified" 和 identity_source: "authenticated_publication_self_profile";不会打印 ID。这只是登录时的观测结果,并非持久化的身份证明,也不能证明拥有写入权限。普通的 doctor 仍会将身份报告为未验证。
尚未在所有 Substack/自定义域名配置中实测验证出版物主机对个人资料端点的支持情况。如果端点不可用、已过期、发生重定向或格式异常,已验证模式会安全失败,不保存任何内容。仍可使用现有的手动配置 ID 流程,但该流程会明确标记为未验证。对于 #150,仍需进行真实浏览器测试;fixture 测试不能证明当前登录界面的实际情况。
如果未指定 --profile,登录会保存到 ~/.substack-mcp/session.json(目录覆盖变量:SUBSTACK_MCP_HOME)。当出版物凭据环境变量和 SUBSTACK_PROFILES 均未设置时,服务会使用此旧版会话。
默认存储(SUBSTACK_CREDENTIAL_STORE=file): 会话使用 AES-256-GCM 加密,密钥根据操作系统账户和计算机派生。文件权限请求值为 0600;在 Windows 上,访问还取决于目录 ACL。这是绑定到计算机的文件,并非操作系统钥匙串或机密保险库。以你的操作系统用户身份运行的代码可以派生该密钥。如果 MCP 客户端会替你管理机密,请改用环境凭据。
可选的操作系统钥匙串: 在登录进程和 MCP 客户端的环境中均设置 SUBSTACK_CREDENTIAL_STORE=keychain。macOS 通过 /usr/bin/security 使用 Keychain;Linux 需要 libsecret 和 secret-tool,以及已解锁的 Secret Service;Windows 通过 PowerShell 的 PasswordVault 使用 Credential Manager。这三种方式都会在 GitHub 托管的运行器上通过 keychain CI 工作流使用合成凭据进行测试(macOS 使用已解锁的临时钥匙串,Linux 使用 gnome-keyring 会话);桌面环境中锁定的钥匙串仍可能触发提示。登录会将所选账户写入钥匙串,服务则从钥匙串读取。明确选择钥匙串后,绝不会将加密文件用作回退来源。钥匙串有助于防范其他操作系统用户、复制的磁盘,以及某些仅能访问文件的恶意软件。以你的用户身份运行的代码通常可以查询钥匙串。请确保操作系统账户和运行中的代码值得信任。
在 Linux 上,对于条目不存在或密钥环已锁定这两种情况,secret-tool lookup 都可能在没有错误消息的情况下以状态码 1 退出。不使用 --force 的具名写入会先搜索并解锁;如果发现已有条目,则拒绝覆盖。
命名配置文件与迁移
npx substack-mcp login https://yourblog.substack.com --user-id 12345 --profile work
npx substack-mcp profiles list
# Copy an existing legacy session without changing its file:
npx substack-mcp profiles migrate --name personal
# Copy a file session or named file profile into the keychain; source remains:
npx substack-mcp profiles migrate --to keychain
npx substack-mcp profiles migrate --to keychain --name work
键必须以小写 ASCII 字母开头,且只能包含小写字母、数字和连字符,最多 64 个字符。替换现有配置文件需要显式指定 --force。列表输出包含键、可读性状态、发布来源和文件保存时间,不包含 Cookie 和用户 ID。不可读的配置文件仍会显示,但无法选用。保存时间记录的是本地持久化时间(包括迁移),并非令牌签发或过期时间。列表最多显示 32 个配置文件。
配置文件存储要求本地文件系统支持硬链接(例如 NTFS 或常见的 Linux 文件系统),以便创建时能够安装完整的加密文件,而不覆盖现有名称。不支持 FAT/exFAT 和某些网络挂载:请将 SUBSTACK_MCP_HOME 设为合适的本地目录。请勿使用 --force 来绕过不受支持的文件系统。
在 MCP 客户端的环境中设置 SUBSTACK_PROFILES=work,personal,即可选择最多 32 个不同的配置文件。请先移除所有发布凭据变量:同时使用配置文件选择和旧版或命名凭据变量会导致错误,即使变量值为空也不例外。所选配置文件缺失、损坏或无效时,启动会停止;绝不会回退到其他账号。发现过程中绝不会激活磁盘上的配置文件。使用多个配置文件时,工具需要显式指定发布键,CLI 读取操作需要 --publication。
如需回滚,请取消设置 SUBSTACK_PROFILES 并恢复之前的环境配置。迁移会逐字节保留旧版会话。这些文件使用现有的加密格式。profiles list 会列出文件配置文件;迁移或登录后,可通过 SUBSTACK_PROFILES 显式选择密钥链配置文件。运行 substack-mcp status --json 可进行离线配置诊断,或运行 substack-mcp doctor --check-auth --json,对每个所选账号执行有界读取。
选项 B — 手动获取凭据
在浏览器中打开 Substack,然后:
- 会话令牌: 对于自定义域名,打开开发者工具 → Application → Cookies →
https://your-custom-domain,并从发布内容自己的域名复制connect.sid(以s%3A开头的 URL 编码字符串)。请勿从 substack.com 复制substack.sid:这是另一个会话,自定义域名的管理 API 会以 403 拒绝它。对于*.substack.com发布内容,请使用该主机上的connect.sid,或.substack.com上的substack.sid。令牌必须与SUBSTACK_PUBLICATION_URL的主机匹配;只有由 Substack 托管的发布内容才可使用.substack.com作为备用。 - 用户 ID: 按照查找你的账号用户 ID中的步骤操作。请勿使用发布文章署名中的 ID:一个发布内容可能有多个作者。此服务不会独立验证所提供的 ID。
- 发布 URL: 你的 Substack URL;如果有自定义域名,请包含该域名(例如,
https://newsletter.yourdomain.com或https://yourblog.substack.com)
查找你的账号用户 ID
- 在 Substack 中,打开你自己的账号个人资料并复制其用户名(即
https://substack.com/@your-handle中@后面的部分)。发布 URL 或其他作者的个人资料都不是你的账号用户名。 - 将
your-handle替换为你的用户名,然后打开https://substack.com/api/v1/user/your-handle/public_profile。读取 JSON 响应顶层的数字id;不要使用嵌套在发布内容或文章署名下的 ID。此服务也会使用该公开个人资料端点进行匿名个人资料查询。 - 确认响应中的
handle和姓名与将用于登录的账号相符。将顶层的id提供给login --user-id或SUBSTACK_USER_ID。公开个人资料查询只能确认你输入的用户名;浏览器登录读取检查不能证明 Cookie 属于该 ID。执行任何写入操作前,请再次确认账号。
2. 配置 MCP 客户端
Claude Desktop
添加到 claude_desktop_config.json:
{
"mcpServers": {
"substack": {
"command": "npx",
"args": ["-y", "@conorbronsdon/substack-mcp"],
"env": {
"SUBSTACK_PUBLICATION_URL": "https://yourblog.substack.com",
"SUBSTACK_SESSION_TOKEN": "your-session-token",
"SUBSTACK_USER_ID": "your-user-id"
}
}
}
}
除了手动配置 MCP 外,还可使用 Claude Code 和 Codex 插件设置。仓库插件市场和本地插件与精选目录收录或托管的 ChatGPT 支持无关。
Claude Code
添加到 .mcp.json:
{
"mcpServers": {
"substack": {
"command": "npx",
"args": ["-y", "@conorbronsdon/substack-mcp"],
"env": {
"SUBSTACK_PUBLICATION_URL": "https://yourblog.substack.com",
"SUBSTACK_SESSION_TOKEN": "your-session-token",
"SUBSTACK_USER_ID": "your-user-id"
}
}
}
}
3. 验证
向 AI 助手询问:“我有多少位 Substack 订阅者?”
工具契约中记录了工具输出兼容性、响应限制和版本管理。
运维诊断
CLI 通过与服务端相同的 MCP 处理程序和凭据解析,提供运维命令和配置检查。drafts create 会创建一个私有草稿;其他运维命令会读取:
substack-mcp status --json
substack-mcp doctor --json --check-auth
substack-mcp drafts list --limit 10
运维 CLI 和诊断中记录了命令、JSON 信封、退出代码、请求截止时间和响应限制。
工具
每个工具都会声明明确的 MCP 副作用注释;请参阅工具注释。工具描述是权威措辞。
读取
| 工具 | 描述 |
|---|---|
get_subscriber_count | 获取你的刊物当前的订阅者数量 |
list_subscribers | 读取一页范围受限的私人订阅者记录 |
search_subscribers | 筛选并分页读取私人订阅者记录;可选活动、日期、标记和收入字段 |
get_subscriber | 按确切邮箱查找会员身份;核对待处理的新增记录 |
list_published_posts | 分页列出已发布的文章 |
get_publication | 读取预计的刊物身份信息/设置,验证已配置的主机,并报告缺失字段;不验证账户身份或角色 |
list_publication_tags | 读取标记定义,默认包含隐藏标记,并进行范围受限的本地分页 |
get_post_tags | 解析文章的标记关联;保留无法解析的 ID,并报告空结果中的身份不确定性。目前仅针对空响应实时验证草稿覆盖情况 |
search_posts | 按查询和状态搜索刊物档案;提供范围受限的分页及续页元数据 |
plan_draft_update | 审核拟议更改、预检和用于尽力检测过时状态的回执;不写入数据 |
export_draft | 可编辑的 Markdown、精确的原始正文、转换诊断、预检和编辑器链接 |
preflight_draft | 只读检查标题、受众、正文结构、图片和付费墙,并提供编辑器链接 |
list_drafts | 列出草稿文章 |
get_post | 按 ID 获取已发布文章的完整内容 |
get_draft | 按 ID 获取草稿的完整内容 |
get_post_comments | 获取已发布文章的评论 |
get_sections | 列出你的刊物版块(分类)及其 ID |
get_post_analytics | 按 ID 获取已发布文章的统计数据(浏览量、打开量、注册量、订阅量、互动量) |
rank_posts | 按浏览量、打开量、发送量、比率、注册量、订阅量、估算价值或日期对文章进行排名,并区分 null 值和缺失值 |
get_publication_stats | 读取仪表板摘要和指定范围内的刊物指标,并区分缺失和不可用状态 |
get_growth_sources | 读取范围受限的增长来源归因和可选事件 |
list_incoming_recommendations | 列出推荐你的刊物,包括开始日期、活跃状态和由仪表板归因的订阅者 |
list_outgoing_recommendations | 列出你的刊物推荐的对象(可能不完整)。这并非推荐你的对象;如需查询,请使用 list_incoming_recommendations |
list_outgoing_recommendation_stats | 列出你的刊物为其推荐的刊物带来的订阅者 |
list_scheduled_posts | 列出计划未来发布的文章(只读;排期仍需在 Substack 的编辑器中进行) |
get_user_profile | 匿名读取按用户名查找的最简公开用户资料 |
get_profile_feed | 匿名读取一页公开用户动态,支持游标续页 |
get_note_thread | 匿名读取公开 Note、其上级内容以及一页回复 |
list_public_posts | 匿名读取一页范围受限的公开档案 |
get_public_post | 按 URL 匿名读取公开文章,并附带正文状态和截断标记 |
公开读取
这五个工具使用独立的匿名读取器。它只发送 User-Agent 和
Accept,绝不会发送已配置的 publication cookie 或其他凭据。已配置的
publication 用于选择默认归档源;调用方可以提供列入许可名单的 HTTPS
publication 源。允许的主机包括 substack.com、单标签
*.substack.com、已配置的 publication 源,以及
SUBSTACK_PUBLIC_READ_ORIGINS 中列出的精确源(以逗号分隔的 HTTPS 源,不含端口、
路径或用户信息)。重定向会被拒绝。*.substack.com publication 可能会
重定向到其自定义域名(例如 lenny.substack.com);JSON 读取不会跟随该重定向。
请将自定义 HTTPS 源添加到
SUBSTACK_PUBLIC_READ_ORIGINS,并通过该源读取。配置了多个
publication 时,每个 publication 工具都必须提供 publication 键。
个人资料动态页面的大小由上游决定;has_more: null 表示上游未提供
续页元数据。若存在 more_branches 或 next_cursor,话题串页面可能会省略回复;
completeness: "unknown" 表示上游未提供续页元数据。
完整归档页面的 has_more: null 是因为未返回总数。公开文章的
body_status 是基于受众和正文是否存在的启发式判断;它不能证明具有完整访问权限。
匿名读取器不会使用订阅权益。暂不支持读取器订阅和收件箱:已配置的
publication 会话访问 substack.com 读取器账户路由时收到 401;这些路由
需要单独的读取器会话,而此服务不会管理该会话。
归档搜索和草稿审查
search_posts 接受 query(1–500 个字符)、status(published、drafts
或 scheduled,默认为 published)、offset(默认为 0)和 limit(1–50,
默认为 25)。它会发起一次经过身份验证的归档请求,并返回投影后的元数据、
returned、total、has_more 和 next_offset。请使用
next_offset 和相同的 query/status 继续获取结果。当 Substack 未提供总数且页面已满时,
has_more 为 null(未知);下一页可能为空。匹配和索引由 Substack 控制:
这并不保证会完整扫描全文。请使用 get_post 或 get_draft 获取完整内容。
分页不是快照;并发编辑可能会导致结果在不同页面间移动。
preflight_draft 接受 draft_id,读取一次草稿,并返回 checks_passed、
包含严重性、代码和消息的发现项、内容计数以及编辑器链接。它会检查标题、
受众、JSON/正文结构、图片包装器和 HTTPS 来源,以及付费墙数量和边界位置。
未知节点和外部图片会生成审查警告。超过两百万个字符、10,000 个节点或深度 100 的正文
不会被完整检查;counts.complete 为 false,达到扫描限制后会跳过聚合检查。
未知节点警告最多列出五种类型,供编辑器审查。这是有针对性的静态检查,
并非完整的 ProseMirror 验证或发布批准。它不会获取链接/图片、验证访问设置,
也不能证明最终渲染效果。请在 Substack 中审查草稿;不会修改任何内容。
配置了多个 publication 时,这两个工具都必须提供 publication。
写入(私有草稿;图片上传会返回公开 URL)
| 工具 | 说明 |
|---|---|
create_draft | 根据 markdown 创建新草稿(私有) |
update_draft | 应用经过审查的变更回执;重新检查未发布状态并报告回读结果 |
update_draft_tags | 规划或更改草稿标签;默认试运行,仅限草稿,写入后回读一次 |
upload_image | 从文件、数据 URI 或公开 HTTPS URL将图片上传到 Substack 的 CDN——返回可公开获取(未列出)的 URL |
更改草稿前先审阅
在 0.9 中,先调用 plan_draft_update 并审阅其输出,再使用相同的字段和返回的回执调用 update_draft。已发布的草稿或已知过时的草稿会被拒绝。读写竞态仍然存在;请检查读取回显结果,并在 Substack 中审阅。CLI 通过 drafts plan 和 drafts apply 使用相同的流程。示例和限制请参阅草稿更改和迁移。
公开社区写入(实验性)
| 工具 | 说明 |
|---|---|
create_post_comment | 在已配置的出版物中发表评论;默认预览,启用实时模式时会立即发布 |
restack | 以独立读者账号重置一篇文章或 Note;默认预览,启用实时模式时会立即发布 |
实时尝试需要设置 SUBSTACK_EXPERIMENTAL_COMMUNITY_WRITES=1、
dry_run=false、confirm_publish=true,并明确批准具体账号、目标和文本。
Restack 操作还需要单独的读者会话。两个工具都会在写入前检查已认证身份,尝试发送一次 POST,并报告范围受限的读取回显结果,不会自动重试。端点有来源证据;实时验证仍待完成。请参阅设置、凭据路由、同意和限制。
发布(Notes——立即公开)
| 工具 | 说明 |
|---|---|
create_note | 发布 Substack Note(短篇内容,立即发布) |
create_note_with_link | 发布附带链接卡片的 Note(立即发布) |
Substack 上的 Notes 没有草稿状态,因此这两个工具都不提供先创建草稿的选项。
订阅者管理
add_free_subscriber 会将一位已同意的读者添加到免费新闻通讯中。这会更改分发设置:该读者可能会收到之后发送的新闻通讯邮件。可以通过 send_welcome_email: true 请求发送欢迎邮件(默认关闭)。此操作不会授予付费访问权限,也不会绕过 Substack 对之前已退订地址的屏蔽。其 MCP 注解将该操作标记为外部写入(readOnlyHint: false、openWorldHint: true)。
{"email":"[email protected]","consent_confirmed":true,"consent_evidence":{"source":"booking:message-id","recorded_at":"2026-09-01T00:00:00Z"},"dry_run":true}
默认采用试运行模式。在确认实际的新闻通讯订阅同意后,将 dry_run: false 设为执行模式。实时添加需要在 consent_evidence 中提供来源引用和时间戳;此证明会与出版物密钥一并回显以供审计,但不能替代对底层同意记录的检查。多出版物配置还必须指定 publication 选择器,与其他所有工具相同。
结果分为 existing、dry_run、verified、blocked 和
unverified、busy、retryable。busy 表示未执行写入;请等待其他操作完成。retryable 表示请求因身份验证或速率限制而被拒绝;请先解决该问题,再明确重试。空的 API 确认不能证明订阅者已添加。
verified 表示请求后精确的成员资格查询成功;但这不能证明本次请求最初创建了该成员资格。仪表板数据可能会延迟更新。缺失的读者也可能之前已退订。
对于 unverified,请使用 get_subscriber 重新检查;切勿自动重复添加。对于 blocked,请在 Substack 中审查,不要绕过屏蔽。自动化调用方必须在发送每个实时请求前持久化尝试记录。客户端的内存重复操作防护在重启或单独的 HTTP 会话之间不会保留。不要将订阅者身份和同意证据存入共享代码库、提交给未经批准的公共服务的提示词或常规日志。
实现和实时验证说明:订阅者 API。
对于 Google Calendar 预约选择加入流程,日历同步助手提供有范围限制的 Gmail 扫描、最新回答选择、私有持久化尝试记录,以及在写入结果不确定时进行只读核对。计划安排是明确的本地设置步骤;安装 MCP 不会启动后台任务。
有意排除的功能
- 发布文章 — 发布长篇文章应由人类审慎决定(上文提到的 Notes 是已记录的例外)
- 删除 — 对 AI 工具来说破坏性太大
- 安排发布时间 — 使用 Substack 编辑器安排发布时间。
list_scheduled_posts会读取 你在编辑器中排队的内容,但此服务绝不会创建、编辑或取消任何安排。
如需使用具备持久云端状态和每周邮件报告的常驻调度器,请参阅 Cloud Calendar sync。
多个出版物
要在单个服务后运行多个出版物?为每个出版物设置一组三个 SUBSTACK_PUB_<KEY>_* 变量,而不是普通的 SUBSTACK_* 变量。<KEY> 可以是你选择的任意名称(字母、数字、下划线),它会转换为小写并以连字符分隔的出版物键,例如 KEVIN_MULDOON → kevin-muldoon。
"env": {
"SUBSTACK_PUB_KEVIN_MULDOON_PUBLICATION_URL": "https://kevinmuldoon.substack.com",
"SUBSTACK_PUB_KEVIN_MULDOON_SESSION_TOKEN": "token-1",
"SUBSTACK_PUB_KEVIN_MULDOON_USER_ID": "111",
"SUBSTACK_PUB_SAPERE_PUBLICATION_URL": "https://sapere.substack.com",
"SUBSTACK_PUB_SAPERE_SESSION_TOKEN": "token-2",
"SUBSTACK_PUB_SAPERE_USER_ID": "222"
}
每组三个变量相互独立,设置任意一个 SUBSTACK_PUB_<KEY>_* 变量都会声明该出版物。变量组不完整——缺少变量、值为空,或只包含空白字符——都会导致启动失败,并显示包含该键的错误,而不会静默忽略该出版物。这一点很重要,因为被忽略的出版物并不只是“少了一个出版物”:如果忽略的是唯一的出版物,服务就会回退到已存储的浏览器登录会话;如果忽略的是两个出版物中的一个,所有工具都会失去 publication 参数,因此原本要调用被忽略出版物的请求会静默转到剩下的那个出版物。
键的比较不区分大小写,且 _ 会转换为 -。两个会解析为同一键的名称(SUBSTACK_PUB_ALPHA_* 和 SUBSTACK_PUB_Alpha_*)也会导致启动错误——静默合并它们会使一个出版物的 URL 与另一个出版物的会话令牌配对。
<KEY> 只能包含 ASCII 字母、数字和下划线;三个后缀必须为大写,且整个变量名不得包含多余的空白字符。任何以 SUBSTACK_PUB_ 开头但不符合此格式的变量名——键中包含连字符、后缀为小写、包含带重音符号的字符、末尾有空格——都会导致启动错误,并指出变量名,而不会被悄悄忽略。原因与上文相同:被忽略的出版物并不只是少了一个出版物,而是会静默转到另一个出版物。
配置了两个或更多出版物时,每个出版物工具都会增加一个必填的 publication 参数,值必须是你配置的键之一(例如上文的 kevin-muldoon、sapere)。调用模型必须在每次出版物调用中指定其中一个;未识别的值会在进行任何 Substack API 调用之前被拒绝,因此误操作不会将内容写入错误的出版物。如果只配置了一个出版物——无论是常见的普通 SUBSTACK_* 变量配置,还是仅配置一组三个 SUBSTACK_PUB_<KEY>_* 变量——都不会添加 publication 参数;所有工具的架构都与单出版物模式一致。
不要混用这两种方式:只要设置了任意 SUBSTACK_PUB_<KEY>_* 变量,普通的 SUBSTACK_* 变量就会被忽略(并显示启动警告),而不会被当作一个未命名的额外出版物。
账户级的 restack 工具使用显式指定的读者 account_user_id,而不是 publication 参数。其读者凭据单独配置;它绝不会使用出版物会话。
SUBSTACK_USER_AGENT 和 SUBSTACK_REQUEST_TIMEOUT_MS 适用于每个已配置的出版物,并非针对单个出版物。浏览器登录也支持显式命名的配置文件;请参阅 命名配置文件与迁移。
令牌过期
Substack 会话令牌会定期过期(通常约 90 天)。如果遇到身份验证错误,请重新运行 substack-mcp login 以刷新已存储的会话,或从匹配的发布站点主机的 DevTools 中复制新的 Cookie,并更新环境变量。自定义域名需要使用自己的 connect.sid,而不是 substack.com 的另一个会话 substack.sid(自定义域名会以 403 拒绝该会话)。对于 *.substack.com 发布站点,请在该主机上使用 connect.sid,或在 .substack.com 上使用 substack.sid。然后运行 substack-mcp doctor --check-auth 验证访问权限。
自定义域名与 Cloudflare
本节介绍经过身份验证的创作者 API 调用。匿名公开阅读 使用上文公开阅读中的源站规则。
通过自定义域名(例如 blog.example.com)提供服务的 Substack 发布站点位于 Cloudflare 后方,Cloudflare 可能会以 403 error code: 1010 拒绝非浏览器请求。为避免此问题,服务默认发送浏览器 User-Agent 和 Referer,并使用已配置的发布站点 URL。
- 匹配主机和 Cookie。 如果使用规范的
*.substack.comURL,请使用该主机的会话或.substack.com备用会话。自定义域名的connect.sid应与该自定义域名的SUBSTACK_PUBLICATION_URL配套使用。 - 覆盖 User-Agent(可选):如果需要不同的浏览器标识,可通过
SUBSTACK_USER_AGENT设置:
"env": {
"SUBSTACK_PUBLICATION_URL": "https://yourblog.substack.com",
"SUBSTACK_SESSION_TOKEN": "your-session-token",
"SUBSTACK_USER_ID": "your-user-id",
"SUBSTACK_USER_AGENT": "Mozilla/5.0 ..."
}
请求超时
每个发往 Substack 的请求都设有 30 秒的截止时间。Node 不会自行设置请求超时——只有 10 秒的连接超时——因此,如果主机接受连接后便不再响应(例如代理丢弃数据包而不是拒绝连接),工具调用就可能无限期挂起。达到截止时间的请求会失败,并返回一个指明端点和时限的 TimeoutError。
可通过 SUBSTACK_REQUEST_TIMEOUT_MS 调高或调低超时时间(单位为毫秒;如果值不是数字或不大于 0,则会发出警告并使用默认值):
"env": {
"SUBSTACK_REQUEST_TIMEOUT_MS": "60000"
}
传输方式
默认情况下,服务通过 stdio 使用 MCP 通信,上述客户端配置也以此为前提。对于持久运行的可自托管部署,可设置 MCP_TRANSPORT=http,启用无状态 Streamable HTTP 服务(POST /mcp、GET /health)。设置方法、监听器变量和安全模型请参阅 HTTP 传输。
此监听器接受的请求
HTTP 监听器启动时处于关闭状态:默认仅允许回环 Host 和 Origin,可选设置 bearer 令牌(MCP_HTTP_TOKEN),请求正文上限为 10 MiB。Host 和 Origin 检查不属于身份验证;只要其他进程能够访问该端口,就应设置令牌。请参阅监听器策略。
带版本的 GHCR 镜像和传输验证:容器分发。
类型化错误
API 失败会映射为类型化错误(AuthenticationError、RateLimitError、
ValidationError、NotFoundError、ServerError、TimeoutError 和基类
SubstackAPIError)。状态映射和错误正文解析的说明请参阅类型化错误。
草稿导出
使用 export_draft 导出只读 Markdown/JSON 文件包,或运行:
substack-mcp export 42 --output draft-export.json
substack-mcp export 42 --format markdown --output draft.md
Markdown 导出会在 .source.json 旁置文件中保留完全一致的原始正文。重新使用前请检查 unsupported_nodes。已存在的文件需要使用 --force。有关发布站点选择、限制、部分导出和文件恢复,请参阅导出与 CLI 行为。
Markdown 支持
草稿支持 CommonMark/GFM Markdown:标题、嵌套的粗体/斜体/删除线、 链接和引用链接、带标题和链接目标的图片、带起始编号的嵌套 列表、代码、引用块、分隔线和硬换行。独立的 `` 块会为长篇草稿添加一个付费墙。
不支持的内容会在写入前返回 unsupported_nodes。查看这些诊断信息后,
草稿调用方可以明确设置 allow_unsupported: true,以保留字面形式的回退内容。表格仍以 Markdown 形式保留在代码块中;原生
表格、标注和任意嵌入内容均不属于支持范围。长篇草稿中,顶层段落里的脚注会映射为编辑器的原生脚注。
笔记在发布或创建附件之前都会拒绝不支持的转换,且没有回退选项。
有关映射、限制、兼容性变更,以及离线测试样例与实时编辑器检查之间的区别,请参阅 Markdown 编写指南。
重要说明
- 此服务使用 Substack 的非官方 API。如果 Substack 更改其端点,服务可能会失效。
- 会话令牌以 Cookie 形式发送。请妥善保管你的
SUBSTACK_SESSION_TOKEN。 - 服务会在启动时检查你的凭据,且检查发生在 MCP 握手完成之后;它只会发出警告,不会因网络调用而阻止启动。如果令牌已过期,各工具仍会分别报错,便于针对实际故障采取措施。
- 服务会处理
SIGTERM和SIGINT:关闭传输并以状态码 0 退出,因此docker stop会及时返回,而不是一直等待宽限期结束。
开发
如需选择性地执行实时读取检查,请参阅实时契约验证材料。 该探测在常规 CI 中处于禁用状态,且绝不会发布或写入内容。
发布前,请运行 npm run test:package。它会在干净的临时目录中安装包含生产依赖的构建归档包,检查两个可执行入口,并在不使用真实凭据的情况下验证 MCP 版本和完整的已注册工具目录。
git clone https://github.com/conorbronsdon/substack-mcp.git
cd substack-mcp
npm install
npm run build
在本地运行:
SUBSTACK_PUBLICATION_URL=https://yourblog.substack.com \
SUBSTACK_SESSION_TOKEN=your-token \
SUBSTACK_USER_ID=your-id \
npm start
参与贡献
欢迎提交问题和拉取请求。由于此服务使用 Substack 的非官方 API,最有帮助的贡献是在端点变更后修复问题。如果某个工具停止工作,请提交问题,并注明工具名称和错误信息。安全优先的边界始终不变:不发布、不删除、不安排长篇帖子发布。笔记会按设计立即发布,其描述中必须继续醒目地说明这一点。
关于
由 Conor Bronsdon 为 Chain of Thought 播客制作工作流构建并维护;该工作流用于起草和审阅简报帖子,再由人工点击发布。Conor 主持 Chain of Thought,这是一档探讨 AI 基础设施以及从业者如何实际构建相关技术的节目。创作者可使用的更多工具见 ai-tools-for-creators。可在 X 上通过 @ConorBronsdon 联系 Conor。
配套工具:
- Transistor MCP:Transistor.fm 的官方 MCP 服务。提供节目、发布和分析功能。
- podcastindex-mcp:搜索 Podcast Index 并跟踪嘉宾出演记录
- op3-mcp:报告 OP3 的下载量、听众地域分布和应用信息
- apple-podcasts-mcp:从 Apple Podcasts Connect 获取播放量、关注者数量和单集收听数据
- gsc-mcp:在 Google Search Console 中查询搜索表现、关键词和站点地图
- podcast-benchmark:仅使用公开数据,将节目与同类节目进行对比
免责声明
这是一个独立的个人项目,与任何公司均无关联,也未获得任何公司的赞助或认可。文中表达的所有观点均为我个人观点。
Codex 插件
此代码库包含位于 .codex-plugin/plugin.json 的 Codex 清单,以及位于
.mcp.json 的 MCP 配置。它使用 npx 通过标准输入/输出运行已发布的 npm 软件包;
必须安装 Node.js 和 npm。.mcp.json 中固定了软件包版本,因此升级插件的服务
需要显式修改配置。
请按照上文所述,使用环境变量或浏览器登录会话,在插件之外配置你的 Substack 凭据。 切勿提交会话令牌。安装不会验证账户身份,也不会授予发帖权限。 长篇文章仍会保存为草稿;Notes 会立即发布。
许可证
MIT
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。