substack-mcp
Indexes and enables searching of Substack blog posts, providing tools for full-text search, filtering, citation generation, and markdown export.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@substack-mcpsearch my recent posts about artificial intelligence"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Substack MCP Server
A Model Context Protocol (MCP) server that indexes and enables searching of Substack blog posts. Built for the Fejl 40 publication.
Overview
This MCP server fetches blog posts from a Substack RSS feed and provides tools for searching and querying the content through Claude Desktop. It includes full-text search, in-memory caching, and automatic refresh capabilities.
Related MCP server: substack-mcp-plus
Features
Full-text Search: Search across post titles, content, and descriptions using FlexSearch
Persistent Disk Cache: Saves posts to disk for instant startup (~/.cache/substack-mcp/)
Smart Caching: In-memory cache with configurable TTL (default: 30 minutes)
Auto-refresh: Automatically updates when cache expires
7 MCP Tools:
search_posts- Search by keywordslist_recent_posts- Get most recent postsget_post_by_title- Find by titleget_post_by_url- Get by URLget_posts_by_date_range- Filter by date rangegenerate_citation- Generate formatted citations (APA, MLA, Chicago, markdown)export_to_markdown- Export posts to markdown files
Installation
Prerequisites
Node.js 18 or higher
Claude Desktop app
npm
Setup
Clone or download this repository:
git clone https://github.com/andersschaffner/substack-mcp.git cd substack-mcpInstall dependencies:
npm installBuild the project:
npm run buildConfigure Claude Desktop:
Add this to your Claude Desktop config file:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%/Claude/claude_desktop_config.json
{ "mcpServers": { "substack-mcp": { "command": "node", "args": ["/absolute/path/to/substack-mcp/index.js"], "env": { "SUBSTACK_FEED_URL": "https://fejl40.substack.com/feed" } } } }Important: Replace
/absolute/path/to/substack-mcp/with the actual path where you cloned the repo.Restart Claude Desktop
Configuration
Environment Variables
SUBSTACK_FEED_URL- The RSS feed URL for your Substack publication (required)CACHE_TTL_MS- Cache time-to-live in milliseconds (default: 1800000 = 30 minutes)
Using with a Different Substack
To use with a different Substack publication, simply change the SUBSTACK_FEED_URL in your Claude Desktop config:
"env": {
"SUBSTACK_FEED_URL": "https://your-publication.substack.com/feed"
}Usage
Once installed and configured, you can ask Claude questions about your blog posts:
"Search my blog posts about AI"
"What have I written about product management?"
"Show me my most recent blog posts"
"Find my post about [specific topic]"
"What did I write in December 2024?"
Claude will automatically use the MCP tools to search and retrieve your blog content.
Available Tools
search_posts
Search blog posts by keywords across title and content.
Parameters:
query(string, required) - Search querylimit(number, optional) - Maximum results (default: 10)
list_recent_posts
List the most recent blog posts.
Parameters:
limit(number, optional) - Number of posts (default: 10)offset(number, optional) - Posts to skip (default: 0)
get_post_by_title
Get a specific post by exact or partial title match.
Parameters:
title(string, required) - Post title or partial titleexact(boolean, optional) - Require exact match (default: false)
get_post_by_url
Retrieve a specific post by its URL.
Parameters:
url(string, required) - Full URL of the Substack post
get_posts_by_date_range
Get posts published within a date range.
Parameters:
start_date(string, required) - Start date (ISO 8601 format)end_date(string, required) - End date (ISO 8601 format)limit(number, optional) - Maximum results (default: 100)
generate_citation
Generate a formatted citation for a blog post.
Parameters:
url(string, required) - URL of the blog post to citestyle(string, optional) - Citation style: 'APA', 'MLA', 'Chicago', or 'markdown' (default: 'markdown')
Example output:
{
"citation": "[Post Title](https://fejl40.substack.com/...) by Anders Schaffner, December 15, 2024",
"style": "markdown",
"post": {
"title": "Post Title",
"link": "https://fejl40.substack.com/...",
"author": "Anders Schaffner",
"pubDate": "2024-12-15T..."
}
}export_to_markdown
Export blog posts to a markdown file.
Parameters:
output_path(string, required) - Output file path (e.g., ~/Desktop/posts.md)query(string, optional) - Search query to filter postsstart_date(string, optional) - Start date filter (ISO 8601 format)end_date(string, optional) - End date filter (ISO 8601 format)limit(number, optional) - Maximum posts to export (default: 100)
Example usage:
Export all posts:
export_to_markdown({ output_path: "~/Desktop/all-posts.md" })Export AI-related posts:
export_to_markdown({ output_path: "~/Desktop/ai-posts.md", query: "AI" })Export 2024 posts:
export_to_markdown({ output_path: "~/Desktop/2024.md", start_date: "2024-01-01", end_date: "2024-12-31" })
Development
Scripts
npm run build- Build the TypeScript projectnpm run dev- Build in watch modenpm start- Run the compiled server
Project Structure
.
├── src/
│ ├── index.ts # Main MCP server
│ ├── post-cache.ts # Caching and search logic with disk persistence
│ ├── rss-fetcher.ts # RSS feed parser
│ ├── citation.ts # Citation formatting (APA, MLA, Chicago, markdown)
│ ├── export.ts # Export to markdown/JSON
│ ├── types.ts # TypeScript interfaces
│ └── utils.ts # Helper functions
├── build.js # esbuild configuration
├── package.json
├── tsconfig.json
└── index.js # Compiled outputHow It Works
Server Startup: When Claude Desktop launches, it starts the MCP server
Disk Cache Load: Server attempts to load posts from disk cache (~/.cache/substack-mcp/posts.json)
RSS Fetch: If disk cache is missing or stale, fetches posts from the Substack RSS feed
Indexing: Posts are indexed with FlexSearch for fast searching
Disk Persistence: Posts are saved to disk cache for instant startup next time
Memory Caching: Posts are cached in memory with a 30-minute TTL
Auto-refresh: Cache automatically refreshes when it expires
Tool Calls: Claude calls the MCP tools when you ask about your blog
Performance: With disk cache, startup is nearly instant (< 1 second). Without disk cache, first startup takes 3-5 seconds to fetch RSS.
Troubleshooting
"Command not found" or server won't start
Ensure the path in
claude_desktop_config.jsonis absolute, not relativeVerify Node.js is installed:
node --versionCheck that
index.jsexists after runningnpm run build
No posts found
Verify the RSS feed URL is correct and accessible
Check Claude's MCP logs:
~/Library/Logs/Claude/mcp*.logEnsure the RSS feed has posts
JSON parse errors
Make sure you're using the latest build
All logging should go to stderr, not stdout
Technical Details
Language: TypeScript
Runtime: Node.js 18+
Build Tool: esbuild
Search Engine: FlexSearch
RSS Parser: rss-parser
MCP SDK: @modelcontextprotocol/sdk v1.25+
License
ISC
Author
Anders Schaffner
Contributing
Feel free to open issues or submit pull requests for improvements!
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/andersschaffner/substack-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server