substack-api-mcp-server
Self-hosted Substack API and MCP server in Python: all 50 Substack tools (drafts from Markdown, scheduling, Notes, comments, subscribers, stats, DMs) on your own Chrome session. Noncommercial use (PolyForm Noncommercial 1.0.0).
Install / Use
claude mcp add cotletdev -- npx -y github:cotletdev/substack-api-mcp-serverIf the server publishes to npm under a different name, use that package instead β check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
AutomationSupported Platforms
Our assessment of substack-api-mcp-server
substack-api-mcp-server scores 83/100 on our quality scale, 2202nd of 2,887 Automation skills we index.
Its MCP Server is 30 KB long, well organised into 38 sections with 18 code examples: a thorough specification that gives an agent plenty to work with.
It has 3 GitHub stars, so there is little community track record yet; judge it on its content.
Maintenance, license and trust
- The repository was last updated today, so substack-api-mcp-server is actively maintained.
- No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
- Its trust signals score 80/100, with 2 cautions from licensing, adoption, age or documentation. These come from repository metadata, not a code audit β read the skill file before letting an agent act on it.
substack-api-mcp-server compared with similar skills
All 4 of these similar skills score higher than substack-api-mcp-server; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| substack-api-mcp-server (this skill)by cotletdev | 83 | 3 | today | MCP Server |
| Agent-Reachby Panniantong | 100 | 101.5k | 1d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 77.7k | today | CLAUDE.md |
| CowAgentby zhayujie | 100 | 47.5k | today | CLAUDE.md |
| Scraplingby D4Vinci | 100 | 89.4k | 1d ago | MCP Server |
Frequently asked questions
- How do I install substack-api-mcp-server?
- Run
claude mcp add cotletdev -- npx -y github:cotletdev/substack-api-mcp-server. The install tabs above show the steps for each supported agent. - Which AI agents does substack-api-mcp-server work with?
- It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
- Is substack-api-mcp-server safe to use?
- It declares no license and scores 80/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is substack-api-mcp-server still maintained?
- The repository was last updated today, so substack-api-mcp-server is actively maintained.
Skill content
View source on GitHubSubstack API and MCP server, self-hosted
<!-- mcp-name: dev.cotlet/substack -->A Substack API and a Substack MCP server you run on your own computer, in Python, on the session of your own Google Chrome. All 50 Substack tools we run in production at Cotlet: posts and drafts from Markdown, publishing and scheduling, Notes, comments, subscribers, stats, recommendations and direct messages.
Substack has no public API to write posts, publish Notes or manage subscribers, and no official MCP server. This repo gives you both:
- MCP server for Claude Code, Claude Desktop, Cursor, Codex and any MCP client, over stdio or HTTP. Setup
- REST API on
http://127.0.0.1:8787/api/v1/substack, with OpenAPI docs at/docs. Setup - Python:
call("list_posts", status="draft"), plus 14 ready scripts inexamples/.
It is for technical people who want to run it themselves, for noncommercial use only (license). If you want it running 24/7 on a server, kept working when Substack changes its site, for a team or a business, use the hosted version at cotlet.dev.
uv tool install substack-api-mcp # or: pip install substack-api-mcp
substack-mcp connect # reads your Substack session from Chrome
substack-mcp call list_posts
claude mcp add substack -- uvx substack-api-mcp mcp
Contents
- How it works
- Requirements
- Install
- Connect your Chrome
- MCP server
- REST API
- Python and the example scripts
- All 50 tools
- Configuration
- Security and your Substack account
- Errors
- Self-hosted or hosted
- FAQ
- License
How it works
AI agent (MCP) / script (REST, Python) βββΆ substack-mcp on your computer ββyour Substack cookiesβββΆ substack.com
β²
substack-mcp connect ββββββββ reads them once from your Chrome (DevTools Protocol)
- You sign in to Substack in your own Chrome, the way you always do.
substack-mcp connectattaches to that Chrome through the Chrome DevTools Protocol, reads the substack.com cookies and saves them to~/.config/substack-api-mcp/session.json, readable by your user only. Substack signs in by an emailed code or link, so there is no password to see or store.- Every tool call is a request to Substack's own web app endpoints (
substack.com/api/v1for the reader side,yourname.substack.com/api/v1for your publication's dashboard) with those cookies, sent with curl_cffi, which copies Chrome's TLS fingerprint. No headless browser runs.
Substack's session cookie (substack.sid) lasts about three months. When Substack signs you out, the server reads the cookies from Chrome again, if Chrome is open with remote debugging on.
Requirements
- Python 3.11 or newer.
- Google Chrome 144 or newer, signed in to Substack. Any Chrome or Chromium works with a debugging port.
- macOS, Linux or Windows.
- A Substack account. Publisher tools (posts, subscribers, stats, comments) work on the first publication your account runs as admin, owner, editor or contributor. Reader tools (feed, search, Notes, messages) work on any account.
Install
From PyPI:
uv tool install substack-api-mcp # or: pipx install substack-api-mcp, or: pip install substack-api-mcp
substack-mcp --version
MCP clients can also run it with no install: uvx substack-api-mcp mcp.
From source:
git clone https://github.com/cotletdev/substack-api-mcp-server.git
cd substack-api-mcp-server
python3 -m venv .venv
. .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
substack-mcp --version
With uv: uv venv && uv pip install -e ., then uv run substack-mcp ....
Setting it up with an AI agent (Claude Code, Codex, Cursor)? Open it in this folder and ask it to set up the repo: AGENTS.md tells it every step, and it asks you only for the steps in Chrome.
To update: uv tool upgrade substack-api-mcp (or pip install -U substack-api-mcp), from source git pull && pip install -e .. We copy every change of the hosted Substack tools into this repo.
Connect your Chrome
Option A: your everyday Chrome (recommended)
-
Open
chrome://inspect/#remote-debuggingin Chrome and switch remote debugging on. Chrome then accepts DevTools connections from programs on this computer, and asks you before each one. -
Make sure you are signed in at substack.com.
-
Run:
substack-mcp connect -
Chrome asks whether to allow the connection. Click Allow.
Saved 19 Substack cookies to /Users/you/.config/substack-api-mcp/session.json
Signed in to Substack as Maya Chen (@mayachen)
You can switch remote debugging off again afterwards. Leave it on if you want the server to pick up a new session by itself after Substack signs you out.
connect looks for Chrome's DevToolsActivePort file in the default profile folder. For Chrome Beta, Canary or a custom profile folder, pass --profile-dir "<folder>".
Option B: a Chrome with a debugging port
Chrome does not open a debugging port on your default profile, so start a separate one, sign in to Substack there once, and connect to it:
# macOS
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir="$HOME/.chrome-substack"
# Linux
google-chrome --remote-debugging-port=9222 --user-data-dir="$HOME/.chrome-substack"
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="%USERPROFILE%\.chrome-substack"
substack-mcp connect --cdp http://127.0.0.1:9222
--cdp also takes a ws:// DevTools URL, for example of a Chrome on another machine reached over an SSH tunnel.
Option C: paste the cookie by hand
For a server with no Chrome: in Chrome open DevTools on substack.com, Application > Cookies > https://substack.com, copy the value of substack.sid, then:
substack-mcp connect --token # paste it, input is hidden
# or, without a session file:
export SUBSTACK_AUTH_TOKEN=...
A pasted token is not refreshed on its own. Paste a new one when Substack signs you out.
Check the session at any time:
substack-mcp status
MCP server
The MCP server lists every tool with its input schema, a description written for agents, and hints: read tools are marked read-only, and tools that publish, message or delete are marked so your client asks before running them.
Claude Code
claude mcp add substack -- uvx substack-api-mcp mcp
# read only:
claude mcp add substack -- uvx substack-api-mcp mcp --read-only
Claude Desktop
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"substack": {
"command": "uvx",
"args": ["substack-api-mcp", "mcp"]
}
}
}
Cursor
~/.cursor/mcp.json, the same block as Claude Desktop. A ready copy is in mcp.json.
Codex
~/.codex/config.toml:
[mcp_servers.substack]
command = "uvx"
args = ["substack-api-mcp", "mcp"]
Over HTTP
substack-mcp serve also serves MCP over streamable HTTP at http://127.0.0.1:8787/mcp, for clients that take a URL:
substack-mcp serve
claude mcp add --transport http substack http://127.0.0.1:8787/mcp
Then ask your agent things like:
Turn essay.md into a draft for everyone and schedule it for Tuesday 8:00 New York time. Once it is out, post a Note with a link card to it.
Find comments on my last three posts that I have not answered and draft a short reply to each.
Last week's numbers: new and paid subscribers, cancellations, revenue, and opens for each post.
Where did my readers come from in the last 30 days?
REST API
substack-mcp serve # http://127.0.0.1:8787, MCP at /mcp, docs at /docs
Each tool has its own route under /api/v1/substack, the same paths as the hosted API at cotlet.dev, so code written against one works with the other. Path parts and the query string are arguments, and a JSON body adds the rest.
curl 'http://127.0.0.1:8787/api/v1/substack/posts?status=scheduled'
curl 'http://127.0.0.1:8787/api/v1/substack/stats?period=30d'
curl -X POST http://127.0.0.1:8787/api/v1/substack/drafts \
-H 'Content-Type: application/json' \
-d '{"title": "Notes on pricing", "body_markdown": "## Why I raised prices\n\nThree reasons..."}'
Any tool by name, body as its arguments:
curl -X POST http://127.0.0.1:8787/api/v1/substack/tools/list_comments -d '{"post_id": "148213977"}'
GET /api/v1/substack/tools: every tool with its route, input schema and an example answer.GET /docs: interactive OpenAPI docs,GET /openapi.jsonthe schema, for n8n, Postman or a generated client.- Answers are JSON. Lists return
next_cursor; pass it back ascursorfor the next page.
The server listens on 127.0.0.1 only. To reach it from another device of yours, set a token, and every request then needs Authorization: Bearer <token>:
SUBSTACK_MCP_TOKEN=$(openssl rand -hex 24) substack-mcp serve --host 0.0.0.0
Python and the example scripts
Straight from Python, no server needed:
from substack_api_mcp import call
from substack_api_mcp.scripting import paginate, write_rows
posts = list(paginate("list_posts", {"status": "published"}, "posts"))
write_rows(posts, "posts.csv")
draft = call("create_draft", title="Notes on pricing", body_markdown="Three reasons...")
call("schedule_post", post_id=draft["post_id"], publish_at="2026-11-03T08:00:00-05:00")
Or one tool from the shell: substack-mcp call get_post_stats post_id=148213977, or with a JSON object.
Ready scripts in examples/. Each prints JSON, takes --out file.csv or --out file.json where it makes sense, and --help:
| Script | What it does |
|---|---|
| draft_from_markdown.py | A .md file to a draft: the first heading is the title, headings, links and lists are kept. --publish-at schedules it. |
| schedule_post.py | Schedules a draft for a set time, or --cancel takes it back to drafts. |
| publish_note.py | A Note now or at a set time, --link-latest adds a
Truncated for display β read the full file on GitHub.
Related Skills
Agent-Reach
101.5kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu β one CLI, zero API fees.
headroom
77.7kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
CowAgent
47.5kOpen-source personal AI assistant & Agent Harness. Plans tasks, runs tools and skills, self-evolves with memory and knowledge. Multi-agent, multi-model, multi-channel. Lightweight, extensible, one-line install.
Scrapling
89.4kπ·οΈ A Web Scraping framework that handles everything from a single request to a full-scale crawl! Don't be shy, join here: https://discord.gg/EMgGbDceNQ and follow here for daily tips and tricks: https://x.com/Scrapling_dev
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit β see the Safety scan above for what the skill file itself contains.
