substack-mcp
Allows creating, editing, scheduling, and publishing drafts on a Substack publication, including uploading images and setting cover thumbnails.
Click on "Install 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 a draft called 'My First Post' and schedule it for tomorrow"
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.
substack-mcp
A Model Context Protocol (MCP) server for Substack. Lets Claude Code create drafts, upload images, set cover thumbnails, schedule, and publish posts on your Substack publication.
Built on top of
python-substack. Uses Substack's internal API (no public posting API exists). Not affiliated with Substack Inc.
Tools
Required
create_draft(title, content_markdown, subtitle?, audience?)— Create a new draft from Markdown.update_draft(post_id, title?, subtitle?, content_markdown?, audience?)— Edit an existing draft.upload_image(image_path)— Upload a local file or remote URL to Substack's CDN, returning the URL.publish_draft(post_id, send_email?, share_automatically?)— Publish immediately.send_emailtoggles email delivery.
Recommended
schedule_draft(post_id, iso_datetime)— Schedule a publish for a future date/time (ISO 8601).unschedule_draft(post_id)— Cancel a scheduled publish.set_cover_image(post_id, image_url)— Set the cover thumbnail (fromupload_imageURL).
Utility
list_drafts(limit?)— List recent drafts.get_draft(post_id)— Get a draft's full body.delete_draft(post_id)— Permanent deletion.
Setup
# 1. Install dependencies
uv pip install -e .
# 2. Make sure you're logged in to Substack in Chrome (or Brave/Edge) — that's it.
# 3. Save credentials — auto-detects your existing browser session
substack-mcp-setup
# 4. Register with Claude Code
claude mcp add substack-mcp --scope user -- /Users/$USER/substack/.venv/bin/substack-mcpRestart Claude Code, then /mcp should show substack-mcp as connected.
How auth works
By default substack-mcp-setup reads the substack.sid cookie directly from
your existing Chrome session via pycookiecheat.
Substack can't tell anything was automated because nothing was: it's the
same session you're already using.
macOS will prompt once for Keychain access ("Chrome Safe Storage"). Click "Always Allow" so it doesn't ask again next time.
Supports: Chrome, Brave, Edge, Chromium, Vivaldi, Opera.
Fallback modes
# Specific browser
substack-mcp-setup --from-browser brave
# Playwright-based (often blocked by Substack — use --chrome instead)
substack-mcp-setup --browser
# Manual paste from DevTools
substack-mcp-setup --manualTokens are stored at ~/Library/Application Support/substack-mcp/config.json
with 0600 permissions.
Security
The substack.sid cookie is equivalent to a password — anyone with it has
full account access (publish posts, edit billing, etc.). Treat it as such.
Where the token lives
macOS:
~/Library/Application Support/substack-mcp/config.json(mode0600)Linux:
~/.config/substack-mcp/config.json(mode0600)Or via env vars:
SUBSTACK_PUBLICATION_URL+SUBSTACK_SESSION_TOKEN(env vars are inherited by child processes — be aware when spawning subprocesses)
The .gitignore excludes config.json; never commit it. The MCP also writes
a temporary cookie file via tempfile.mkstemp (mode 0600) and deletes it in
a finally block — see auth.py:write_cookie_file.
If a token leaks
Sign out of all sessions: Substack → Settings → Security → "Sign out of all sessions". This invalidates every existing
substack.sidimmediately.Log back in to Substack in your browser.
Re-run
substack-mcp-setupto capture the new cookie.
Image upload safety
upload_image only accepts:
HTTP(S) URLs, or
Local files with image extensions (
.png,.jpg,.jpeg,.gif,.webp,.heic,.heif) that are not under sensitive system paths (/etc,/System,~/.ssh,~/.aws,~/Library/Keychains, etc.)
This guards against an assistant being tricked (via prompt injection in fetched content) into uploading e.g. an SSH private key to Substack's CDN.
Known limitation: Markdown image syntax  inside create_draft
is processed by python-substack and bypasses this validation. If you pass
untrusted Markdown, sanitize image paths first.
Dependencies
Versions are pinned with ~= (compatible release, no major bumps). Bumping
python-substack in particular should be reviewed — it talks to Substack's
private API and lives outside Substack's official surface.
Notes
audienceaccepts:everyone(default),only_paid,founding,only_free.Markdown image syntax
auto-uploads local files when you callcreate_draft.The cover image (set via
set_cover_image) is what appears on your publication homepage and in social shares. If you don't set one explicitly, Substack typically uses the first image in the body.
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/nanameru/substack-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server