#!/usr/bin/env python3
"""
Setup script for Substack Reader MCP Server.
This script helps you:
1. Export cookies from your browser
2. Configure your Substack username
3. Test the connection
"""
import json
import os
import subprocess
import sys
from pathlib import Path
CONFIG_DIR = Path.home() / ".config" / "substack-reader"
COOKIES_PATH = CONFIG_DIR / "cookies.json"
CONFIG_PATH = CONFIG_DIR / "config.json"
def ensure_config_dir():
"""Create config directory if it doesn't exist."""
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
print(f"✓ Config directory: {CONFIG_DIR}")
def get_cookies_instructions():
"""Print instructions for exporting cookies."""
print("""
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STEP 1: Export Substack Cookies
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Install a cookie export extension:
- Chrome: "EditThisCookie" or "Cookie-Editor"
- Firefox: "Cookie-Editor"
2. Log into Substack (substack.com) in your browser
3. Open the cookie extension and export ALL cookies as JSON
4. Save the JSON to: {cookies_path}
The file should look like:
[
{{"name": "substack.sid", "value": "...", ...}},
{{"name": "substack.lli", "value": "...", ...}},
...
]
Press Enter when you've saved the cookies file...
""".format(cookies_path=COOKIES_PATH))
input()
def verify_cookies():
"""Verify cookies file exists and has required cookies."""
if not COOKIES_PATH.exists():
print(f"✗ Cookies file not found at {COOKIES_PATH}")
return False
try:
with open(COOKIES_PATH) as f:
cookies = json.load(f)
required = {"substack.sid"}
found = {c.get("name") for c in cookies}
if required & found:
print(f"✓ Found {len(cookies)} cookies including substack.sid")
return True
else:
print("✗ Missing required cookie: substack.sid")
return False
except json.JSONDecodeError:
print("✗ Invalid JSON in cookies file")
return False
def get_username():
"""Get and save Substack username."""
print("""
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STEP 2: Configure Username
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Your Substack username is the part after @ in your profile URL.
Example: If your profile is substack.com/@johndoe, your username is "johndoe"
""")
username = input("Enter your Substack username: ").strip().lstrip("@")
if username:
config = {"username": username}
with open(CONFIG_PATH, "w") as f:
json.dump(config, f, indent=2)
print(f"✓ Saved username: {username}")
return username
return None
def test_connection(username):
"""Test the connection by fetching subscriptions."""
print("""
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STEP 3: Testing Connection
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
""")
try:
from substack_api import User
user = User(username)
subs = user.get_subscriptions()
print(f"✓ Found {len(subs)} subscriptions!")
if subs:
print("\nYour subscriptions:")
for i, sub in enumerate(subs[:10], 1):
name = sub.get("name", sub.get("url", "Unknown"))
print(f" {i}. {name}")
if len(subs) > 10:
print(f" ... and {len(subs) - 10} more")
return True
except Exception as e:
print(f"✗ Error: {e}")
return False
def print_config_instructions(username):
"""Print Claude Code configuration instructions."""
server_path = Path(__file__).parent / "server.py"
print(f"""
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STEP 4: Configure Claude Code
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Add this to your Claude Code settings (~/.claude/settings.json):
{{
"mcpServers": {{
"substack-reader": {{
"command": "python3",
"args": ["{server_path}"],
"env": {{
"SUBSTACK_USERNAME": "{username}",
"SUBSTACK_COOKIES_PATH": "{COOKIES_PATH}"
}}
}}
}}
}}
Then restart Claude Code to load the MCP server.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Available Tools
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• list_subscriptions - List all your subscribed newsletters
• get_feed - Get recent posts from all subscriptions
• get_recent_posts - Get posts from a specific newsletter
• read_post - Read full content of any post
• search_newsletter - Search within a newsletter
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ Setup Complete!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
""")
def main():
print("""
╔═══════════════════════════════════════════════════════════╗
║ SUBSTACK READER MCP SERVER - SETUP ║
╚═══════════════════════════════════════════════════════════╝
""")
ensure_config_dir()
get_cookies_instructions()
if not verify_cookies():
print("\nPlease save your cookies and run setup again.")
sys.exit(1)
username = get_username()
if not username:
print("\nUsername required. Run setup again.")
sys.exit(1)
test_connection(username)
print_config_instructions(username)
if __name__ == "__main__":
main()