loading…
Search for a command to run...
loading…
Enables programmatic management of Substack content, including creating drafts, publishing posts, and uploading images. It supports specialized features like li
Enables 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.
A Model Context Protocol (MCP) server for Substack integration with Claude Code and other MCP-compatible AI tools.
# Clone the repo
git clone https://github.com/acolle/substack-mcp.git
cd substack-mcp
# Install dependencies
pip install -r requirements.txt
python -m unittest discover -s tests
substack.sid and copy its value# Create ~/.substackrc
cat > ~/.substackrc << 'EOF'
export SUBSTACK_PUBLICATION="your-publication.substack.com"
export SUBSTACK_SID="your-cookie-value-here"
EOF
# Add the MCP server to Claude Code
claude mcp add substack \
--command "bash" \
--args "-c" "source ~/.substackrc && python3 $(pwd)/substack_mcp/server.py"
Or manually add to ~/.claude.json:
{
"mcpServers": {
"substack": {
"command": "bash",
"args": ["-c", "source ~/.substackrc && python3 /path/to/substack-mcp/substack_mcp/server.py"]
}
}
}
| Tool | Description |
|---|---|
substack_create_draft |
Create a new draft post |
substack_update_draft |
Update an existing draft |
substack_append_to_draft |
Append content (for live blogging) |
substack_add_code_block |
Add a code block to a draft |
substack_add_image |
Add an image to a draft |
substack_publish |
Publish a draft |
substack_post_note |
Post a short note |
substack_get_drafts |
List all drafts |
substack_get_posts |
List published posts |
substack_live_blog_start |
Start a live blogging session |
substack_live_blog_end |
End live blogging session |
You: Create a new Substack post about AI tools
Claude: I'll create a draft for you...
[Uses substack_create_draft tool]
Created draft 12345. Edit at: https://your-pub.substack.com/publish/post/12345
You: Add this diagram to my post [image path]
Claude: I'll upload the image and add it to your draft...
[Uses substack_add_image tool]
Image added successfully.
You: Start a live blog for the product launch
Claude: Starting live blog session...
[Uses substack_live_blog_start tool]
Live blog started. I'll append updates as they happen.
The core client for interacting with Substack's API.
from substack_client import SubstackClient, SubstackDocument
# rate_limit is seconds between requests; timeout is per-request timeout.
client = SubstackClient(token="your-sid", publication="your-pub.substack.com", rate_limit=0.5, timeout=30.0)
# Upload an image
img = client.upload_image("/path/to/image.png")
# Returns: {"url": "https://...", "width": 800, "height": 600, "bytes": 12345, "contentType": "image/png"}
# Create a document
doc = SubstackDocument()
doc.heading("My Post", level=2)
doc.paragraph("Hello world!")
doc.image(src=img['url'], width=img['width'], height=img['height'],
bytes_size=img['bytes'], content_type=img['contentType'])
# Create and publish
draft = client.create_draft(title="My Post", body=doc)
client.publish_draft(draft.id, send_email=False)
Substack uses ProseMirror and requires specific attributes for images:
{
"type": "captionedImage",
"content": [{
"type": "image2",
"attrs": {
"src": "https://substack-post-media.s3.amazonaws.com/...",
"width": 800,
"height": 600,
"bytes": 12345,
"type": "image/png",
"internalRedirect": "https://pub.substack.com/i/{draft_id}?img={encoded_url}",
"belowTheFold": false,
"topImage": false,
"isProcessing": false
}
}]
}
The internalRedirect field is required - without it, Substack's editor fails to render the document.
create_draft and update_draft automatically add missing internalRedirect values for any image nodes.imageCaption nodes) to avoid editor rendering issues.upload_image() and use the returned metadata.MIT
This uses Substack's unofficial/internal API which may change without notice. Use at your own risk.
Добавь это в claude_desktop_config.json и перезапусти Claude Desktop.
{
"mcpServers": {
"substack-mcp-server": {
"command": "npx",
"args": []
}
}
}