An open-source CLI, TypeScript SDK, and MCP server for automating Substack. Built for AI agents and developers who need programmatic access to Substack's platform.
Substack doesn't offer a public API. This tool uses reverse-engineered internal endpoints to provide full automation capabilities: create posts, publish notes, manage subscribers, view analytics, and more.
This is a community tool. Fork it, extend it, build on top of it. Not affiliated with Substack Inc.
| Feature | CLI | SDK | MCP |
|---|---|---|---|
| Authentication (cookie / email+password) | ✅ | ✅ | ✅ |
| Create posts (draft or publish) | ✅ | ✅ | ✅ |
| Publish drafts | ✅ | ✅ | ✅ |
| List posts (published / drafts) | ✅ | ✅ | ✅ |
| Delete posts | ✅ | ✅ | ✅ |
| Create notes | ✅ | ✅ | ✅ |
| List notes | ✅ | ✅ | ✅ |
| Like notes | — | ✅ | ✅ |
| Restack notes | — | ✅ | ✅ |
| List subscribers | ✅ | ✅ | ✅ |
| Subscriber stats | — | ✅ | ✅ |
| Profile info | — | ✅ | ✅ |
| Post analytics | — | ✅ | ✅ |
# Install globally
npm install -g substack-tool
# Or use npx
npx substack-tool --helpThis tool authenticates using Substack's session cookie (connect.sid). Here's how to get it:
- Log in to substack.com in your browser
- Open DevTools (
F12orCmd+Shift+I) - Go to Application → Cookies →
https://substack.com - Find the
connect.sidcookie - Copy its value (starts with
s%3A...)
⚠️ Keep this cookie private. It grants full access to your Substack account. Never commit it to version control. Store it in an environment variable.
export SUBSTACK_COOKIE="connect.sid=s%3A..."# Login with cookie (recommended)
substack-tool auth login --cookie "connect.sid=s%3A..."
# Login with email/password (experimental)
substack-tool auth login --email you@example.com --password "yourpassword"
# Check auth status
substack-tool auth status# Create a draft
substack-tool post create --title "My Post Title" --body "<h1>Hello World</h1><p>This is my post.</p>"
# Create from a Markdown file and publish immediately
substack-tool post create --title "Weekly Update" --file ./post.md --publish
# List published posts
substack-tool post list --status published
# List drafts
substack-tool post list --status draft# Post a note
substack-tool note create --body "Interesting thought of the day..."
# List recent notes
substack-tool note list --limit 10# List subscribers
substack-tool subscribers list --limit 50Use the SDK in your own projects for programmatic Substack automation.
npm install substack-toolimport { Substack } from 'substack-tool';
const client = new Substack({
cookie: process.env.SUBSTACK_COOKIE
});
// Create a draft post
const draft = await client.createPost({
title: 'Automated Post',
body: '<p>Published by an AI agent.</p>',
draft: true
});
console.log(`Draft created: #${draft.id}`);
// Publish it
await client.publishPost(draft.id);
// Post a note
await client.createNote('Just published a new post!');
// Get subscriber count
const stats = await client.getSubscriberStats();
console.log(`Subscribers: ${stats.count}`);
// Get post analytics
const analytics = await client.getPostAnalytics(draft.id);
console.log(`Views: ${analytics.views}, Likes: ${analytics.likes}`);
// List recent notes
const notes = await client.listNotes(10);
notes.forEach(n => console.log(`- ${n.body}`));| Method | Description |
|---|---|
login(email, password) |
Authenticate with email/password |
getCookie() |
Get current session cookie string |
listPosts(status, limit, offset) |
List posts (published/draft/all) |
createPost({ title, body, draft }) |
Create a new post |
publishPost(draftId) |
Publish a draft |
deletePost(id) |
Delete a post |
listNotes(limit) |
List recent notes |
createNote(body) |
Create a note |
likeNote(noteId) |
Like a note |
restackNote(noteId) |
Restack (repost) a note |
listSubscribers(limit) |
List subscribers |
getSubscriberStats() |
Get subscriber count/growth |
getProfile() |
Get your profile info |
getPostAnalytics(postId) |
Get post view/like/comment stats |
This tool includes a Model Context Protocol (MCP) server, allowing AI agents like Claude, GPT, or any MCP-compatible client to automate Substack through natural language.
Add to your claude_desktop_config.json:
{
"mcpServers": {
"substack": {
"command": "npx",
"args": ["-y", "substack-tool", "--mcp"],
"env": {
"SUBSTACK_COOKIE": "connect.sid=s%3A..."
}
}
}
}Or if installed globally:
{
"mcpServers": {
"substack": {
"command": "substack-mcp",
"env": {
"SUBSTACK_COOKIE": "connect.sid=s%3A..."
}
}
}
}| Tool | Description |
|---|---|
substack_auth_status |
Check authentication status |
substack_list_posts |
List posts with status filter |
substack_create_post |
Create a post (draft or published) |
substack_publish_post |
Publish a draft by ID |
substack_delete_post |
Delete a post by ID |
substack_create_note |
Create a short-form note |
substack_list_notes |
List recent notes |
substack_like_note |
Like a note |
substack_restack_note |
Restack (share) a note |
substack_list_subscribers |
List publication subscribers |
substack_get_subscriber_stats |
Get subscriber growth stats |
substack_get_profile |
Get profile information |
substack_get_post_analytics |
Get analytics for a post |
Once connected via MCP, you can say things like:
- "Create a draft post titled 'Weekly AI Roundup' with a summary of this week's AI news"
- "Post a note saying 'New article just dropped! Check it out.'"
- "Show me my subscriber count"
- "List my last 5 published posts and their view counts"
- "Publish my draft #12345"
If you need a REST API (for webhooks, n8n, Make, Zapier, etc.), you can run the SDK behind a simple Express server:
import express from 'express';
import { Substack } from 'substack-tool';
const app = express();
app.use(express.json());
const client = new Substack({ cookie: process.env.SUBSTACK_COOKIE });
app.post('/api/posts', async (req, res) => {
const post = await client.createPost(req.body);
res.json(post);
});
app.post('/api/notes', async (req, res) => {
const note = await client.createNote(req.body.body);
res.json(note);
});
app.get('/api/subscribers', async (req, res) => {
const subs = await client.listSubscribers();
res.json(subs);
});
app.listen(3000, () => console.log('Substack API running on :3000'));git clone https://github.com/anyrxo/substack-tool.git
cd substack-tool
npm install
npm run build
# Run CLI locally
node dist/cli.js --help
# Run MCP server locally
SUBSTACK_COOKIE="..." node dist/mcp.jsSubstack doesn't provide a public API, but their web app makes internal API calls that can be observed and replicated. This tool:
- Authenticates using your session cookie (the same one your browser uses)
- Makes the same HTTP requests that Substack's web interface makes
- Parses the JSON responses into typed TypeScript objects
This is the same approach used by browser extensions, automation tools, and integrations across the industry. We're not bypassing any security measures; we're simply making the same requests your browser already makes.
For detailed endpoint documentation, see docs/api-reference.md.
"Unauthorized" or "403" errors
Your connect.sid cookie has expired. Get a fresh one from your browser. Cookies typically last a few weeks but may expire sooner.
Notes not posting Substack Notes use a ProseMirror document format internally. The SDK handles this conversion automatically, but complex formatting (images, embeds) in notes may not be supported yet.
Rate limiting Substack may rate-limit rapid requests. Add delays between bulk operations. The SDK doesn't currently handle rate limiting automatically.
This project is not affiliated with, endorsed by, or associated with Substack Inc. in any way.
This is an independent, community-driven, open-source tool created for educational and research purposes. It uses Substack's internal (undocumented) API endpoints, which are not officially supported and may change or break at any time without notice.
By using this tool, you acknowledge that:
- You are solely responsible for how you use it
- You must comply with Substack's Terms of Service
- Automated access to Substack may violate their terms; use at your own risk
- The authors and contributors accept no liability for any consequences of using this tool
- This tool is provided "as is" without warranty of any kind
This project is intended for educational purposes, to demonstrate how web APIs work and how automation tools can be built. If Substack releases an official API, this tool should be migrated to use it.
If you are from Substack and have concerns about this project, please open an issue and we will address them promptly.
PRs welcome. Please open an issue first to discuss what you want to change.
MIT