FastMCP server for Substack — publish Notes and posts, pull analytics, manage dr

io.github.adelaidasofia由 GitHub 账号 adelaidasofia 发布v0.1.0更新于 Oct 25, 2026

FastMCP server for Substack — publish Notes and posts, pull analytics, manage drafts, pluggable…

发布方自己的服务:posts.design

概览

AI 生成的概览

一个本地 MCP 服务器,让助手使用浏览器会话 Cookie 发布 Substack Notes 和文章、管理草稿并获取出版物分析数据。

可以做什么
发布、回复和列出 Notes,支持附件,并可批量发布 vault 草稿;对文章点赞、restack 和评论,并读取订阅源和出版物列表;创建、编辑、定时和发布文章草稿,列出分区、草稿和已发布文章,并上传图片;读取仪表盘 KPI、单篇统计、订阅者增长与来源、热门文章、收入和推荐等分析数据,并可快照到 vault 文件;将 Obsidian 风格的 vault 草稿文件桥接到 Substack,并通过本地 Pillow 或 Canva 流程生成视觉卡片
适用场景
适合希望让助手起草、定时和发布文章与 Notes、回复订阅源内容,并查看订阅者和收入分析而无需切换到 Substack 后台的 Substack 作者。
运行要求
以本地 Python 进程运行(从仓库 pip 安装或使用打包插件)。需要 config.json,包含出版物子域名、默认出版物、可选的 vault 草稿路径和图片生成器设置。认证使用 SUBSTACK_SID_COOKIE 会话 Cookie,过期后需从浏览器开发者工具重新提取。Canva 图片生成需要连接 Canva MCP 并填写设计 ID。
安装前请注意
发布、回复、评论、restack、点赞、定时和上传都会改动你的真实 Substack 账户,并可能触达订阅者,使用 send_email 时还会发送邮件。会话 Cookie 拥有完整账户权限,请妥善保管 config.json,并在过期后重新提取。除非设置 MYCELIUM_NO_PING,插件会向 myceliumai.co 发送一次匿名安装信号。

安装

在 SourceWeft 中

  1. 打开 控制台中的 FastMCP server for Substack — publish Notes and posts, pull analytics, manage dr,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

substack-mcp

[License] [GitHub stars] [Last commit] [Open issues] [PyPI version] [PyPI downloads] [Built by Mycelium AI]

FastMCP server for Substack: publish Notes and posts, pull analytics, manage drafts, bridge Obsidian vault drafts to Substack, and generate visual cards with pluggable image generators.

Quick reference

substack__test_connection             -- verify auth (start here)substack__publish_note text=...       -- publish a Note immediatelysubstack__list_vault_drafts           -- show drafts from your vault filesubstack__publish_vault_draft index=N -- publish one vault draft as a Notesubstack__create_draft title=... body=... -- create a post draftsubstack__get_dashboard days=30       -- subscriber + view KPIssubstack__capture_analytics_to_vault  -- snapshot analytics to vault markdown

Tool inventory (30)

Notes + vault pipeline

  • test_connection(publication?) -- verify auth, return your profile
  • list_publications() -- show configured publications and which is default
  • publish_note(text, publication?, attachment_ids?) -- publish a Note immediately; markdown supported
  • create_note_attachment(image_path?, image_url?, link_url?, publication?) -- upload image or register link; returns attachment UUID for use with publish_note
  • list_my_notes(limit?, publication?) -- your recent Notes with reaction + comment counts
  • reply_to_note(note_id, text, publication?) -- reply to a Note by ID
  • list_vault_drafts() -- parse vault drafts file, return index + preview for each draft
  • publish_vault_draft(index, publication?, move_to_published?) -- publish one vault draft as a Note
  • batch_publish_vault_drafts(indices, publication?) -- publish multiple vault drafts in sequence

Post management

  • create_draft(title, body, subtitle?, audience?, publication?, section_id?) -- create a post draft; body is markdown
  • update_draft(draft_id, title?, body?, subtitle?, audience?, publication?, section_id?) -- edit an existing draft
  • publish_post(draft_id, send_email?, audience?, publication?, section_id?) -- publish a draft live to subscribers
  • schedule_post(draft_id, publish_at, publication?, section_id?) -- schedule a draft for future publication (ISO 8601)
  • list_sections(publication?) -- list configured sections for a publication; required to publish on publications with sections
  • list_drafts(limit?, publication?) -- list unpublished drafts
  • list_published(limit?, publication?) -- list published posts with basic stats
  • get_post(identifier, publication?) -- get full post by slug or numeric ID
  • upload_image(image_path, publication?) -- upload an image to Substack CDN; returns CDN URL
  • react(post_id, publication?) -- heart a post
  • restack(post_id, publication?) -- restack a post
  • comment(post_id, body, publication?) -- comment on a post
  • get_feed(limit?, publication?) -- your reader feed (posts from publications you follow)

Analytics

  • get_dashboard(days?, publication?) -- KPIs: total/paid subscribers, views, growth, ARR
  • get_post_stats(post_id, publication?) -- views, opens, clicks, shares, conversions for one post
  • get_subscriber_growth(publication?) -- subscriber count over time
  • get_growth_sources(publication?) -- subscriber growth by source (search, recommendations, direct, social)
  • get_top_posts(limit?, publication?) -- posts ranked by engagement
  • get_earnings(publication?) -- revenue data for paid publications
  • get_recommendation_stats(direction?, publication?) -- recommendation network performance
  • capture_analytics_to_vault(publication?) -- write a weekly analytics snapshot to your vault

Install

Open Claude Code, paste:

/plugin marketplace add adelaidasofia/substack-mcp/plugin install substack-mcp@substack-mcp
Legacy install
bash
git clone https://github.com/adelaidasofia/substack-mcpcd substack-mcppip3 install -r requirements.txtpython3 -c "import server; print('OK')"

Configuration

Copy config.example.json to config.json and fill in your values:

bash
cp config.example.json config.json

config.json is gitignored. Key fields:

FieldDescription
publications[].nameInternal name used in tool calls
publications[].subdomainYour Substack subdomain (e.g. yourname)
publications[].cookieSession cookie (see below)
default_publicationWhich publication to use when publication arg is omitted
vault_drafts_pathPath to your vault drafts markdown file
image_generator.defaultActive image adapter: pillow_local or canva

Session cookie setup

Substack does not have a public API with OAuth. Auth uses your browser session cookie.

  1. Open Chrome and log in to Substack.
  2. Open DevTools (F12) and go to the Application tab.
  3. Under Cookies, find substack.com.
  4. Copy the value of substack.sid.
  5. Paste it into config.json under the matching publication's cookie field.

The raw value works; the server accepts both abc123 and substack.sid=abc123.

Session cookies expire. If tools return {"error": "Auth failed"}, re-extract the cookie.

Register in Claude Code

Add to your .mcp.json (project-scoped) or via claude mcp add -s user:

json
{  "mcpServers": {    "substack": {      "command": "python3",      "args": ["/path/to/substack-mcp/server.py"]    }  }}

Restart Claude Code after editing .mcp.json. Verify with claude mcp list.

Vault integration

Set vault_drafts_path in config.json to a markdown file in your Obsidian vault. Format each draft as a section separated by ---. Sections under ## Ready to Post are surfaced first by list_vault_drafts. Sections under ## Essay Seeds come next.

After publishing, publish_vault_draft moves the draft to a ## Published section and appends the Substack URL and timestamp.

Pluggable image generators

Visual card generation is handled by the adapter set in config.json under image_generator.default.

Shipped adapters

pillow_local (default) -- pure Pillow, no external API. Renders 1080x1080 PNG cards locally using fonts from the fonts/ directory. Three pillar templates: warm mustard with optional figure (P1), deep burgundy bold quote (P2), mustard with section tag (P3). Use with render_card.py as a standalone CLI.

canva -- Canva MCP choreography. Returns a steps list describing the Canva MCP tool calls needed to clone a template, replace text, replace the figure, and export PNG. The Claude session executing the playbook follows these steps. Requires Canva MCP connected in Claude Code and design IDs filled in under image_generator.canva.pillars.

Stubbed adapters (contributions welcome)

nano_banana -- Gemini 3 Pro Image via the nano-banana skill. Stub in image_generators/nano_banana.py. Implement generate() by calling the skill's image endpoint with a prompt built from the card spec.

midjourney -- Midjourney API (or proxy). Stub in image_generators/midjourney.py. Implement generate() by submitting a prompt, polling for completion, and downloading the result.

dalle -- OpenAI DALL-E. Stub in image_generators/dalle.py. Implement generate() using openai.images.generate.

Writing your own adapter

Subclass ImageGenerator from image_generators.base:

python
from image_generators.base import ImageGenerator
class MyAdapter(ImageGenerator):    @property    def name(self) -> str:        return "my_adapter"
    def generate(self, spec: dict) -> dict:        # spec keys: pillar, quote, handle, figure_path, output_path        # return: {status: "ok", adapter: ..., image_path: ..., width: ..., height: ...}        ...

Register it in image_generators/__init__.py and add a config block under image_generator.my_adapter in config.json.

Visual publishing pipeline

The visual_helper.py script handles the deterministic side of the visual queue pipeline: parsing a Review Queue markdown file, rotating through figures, and marking entries published. See visual_playbook.md for the full end-to-end flow including image generation, upload, and publishing steps.

bash
python3 visual_helper.py peek --lang es        # get next approved visual itempython3 visual_helper.py mark --lang es ...    # mark published + update logpython3 visual_helper.py rotate-figure --pillar P1

Known gotchas

  1. Cookie expiry. substack.sid cookies expire after a few weeks. Re-extract from Chrome DevTools when test_connection returns auth errors.

  2. draft_bylines is required but undocumented. create_draft will 400 without it. The server fetches your user_id from /user/profile/self automatically and injects it into every draft POST.

  3. Note attachment endpoint requires trailing slash. POST /comment/attachment/ (with slash) works. Without slash it returns 404. The server handles this correctly.

  4. Publication-scoped vs global endpoints. Notes use substack.com/api/v1/comment/feed/. Post drafts use {subdomain}.substack.com/api/v1/drafts. Mixing them returns 404 or 403.

  5. pledgedArr in the dashboard is a projection, not real pledges. Use get_earnings for actual revenue data.

  6. Multi-publication support. Pass publication="name" to any tool to target a specific publication. Omit it to use default_publication from config.

  7. Sections are required to publish on publications that have them. Substack returns HTTP 400: Please choose a section from publish_post / schedule_post when the draft hasn't been filed under a section. Look up section IDs with list_sections(publication="main"), then pass section_id=<id> to either the draft tool or the publish/schedule tool:

    list_sections                             # → [{id: 12345, name: "Essays", slug: "essays", ...}, ...]create_draft title=... body=... section_id=12345# or, for an existing draft:publish_post draft_id=987654 section_id=12345

    publish_post / schedule_post patch the draft before publishing, so a single call is enough.

Related MCPs

Same author, same architecture pattern (FastMCP, draft+confirm on writes where applicable, vault auto-export, MIT):

Telemetry

This plugin sends a single anonymous install signal to myceliumai.co the first time it loads in a Claude Code session on a given machine.

What is sent:

  • Plugin name (e.g. slack-mcp)
  • Plugin version (e.g. 0.1.0)

What is NOT sent:

  • No user identifiers, names, emails, tokens, or API keys
  • No file paths, message content, or anything from your work
  • No IP address is stored after dedup processing

Why: Helps the maintainer know which plugins people actually install, so attention goes to the ones that get used.

Opt out: Set the environment variable MYCELIUM_NO_PING=1 before launching Claude Code. The hook will skip the network call entirely. Already-pinged installs leave a sentinel at ~/.mycelium/onboarded-<plugin> — delete it if you want to reset state.

License

MIT


Built by Mycelium AI. Full install or team version at diazroa.com.

来源:README.md,提交 1d5c90f

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

1
  1. v0.1.0最新Sep 16, 2026

评分

已满足适用检查项的 50%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分

其他 Posts 集成