substack-mcp
Indexes and enables searching of Substack blog posts, providing tools for full-text search, filtering, citation generation, and markdown export.
Click on "Deploy 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-article-mcp
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!
Available Tools
7 toolsexport_to_markdownC
Export blog posts to a markdown file
Inputs: output_path (required), limit, query, end_date, +1 more.
generate_citationB
Generate a formatted citation for a blog post
Inputs: url (required), style.
get_post_by_titleC
Get a specific post by exact or partial title match
Inputs: title (required), exact.
get_post_by_urlC
Retrieve a specific post by its URL
Inputs: url (required).
get_posts_by_date_rangeC
Get posts published within a date range
Inputs: end_date (required), start_date (required), limit.
list_recent_postsC
List the most recent blog posts
Inputs: limit, offset.
search_postsB
Search blog posts by keywords across title, content, and description
Inputs: query (required), limit.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
TDQS
Scored across 7 tools
The five retrieval tools differ by access pattern (keyword, recency, title, URL, date range), which is mostly clear. However, get_post_by_title and search_posts can overlap when a title is used as a keyword, and generate_citation vs export_to_markdown both consume posts, creating mild boundary blur.
All tools follow a consistent snake_case verb_noun pattern (search_posts, list_recent_posts, get_post_by_title, export_to_markdown). The convention is predictable and readable throughout.
Seven tools is well-scoped for a blog reading/search server, with each tool earning its place by covering a distinct retrieval or output mode.
Core read workflows (search, recency, by title, by URL, by date, cite, export) are well covered. Minor gaps exist around author/subscription or comment retrieval, but these are workable given the reading-focused scope.
Maintenance
Related MCP Connectors
Search Hacker News, Bluesky, and Substack from a single MCP interface
Substack newsletter, posts & podcast search
Search your Glasp web and Kindle highlights, notes, and AI memories from any MCP client. Read-only.
Search your newsletter and YouTube archive, drafted actions and working context from any MCP client.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables 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.MIT
- AlicenseNot gradedqualityDmaintenanceMCP server for Substack that enables reading articles, comments, feed, and subscriptions from AI clients like Cursor and Claude, with optional authentication for paid content.28 npm5MIT
- AlicenseAqualityBmaintenanceA local MCP server for managing saved Substack posts. Enables offline reading, searching, bookmarking, and unbookmarking of Substack content via CLI or MCP clients.18MIT
- AlicenseNot gradedqualityDmaintenanceEnables managing Substack publications: publish Notes and posts, manage drafts, pull analytics, and read any publication's public feed via MCP.MIT