Substack Read
substack_readRead other people's Substack content and research the market. Read only.
Actions: list_articles, get_article, search_articles, get_comments (a publication's posts); list_subscriptions (who you follow), get_inbox (new posts from them), get_feed (For You); fetch_notes, get_profile_feed (any author's Notes); catalog (a creator's full archive with SEO fields); search_topic (posts and Notes across all of Substack, by topic); get_publication (a publication's public profile); get_engagement (who engaged with YOUR publication); newsletters_search, newsletters_intersection, newsletters_analytics, newsletters_suggest_queries (130,000+ newsletter corpus); workflows_search, workflows_run (guided growth workflows: run the loaded workflow, do not print it).
get_inbox, get_feed, list_subscriptions and get_engagement need the QVN Chrome extension signed in on substack.com. Keep limit at 20 or less per call to avoid Substack 429s.
Call action help for parameters.
Tool call template
Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {
"action": "<action>"
},
"name": "substack_read"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| max | No | catalog only: cap the number of posts returned (newest first). Omit for the full catalog. | |
| days | No | get_engagement only: window in days (1-30, default 7). Always sent, so the MCP window does not inherit the HTTP route's narrower 2-day default — "who engaged with me" over 2 days is a near-empty answer. | |
| kind | No | search_topic only: "all" (default), "posts" or "notes". | |
| slug | No | get_article, get_comments: article slug (e.g. 'my-article-title') or numeric post ID (e.g. '184929446'). workflows_run: the workflow slug, e.g. "niche-sizer" (from workflows_search). | |
| sort | No | list_articles: 'new' (default), or 'top' — Substack's own composite ranking, NOT the same as sorting by the returned likes+comments+restacks. | |
| sync | No | get_engagement only: spawn a background refresh first. The response still returns the CURRENT cache — call again after ~2 min for the refreshed set and compare stale_hours. Nothing refreshes this cache on a schedule, so this is the only way to make it current. | |
| tier | No | newsletters_search: filter by tier (0=free, higher numbers=premium tiers). | |
| exact | No | newsletters_search: true = strict keyword matching only; false (default) = synonym-expanded semantic matching. | |
| fuzzy | No | newsletters_analytics / newsletters_intersection: DEFAULT true = match as free text over newsletter name/description/author (works for non-tag terms like "vibe coding"). Pass false for a strict curated-tag match. | |
| limit | No | Results per call. Max 50 for list_articles, search_articles, get_feed, fetch_notes, get_profile_feed; max 100 for newsletters_search and newsletters_intersection (checked per action, server side). get_feed is capped to 20 by the backend. Defaults: 12 (list_articles, search_articles), 20 (get_feed, fetch_notes, newsletters_*). Keep batches small: large loops can trigger Substack 429s. | |
| pages | No | get_inbox, get_feed, get_profile_feed: pages to fetch (~20 items per page). Default 1; use 3–5 for 48h coverage. Ignored by get_feed when min_date is set. | |
| query | No | Search keyword. Required for search_topic, search_articles and newsletters_search (e.g. "AI newsletters for founders"). Optional keyword filter for list_articles and workflows_search. | |
| action | Yes | The operation to perform. Current actions: list_articles, get_article, search_articles, get_comments, list_subscriptions, get_inbox, get_feed, fetch_notes, get_profile_feed, catalog, get_publication, search_topic, get_engagement, newsletters_search, newsletters_intersection, newsletters_analytics, newsletters_suggest_queries, workflows_search, workflows_run. Pass "help" for the live list with parameters; actions added after you connected appear there and work without reconnecting. | |
| cursor | No | search_topic only: next_cursor from the call before, for the next page. | |
| offset | No | list_articles: pagination offset. Default 0. | |
| keyword | No | newsletters_analytics: the single keyword to analyze (e.g. "productivity"). | |
| options | No | Extra parameters for an action whose params are not listed in this schema (see action "help"). Parameters that ARE listed in this schema must be passed at top level; here they are ignored. | |
| sort_by | No | newsletters_search: sort order. "relevance" (default), "subscribers", or "recent". | |
| category | No | workflows_search: optional category filter. All workflows are category "workflow"; unknown values are ignored. | |
| keywords | No | newsletters_intersection: 2–5 keywords. Returns newsletters matching ALL of them. | |
| min_date | No | get_feed only: ISO date (e.g. "2026-06-07"). Fetches pages until all items are older than this date; use instead of pages for time-window queries. | |
| subdomain | No | Substack subdomain (e.g. 'platformer', 'stratechery'). Required for list_articles, search_articles, catalog, get_publication. Optional for get_article and get_comments — auto-detected when passing a numeric post ID. | |
| since_date | No | catalog only: ISO date (e.g. "2026-01-01"). Returns only posts on/after this date. | |
| description | No | newsletters_suggest_queries: natural-language description of what you want to analyze. | |
| check_answered | No | get_engagement only: drop items already answered on Substack. | |
| substack_input | No | fetch_notes and get_profile_feed: Substack URL, @handle, or subdomain. Examples: 'jennyouyang', '@jennyouyang', 'https://jennyouyang.substack.com'. | |
| min_subscriber_count | No | newsletters_search: only newsletters with at least this many subscribers. |