Substack MCP
by codalanguez
README.md
# Substack MCP
> ⚠️ **Unofficial. Use at your own risk.** This drives Substack's private,
> undocumented API by reverse-engineering the browser session — there is no
> official API. It may break without notice and may be against Substack's terms.
> Auth is a **session cookie (`substack.sid` / `connect.sid`) — a bearer secret,
> treat it like a password**: never commit it, keep it in a local gitignored
> `.env`, rotate it if exposed. No warranty. See [SECURITY.md](SECURITY.md).
An MCP server that lets Claude (or any MCP client) drive Substack: publish
Notes and posts, manage drafts, pull analytics, and read any publication's
public feed.
Substack has **no official API**. Like every Substack automation, this talks to
the private, undocumented API using your browser session cookie (`substack.sid`).
That means:
- **Endpoints can change without notice.** If a tool starts returning odd
errors, an endpoint probably moved.
- **The cookie is a bearer secret.** Anyone holding it *is* you, and it stays
valid for months even with MFA on. It lives only in a local, gitignored
`.env` — never in code or the MCP client config.
- **Be polite to the API.** Calls are throttled to ~1 request/second.
Publishing tools (`publish_note`, `publish_post`, `schedule_post`) are **public
and irreversible**. Treat them accordingly.
## Tools (20)
**Connection**
- `test_connection` — verify the cookie works; returns your user id/handle.
**Notes**
- `publish_note` — post a Note now (markdown supported).
- `reply_to_note` — reply to a Note by id.
- `create_note_attachment` — attach an image (local file or URL) or a link.
- `list_my_notes` — your recent Notes with engagement counts.
**Posts**
- `create_draft` / `update_draft` — compose and edit drafts (markdown body).
- `publish_post` — publish a draft live (optionally emailing subscribers).
- `schedule_post` — schedule a draft (ISO-8601 UTC).
- `list_drafts` / `list_published` / `get_post` — inventory and read.
- `list_sections` — section ids (needed if your publication uses sections).
- `upload_image` — push a local image to Substack's CDN.
**Stats**
- `get_dashboard` — subscribers, paid, views, growth over 30/60/90 days.
- `get_post_stats` — per-post views/opens/clicks/shares/conversions.
- `get_subscriber_growth` — subscriber count over time.
- `get_top_posts` — ranked by engagement.
- `get_earnings` — pledge/revenue summary.
**Public (no auth)**
- `get_public_posts` — read any publication's RSS feed (defaults to yours).
## Setup
Dependencies are already installed in `.venv`. To recreate from scratch:
```bash
py -3.14 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
```
### 1. Get your session cookie
1. Log into Substack in a browser.
2. Open DevTools (F12) → **Application** → **Cookies** → `https://substack.com`.
3. Copy the **value** of the `substack.sid` cookie.
### 2. Configure
```bash
cp .env.example .env
```
Edit `.env`:
```
SUBSTACK_SID=<substack.sid from substack.com>
SUBSTACK_SUBDOMAIN=codalanguez
SUBSTACK_PUB_HOST=newsletter.codalanguez.com
SUBSTACK_PUB_SID=<substack.sid from newsletter.codalanguez.com>
```
**Custom domains need two cookies.** Coda's publication redirects
`codalanguez.substack.com` → `newsletter.codalanguez.com`, and Substack splits
auth across the two hosts:
| Env var | Extract from | Cookie name | Used for |
| --- | --- | --- | --- |
| `SUBSTACK_SID` | `substack.com` | `substack.sid` | Notes, profile, public reads |
| `SUBSTACK_PUB_SID` | `newsletter.codalanguez.com` | **`connect.sid`** | dashboard, drafts, publishing, stats |
The two hosts use **different cookie names** — `substack.com` uses `substack.sid`,
the custom domain uses `connect.sid` (Substack's older stack). Extract each via
DevTools → Application → Cookies → *that host* → *that cookie*. For a plain
`*.substack.com` publication, leave `SUBSTACK_PUB_HOST` / `SUBSTACK_PUB_SID`
blank — `SUBSTACK_SID` covers everything.
### 3. Verify
```bash
.\.venv\Scripts\python.exe -c "import asyncio, server; print(asyncio.run(server.test_connection()))"
```
You should see your user id and handle. `Auth failed` means the cookie is
missing or expired — re-extract it.
## Register with Claude Code
```bash
claude mcp add substack -- "<repo>/.venv/Scripts/python.exe" "<repo>/server.py"
```
Replace `<repo>` with the absolute path to your clone. No secret goes in the
client config — the server reads `.env` itself. Restart Claude Code and the tools
appear under the `substack` server.
## Weekly health check
`health_check.py` pulls your current stats, writes a timestamped JSON snapshot +
markdown report with week-over-week deltas, then asks `claude -p` to append an
**Analysis & Recommendations** section. Output goes to `health-checks/reports/`
and `health-checks/snapshots/`; each run appends a line to `health-checks/run.log`.
```bash
.\.venv\Scripts\python.exe health_check.py # full report + analysis
.\.venv\Scripts\python.exe health_check.py --no-analysis # numbers only
```
It's registered as a Windows Scheduled Task — **"Weekly Substack Health Check —
Coda Languez"**, Mondays 9:00 AM (America/Denver). Manage it:
```powershell
$n = "Weekly Substack Health Check " + [char]0x2014 + " Coda Languez"
Get-ScheduledTaskInfo -TaskName $n # last run / result
Start-ScheduledTask -TaskName $n # run now
Disable-ScheduledTask -TaskName $n # pause
```
To change the day/time, edit the trigger in Task Scheduler (or re-run the
`Register-ScheduledTask` command with a new `-At` / `-DaysOfWeek`). Reports need
`SUBSTACK_PUB_SID` set; without it the report notes that stats are unavailable.
## When the cookie expires
Tools return `{"error": "Auth failed — the substack.sid cookie is likely
expired..."}`. Re-extract `substack.sid` (step 1) and update `.env`.
## Credits
Endpoint shapes were verified against the open-source
[`adelaidasofia/substack-mcp`](https://github.com/adelaidasofia/substack-mcp)
(MIT) and [`ma2za/python-substack`](https://github.com/ma2za/python-substack).
The cookie-extraction technique follows Paweł Huryn's write-up on Substack's
undocumented API.
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues