substack-mcp
Creates, inspects, updates, schedules, and publishes Substack posts from Markdown. Supports uploading local images, setting audience, comment permissions, SEO metadata, slug, sections and tags, listing publications and drafts, exporting drafts to loss-aware Markdown backups, and safely updating drafts while preserving unsupported editor widgets, with explicit confirmation safeguards for publishing and deletion.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@substack-mcpcreate an unpublished Substack draft from post.md with tags python and automation"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Python Substack
Write Substack posts in Markdown and safely create, inspect, schedule, and publish them through Python, a command-line interface, or MCP.
Documentation · Getting started · PyPI
Creating and publishing are separate operations.substack drafts create
always creates an unpublished draft. It never schedules, sends, publishes,
or deletes content.
From Markdown to a Substack draft
Install the package:
pip install python-substackCheck the selected account and publication:
substack statusCreate a safe unpublished draft, then publish only when it is ready:
substack drafts create post.md
substack drafts publish 12345 --no-sendPublishing and deletion require confirmation. Noninteractive and JSON
workflows must pass --yes explicitly.
Markdown source:

Substack result:

Related MCP server: substack-mcp-plus
What it supports
Create rich Substack drafts from Markdown.
Upload local images referenced by Markdown.
Set audience, comment permissions, SEO metadata, slug, sections, and tags.
List and inspect publications and drafts.
Export drafts to loss-aware Markdown backups without server writes.
Safely update drafts from Markdown, preserving unsupported editor widgets by default.
Schedule, unschedule, publish, and delete drafts with explicit safeguards.
Use stable JSON envelopes in scripts and automation.
Authenticate with browser cookies or email and password.
Use the same publishing workflow from Python or an optional MCP server.
Setup
Copy .env.example to .env and configure one authentication method:
EMAIL=
PASSWORD=
PUBLICATION_URL=
COOKIES_PATH=
COOKIES_STRING=Cookie authentication is usually more reliable when Substack requires captcha or magic-link sign-in. See Authentication for cookie export instructions and account-selection details.
Verify the installation without authenticating:
substack --version
substack --helpCLI
Create a draft with metadata:
substack --json drafts create post.md \
--title "My Post" \
--subtitle "Optional subtitle" \
--tag python \
--tag substack \
--slug my-post \
--search-engine-title "SEO title" \
--search-engine-description "SEO description"Inspect publications and drafts:
substack publications list
substack drafts list --limit 10
substack drafts get 12345
substack drafts export 12345 --output backup.md
substack drafts update 12345 revised-post.md --dry-run --yes
substack --publication-url https://example.substack.com drafts listManage scheduling:
substack drafts schedule 12345 --at 2026-08-01T09:00:00+03:00
substack drafts unschedule 12345Publish or delete intentionally:
substack drafts publish 12345 --no-send
substack drafts delete 12345 --yesGlobal options such as --json, --cookies, and --publication-url must
appear before the command:
substack --json drafts list
substack --cookies cookies.json --json statusThe original standalone commands remain supported. See Legacy CLI commands.
Python
import os
from dotenv import load_dotenv
from substack import Api
load_dotenv()
api = Api(
email=os.getenv("EMAIL"),
password=os.getenv("PASSWORD"),
publication_url=os.getenv("PUBLICATION_URL"),
)
result = api.create_draft_from_markdown(
title="Shipping with Python",
subtitle="A short note from a script",
markdown="""
# Hello
This draft was created from **Markdown**.

""",
tags=["python", "automation"],
slug="shipping-with-python",
)
print(result["draft"]["id"])create_draft_from_markdown creates a draft by default. It publishes only when
publish=True is passed.
Back up an existing draft without modifying it:
backup = api.export_draft_to_markdown(12345)
print(backup["markdown"])
print(backup["unsupported_nodes"])Review a Markdown update before writing it, then update deliberately:
result = api.update_draft_from_markdown(12345, "# Revised draft", dry_run=True)
result = api.update_draft_from_markdown(12345, "# Revised draft")Unsupported editor widgets exported as python-substack-node:v1 markers are
preserved by default. An update refuses to remove or alter them unless
allow_unsupported_change=True is explicitly passed.
For direct ProseMirror node construction, see the low-level Python API. YAML workflows are documented in YAML drafts.
Markdown
Supported Markdown includes headings, paragraphs, bold, italic, inline code, strikethrough, superscript, subscript, links, images, linked images, image captions, code blocks, blockquotes, ordered and unordered lists, horizontal rules, footnotes, LaTeX math, pull quotes, and callouts.
from substack.post import Post
post = Post("Title", "Subtitle", user_id=1)
post.from_markdown(
"""
# Heading
Paragraph with **bold**, *italic*, `code`, and [links](https://example.com).
"""
)Pass api= to upload local images while rendering:
post.from_markdown(markdown_content, api=api)See the complete Markdown reference.
MCP
Install and run the optional MCP server:
pip install "python-substack[mcp]"
substack-mcpThe MCP tools use the same environment variables and SDK behavior as the CLI. See MCP server for the tool list and safety notes.
Project documentation
Compatibility
The project preserves existing Python APIs, console commands, CLI behavior, environment variables, JSON keys, and MCP tool signatures through the 1.x series. Additive capabilities may be introduced. See the compatibility policy.
Disclaimer
This project is not affiliated with Substack. It uses undocumented Substack interfaces that may change without notice.
This server cannot be deployed
Maintenance
Related MCP Connectors
Read Buttondown subscribers, emails, analytics and automations; add subscribers; write email drafts.
Create, schedule, and publish social posts, manage accounts, and read analytics as MCP tools.
DEV.to MCP — wraps the DEV Community API (free, no auth for public reads)
Read and write Mission Control state via MCP — projects, tasks, subtasks, templates, status updates.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables programmatic management of Substack content, including creating drafts, publishing posts, and uploading images. It supports specialized features like live blogging and posting to Substack Notes through MCP-compatible AI tools.MIT
- AlicenseNot gradedqualityDmaintenanceCreate, manage, and publish Substack posts with full rich text formatting directly from Claude Desktop or any MCP-compatible client.52 npm25MIT
- FlicenseNot gradedqualityDmaintenanceAn MCP server for publishing markdown articles to Medium and Substack via unofficial APIs, with tools to list, create, and manage posts and drafts.-
- AlicenseNot gradedqualityDmaintenancePrivate MCP server for validating, previewing, creating, and updating Substack newsletter drafts through an MCP-compatible client.515 npm1Apache 2.0