Substack MCP Server
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| SUBSTACK_USER_ID | Yes | Your Substack user ID | |
| SUBSTACK_SESSION_TOKEN | Yes | Your Substack session token | |
| SUBSTACK_PUBLICATION_URL | Yes | Your Substack publication URL |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| create_draft_postC | create a draft post on your Substack account. |
| set_post_bodyA | replace the body of a draft with a Substack document. This is the only way to write structured content — headings, lists, links, code blocks, images, buttons and a paywall. Create the draft first with create_draft_post, then call this with its id. The result reports how many nodes of each type were stored, so a caller can confirm that what it asked for is there. An image must already be hosted by Substack: this cannot upload one. |
| upload_imageA | Host an image on your Substack publication and get back a Substack URL — the one thing image2.src in set_post_body and cover_image in update_draft will actually render. The source is either an http(s) URL, which the server downloads and re-hosts, or |
| list_subscribersA | List and filter the subscribers of your Substack publication. Supports the same 48 columns and operators as the Subscribers dashboard, combined with AND, plus free-text search, sorting and pagination. Returns |
| export_subscribersA | Export subscribers with their full column values, including the engagement metrics list_subscribers can filter on but not return: email opens over 7d/30d/6mo, unique emails seen, post views, unique posts seen, comments, shares, links clicked, days active and activity rating. Takes the same filters as list_subscribers and covers the whole matching set — there is no paging. Substack generates the file asynchronously, so this waits for it and returns the parsed records. Two columns cannot be exported and are reported in |
| list_postsA | List the posts of your Substack publication: drafts, published posts or scheduled posts. Supports free-text search, pagination and sort direction. Each post is returned as a summary; use get_draft for the full content of an unpublished one. |
| get_draftA | Read one draft post of your Substack publication in full, including its body and its audience and email settings. Take the id from list_posts or create_draft_post. |
| update_draftA | Change an existing draft's title, subtitle or any of its Post settings: audience, who may comment, comment order, cover image, social preview title and description, SEO title and description, and URL slug. The update is partial: only the fields you pass change, everything else — including the body — is left alone. A cover_image not already hosted by Substack is downloaded and re-hosted first. Take the id from list_posts or create_draft_post. |
| publish_draftA | Publish a draft. The post goes live on the web; |
| delete_draftA | Delete an unpublished draft. Refuses if the id belongs to a published post: Substack deletes both through the same endpoint, and removing a live post is irreversible, so that is left to the dashboard. |
| get_publicationA | Read the settings and identity of your Substack publication: name, subdomain, custom domain, hero text, copyright, sender name, logo, plans and payment state. Returns a projection by default; pass full: true for all 111 fields. |
| get_user_profileA | Read the account behind the session: id, handle, name, bio, and every publication you have a role on. This is how to discover which publications the session can reach, beyond the one SUBSTACK_PUBLICATION_URL points at. |
| list_publication_tagsA | List every tag defined on your Substack publication, with its name, slug and whether it is hidden. Tag ids are UUIDs, so this is how to find one — though add_tag_to_post takes a name and does not need it. |
| get_post_tagsA | List the tags on one post, by name. The underlying endpoint returns only UUIDs, so this resolves them against the publication's tag list — it is the only way to read back what add_tag_to_post did, since neither get_draft nor list_posts carries tags. |
| add_tag_to_postA | Add a tag to a post, by tag name, creating the tag on the publication if it does not exist yet. Works on drafts as well as published posts. Reports |
| get_post_commentsA | Read the comments on one of your posts, each with its author, text, reaction and reply counts, and its position in the thread. Comments withheld by Substack's automod are counted separately under automod_hidden_count rather than mixed in. |
| comment_on_postA | Post a public comment on one of your posts, as you. This is published under your name and this server offers no way to delete it. |
| list_subscriptionsA | List the Substack publications this account subscribes to, with the plan, membership state and whether emails are on. Excludes paused and expired subscriptions unless asked otherwise. This is what the account reads, not who reads it — for your own subscribers use list_subscribers. |
| list_reader_postsA | List recent posts from the publications this account subscribes to — the reader Inbox — with read state and reading progress. Each post is summarised; use get_reader_post to read one. |
| get_reader_postA | Read one post in full, from any publication — not just your own. Returns the body as HTML along with its author, stats and audience. This is the only way to read the text of someone else's post. |
| get_reader_feedA | Read the Substack Notes feed: Notes and posts surfaced to this account. Pick the feed with |
| get_profile_feedA | Read what one account has published — its Notes, its posts, or both. Defaults to your own account, so this is how to list the Notes you have written; pass user_id for anyone else. |
| get_comment_threadA | Read one Note or comment together with the replies beneath it, each with its author and its position in the thread. Take the id from get_reader_feed or get_profile_feed. |
| restack_itemA | Restack a Note to your own followers. This is public, appears on your profile, and cannot be undone from here — a restack has no id of its own, so there is nothing to delete. Notes only: restacking a post is not supported, because that endpoint 404s even on a valid post id. |
| get_publication_statsA | Read the headline stats of your Substack publication: total and recent subscribers, ARR, site views, and the 30-day email open rate. Takes no arguments. For anything deeper — retention, churn, growth sources, referrals — use get_analytics. |
| get_post_statsA | Rank the posts of your Substack publication by any of 43 per-post metrics. This is how to tell which post actually grew the list (signups, subscribes, free_to_paid_upgrades), which was worth most (estimated_value), which cost you subscribers (unsubscribes), and which people read to the end (subscribers_finished_post) — alongside delivery, opens, clicks, views and restacks. Covers the whole archive with paging. There is no date filter: the endpoint ignores one, so narrow by sorting and paging instead. |
| get_analyticsA | Read one publication-level analytics report, covering the dashboard's Stats tabs: cohort retention, unsubscribes and their reasons, growth sources, referrals, audience overlap with other Substacks, subscriber Notes, paid growth, and timeseries for subscribers, followers and ARR. For per-post numbers use get_post_stats instead. Pick a report with |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/marcomoauro/substack-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server