Substack MCP Server
This server is a self-hosted Substack API and MCP server (50 tools) that runs on your own machine using your Chrome session, letting AI agents or scripts manage a Substack publication and reader account.
Posts and drafts: list, read (full Markdown body), create drafts from Markdown, update, duplicate, and delete posts.
Publishing: publish now, schedule for a set time (web and email), cancel a schedule, and unpublish back to drafts.
Sections and post tags: list sections and post tags, create tags, and add or remove tags on posts.
Comments: list comments (optionally unanswered only), reply, pin, like, remove others' comments, and delete your own.
Notes: list Notes and their replies, publish a Note now or scheduled (optionally with a link card to a published post), and reply to Notes.
Subscribers: list (by plan, join date), add, remove, export to CSV, and manage private subscriber tags.
Stats and analytics: publication totals and revenue, daily stats, audience insights (countries, states, overlapping publications), traffic sources, and per-post stats, traffic, and engagement.
Recommendations: list recommendations given or received, and recommend or unrecommend another publication.
Reader, feed and messages: home feed (For you/Following), search all of Substack, notifications, unread counts, DM conversations, send messages, follow users, like posts, and list your subscriptions.
Access options: MCP over stdio or HTTP, a local REST API with OpenAPI docs, and a Python
call()interface with 14 example scripts.Safety: read-only mode (25 read tools), local-only binding by default, bearer-token auth for remote access, substack.com-only requests, and explicit guards against account settings or money-moving endpoints.
Provides tools for interacting with Substack's web endpoints using your own signed-in Chrome session: create posts and drafts from Markdown, publish and schedule them, post Notes, read and reply to comments, and manage subscribers. Also covers stats (subscriber growth, revenue, opens, referral sources), recommendations, and direct messages — 50 tools that can be used via MCP clients, a local REST API with OpenAPI docs, or Python scripts.
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 MCP Servercreate a draft post from this markdown and schedule it for tomorrow"
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 API and MCP server, self-hosted
A Substack API and a Substack MCP server you run on your own computer, in Python, on the session of your own Google Chrome. All 50 Substack tools we run in production at Cotlet: posts and drafts from Markdown, publishing and scheduling, Notes, comments, subscribers, stats, recommendations and direct messages.
Substack has no public API to write posts, publish Notes or manage subscribers, and no official MCP server. This repo gives you both:
MCP server for Claude Code, Claude Desktop, Cursor, Codex and any MCP client, over stdio or HTTP. Setup
REST API on
http://127.0.0.1:8787/api/v1/substack, with OpenAPI docs at/docs. SetupPython:
call("list_posts", status="draft"), plus 14 ready scripts inexamples/.
It is for technical people who want to run it themselves, for noncommercial use only (license). If you want it running 24/7 on a server, kept working when Substack changes its site, for a team or a business, use the hosted version at cotlet.dev.
uv tool install substack-api-mcp # or: pip install substack-api-mcp
substack-mcp connect # reads your Substack session from Chrome
substack-mcp call list_posts
claude mcp add substack -- uvx substack-api-mcp mcpContents
Related MCP server: substack-mcp-plus
How it works
AI agent (MCP) / script (REST, Python) ──▶ substack-mcp on your computer ──your Substack cookies──▶ substack.com
▲
substack-mcp connect ───────┘ reads them once from your Chrome (DevTools Protocol)You sign in to Substack in your own Chrome, the way you always do.
substack-mcp connectattaches to that Chrome through the Chrome DevTools Protocol, reads the substack.com cookies and saves them to~/.config/substack-api-mcp/session.json, readable by your user only. Substack signs in by an emailed code or link, so there is no password to see or store.Every tool call is a request to Substack's own web app endpoints (
substack.com/api/v1for the reader side,yourname.substack.com/api/v1for your publication's dashboard) with those cookies, sent with curl_cffi, which copies Chrome's TLS fingerprint. No headless browser runs.
Substack's session cookie (substack.sid) lasts about three months. When Substack signs you out, the server reads the cookies from Chrome again, if Chrome is open with remote debugging on.
Requirements
Python 3.11 or newer.
Google Chrome 144 or newer, signed in to Substack. Any Chrome or Chromium works with a debugging port.
macOS, Linux or Windows.
A Substack account. Publisher tools (posts, subscribers, stats, comments) work on the first publication your account runs as admin, owner, editor or contributor. Reader tools (feed, search, Notes, messages) work on any account.
Install
From PyPI:
uv tool install substack-api-mcp # or: pipx install substack-api-mcp, or: pip install substack-api-mcp
substack-mcp --versionMCP clients can also run it with no install: uvx substack-api-mcp mcp.
From source:
git clone https://github.com/cotletdev/substack-api-mcp-server.git
cd substack-api-mcp-server
python3 -m venv .venv
. .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
substack-mcp --versionWith uv: uv venv && uv pip install -e ., then uv run substack-mcp ....
Setting it up with an AI agent (Claude Code, Codex, Cursor)? Open it in this folder and ask it to set up the repo: AGENTS.md tells it every step, and it asks you only for the steps in Chrome.
To update: uv tool upgrade substack-api-mcp (or pip install -U substack-api-mcp), from source git pull && pip install -e .. We copy every change of the hosted Substack tools into this repo.
Connect your Chrome
Option A: your everyday Chrome (recommended)
Open
chrome://inspect/#remote-debuggingin Chrome and switch remote debugging on. Chrome then accepts DevTools connections from programs on this computer, and asks you before each one.Make sure you are signed in at substack.com.
Run:
substack-mcp connectChrome asks whether to allow the connection. Click Allow.
Saved 19 Substack cookies to /Users/you/.config/substack-api-mcp/session.json
Signed in to Substack as Maya Chen (@mayachen)You can switch remote debugging off again afterwards. Leave it on if you want the server to pick up a new session by itself after Substack signs you out.
connect looks for Chrome's DevToolsActivePort file in the default profile folder. For Chrome Beta, Canary or a custom profile folder, pass --profile-dir "<folder>".
Option B: a Chrome with a debugging port
Chrome does not open a debugging port on your default profile, so start a separate one, sign in to Substack there once, and connect to it:
# macOS
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir="$HOME/.chrome-substack"
# Linux
google-chrome --remote-debugging-port=9222 --user-data-dir="$HOME/.chrome-substack"
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="%USERPROFILE%\.chrome-substack"
substack-mcp connect --cdp http://127.0.0.1:9222--cdp also takes a ws:// DevTools URL, for example of a Chrome on another machine reached over an SSH tunnel.
Option C: paste the cookie by hand
For a server with no Chrome: in Chrome open DevTools on substack.com, Application > Cookies > https://substack.com, copy the value of substack.sid, then:
substack-mcp connect --token # paste it, input is hidden
# or, without a session file:
export SUBSTACK_AUTH_TOKEN=...A pasted token is not refreshed on its own. Paste a new one when Substack signs you out.
Check the session at any time:
substack-mcp statusMCP server
The MCP server lists every tool with its input schema, a description written for agents, and hints: read tools are marked read-only, and tools that publish, message or delete are marked so your client asks before running them.
Claude Code
claude mcp add substack -- uvx substack-api-mcp mcp
# read only:
claude mcp add substack -- uvx substack-api-mcp mcp --read-onlyClaude Desktop
~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"substack": {
"command": "uvx",
"args": ["substack-api-mcp", "mcp"]
}
}
}Cursor
~/.cursor/mcp.json, the same block as Claude Desktop. A ready copy is in mcp.json.
Codex
~/.codex/config.toml:
[mcp_servers.substack]
command = "uvx"
args = ["substack-api-mcp", "mcp"]Over HTTP
substack-mcp serve also serves MCP over streamable HTTP at http://127.0.0.1:8787/mcp, for clients that take a URL:
substack-mcp serve
claude mcp add --transport http substack http://127.0.0.1:8787/mcpThen ask your agent things like:
Turn essay.md into a draft for everyone and schedule it for Tuesday 8:00 New York time. Once it is out, post a Note with a link card to it.
Find comments on my last three posts that I have not answered and draft a short reply to each.
Last week's numbers: new and paid subscribers, cancellations, revenue, and opens for each post.
Where did my readers come from in the last 30 days?
REST API
substack-mcp serve # http://127.0.0.1:8787, MCP at /mcp, docs at /docsEach tool has its own route under /api/v1/substack, the same paths as the hosted API at cotlet.dev, so code written against one works with the other. Path parts and the query string are arguments, and a JSON body adds the rest.
curl 'http://127.0.0.1:8787/api/v1/substack/posts?status=scheduled'
curl 'http://127.0.0.1:8787/api/v1/substack/stats?period=30d'
curl -X POST http://127.0.0.1:8787/api/v1/substack/drafts \
-H 'Content-Type: application/json' \
-d '{"title": "Notes on pricing", "body_markdown": "## Why I raised prices\n\nThree reasons..."}'Any tool by name, body as its arguments:
curl -X POST http://127.0.0.1:8787/api/v1/substack/tools/list_comments -d '{"post_id": "148213977"}'GET /api/v1/substack/tools: every tool with its route, input schema and an example answer.GET /docs: interactive OpenAPI docs,GET /openapi.jsonthe schema, for n8n, Postman or a generated client.Answers are JSON. Lists return
next_cursor; pass it back ascursorfor the next page.
The server listens on 127.0.0.1 only. To reach it from another device of yours, set a token, and every request then needs Authorization: Bearer <token>:
SUBSTACK_MCP_TOKEN=$(openssl rand -hex 24) substack-mcp serve --host 0.0.0.0Python and the example scripts
Straight from Python, no server needed:
from substack_api_mcp import call
from substack_api_mcp.scripting import paginate, write_rows
posts = list(paginate("list_posts", {"status": "published"}, "posts"))
write_rows(posts, "posts.csv")
draft = call("create_draft", title="Notes on pricing", body_markdown="Three reasons...")
call("schedule_post", post_id=draft["post_id"], publish_at="2026-11-03T08:00:00-05:00")Or one tool from the shell: substack-mcp call get_post_stats post_id=148213977, or with a JSON object.
Ready scripts in examples/. Each prints JSON, takes --out file.csv or --out file.json where it makes sense, and --help:
Script | What it does |
A | |
Schedules a draft for a set time, or | |
A Note now or at a set time, | |
Published, draft or scheduled posts: title, audience, dates, URL. | |
One post saved as a Markdown file. | |
New and paid subscribers, cancellations, revenue, and each new post's opens and new subscribers. | |
Opens, open rate, views, likes, restacks and new subscribers for your last N posts. | |
Subscribers, paid subscribers, followers and views day by day. | |
Where your visitors came from, most views first. | |
Comments on your last N posts that you have not replied to. | |
A reply under one comment. | |
Subscribers by plan or join date, with activity rating. | |
The full list as the CSV that Export gives in the dashboard. | |
Adds emails from a text or CSV file as free subscribers, after asking you. |
python examples/draft_from_markdown.py essay.md --publish-at 2026-11-03T08:00:00-05:00
python examples/unanswered_comments.py --last 3 --out todo.csvOn a schedule, cron on your own computer works while it is on: 0 8 * * 1 cd ~/substack-api-mcp-server && .venv/bin/python examples/weekly_report.py.
All 50 tools
post_id comes from list_posts, comment_id from list_comments. substack-mcp tools prints this list, substack-mcp tools --json adds the input schemas.
Posts and drafts
Tool | Access | REST route | What it does |
| read |
| Posts of your publication, newest first, with status and audience. |
| read |
| Full post: title, subtitle, body as Markdown, audience, URL and dates. |
| write |
| New draft from Markdown. Nothing is sent until you publish or schedule it. |
| write |
| Change the title, subtitle, body or audience of a draft. |
| write |
| Copy any post into a new draft. |
| write |
| Delete a draft, scheduled or published post, with its comments. |
Publishing
Tool | Access | REST route | What it does |
| write |
| Publish a draft now. |
| write |
| Publish a draft at a set time, on the web and by email. |
| write |
| Stop a scheduled post from going out; it stays as a draft. |
| write |
| Take a published post off the web and back to drafts. |
Sections and post tags
Tool | Access | REST route | What it does |
| read |
| Sections of your publication, the separate newsletters inside it. |
| read |
| Tags your publication uses to group posts. |
| write |
| New tag for grouping your posts. |
| write |
| Add a tag to a post, or take it off. |
Comments
Tool | Access | REST route | What it does |
| read |
| Comments on a post, with author, text and whether you replied. |
| write |
| Reply as you under a comment on your post. |
| write |
| Pin a comment to the top of your post's comments, or unpin it. |
| write |
| Like or unlike a comment or a Note as you. |
| write |
| Remove someone's comment from your post as the publication's moderator. |
| write |
| Delete one of your own comments, Notes or Note replies. |
Notes
Tool | Access | REST route | What it does |
| read |
| Notes posted by you or any other Substack user, newest first, with likes and replies. |
| read |
| Replies under a Note, with author, text and likes. |
| write |
| Short post in Substack Notes, now or at a set time, optionally with a link card to one of your posts. |
| write |
| Reply as you under any Note or Note reply. |
Subscribers
Tool | Access | REST route | What it does |
| read |
| Subscribers with plan, start date and activity rating. |
| write |
| Add one email to your list as a free subscriber. |
| write |
| Remove one email from your subscriber list. |
| read |
| The full subscriber list as a CSV download link, with the row count. |
| read |
| Tags you use to group subscribers. |
| write |
| New private tag for grouping subscribers. |
| write |
| Put a tag on subscribers by email, or take it off. |
Stats
Tool | Access | REST route | What it does |
| read |
| Total and paid subscribers, new subscribers, paid cancellations and estimated revenue for a period. |
| read |
| Day by day: total and paid subscribers, followers and views. |
| read |
| Where your subscribers live, and which publications share your readers. |
| read |
| Where your publication's visitors came from in a period, most views first. |
| read |
| Recipients, opens, open rate, views, likes, restacks and subscribers gained. |
| read |
| Where a post's readers came from: sources, categories and devices. |
| read |
| Who liked and commented on a post, and the subscribers it won and lost. |
Recommendations
Tool | Access | REST route | What it does |
| read |
| Publications you recommend, or that recommend you, with the subscribers each sent. |
| write |
| Recommend another publication to your readers, or stop recommending it. |
Reader, feed and messages
Tool | Access | REST route | What it does |
| read |
| Your Substack home feed: posts and Notes, For you or Following. |
| read |
| Search all of Substack for people, posts and Notes. |
| read |
| Your Substack notifications: replies, likes, new followers, restacks, newest first. |
| read |
| How many unread direct messages, message requests and activity notifications you have. |
| read |
| Your direct-message conversations, latest first, with the last message. |
| read |
| The latest messages of one direct-message conversation, oldest first. |
| write |
| Send a direct message on Substack, in a conversation or to a person. |
| write |
| Follow or unfollow a Substack user, so their Notes reach your feed. |
| write |
| Like or unlike any Substack post as you. |
| read |
| Publications you subscribe to, with your plan and whether their emails reach you. |
Never built, on purpose: your Substack sign-in, email, profile and account settings, your publication's address or ownership, and anything that moves money (paid plans, payouts, comps). Every request passes a guard that refuses writes to those Substack paths.
Configuration
Variable | Default | What it does |
|
| Folder of |
| Substack | |
| Proxy for every request to Substack, e.g. | |
|
| |
| Bearer token required by | |
|
| Address of |
Security and your Substack account
No password anywhere. Substack signs in by an emailed code. Only cookies are read, and only those of substack.com.
The session file is yours.
session.jsonis created with mode 0600. Anyone who has it can act as you on Substack, so keep it out of git and shared folders.Local by default.
servebinds to127.0.0.1and refuses another address withoutSUBSTACK_MCP_TOKEN.substack.com only. Requests and redirects outside substack.com and its subdomains are refused.
Read-only mode.
--read-onlyorSUBSTACK_MCP_READ_ONLY=1exposes the 25 read tools only.Actions reach real people. Published and scheduled posts are emailed to your subscribers, and Notes, comments, replies and DMs go out under your name. MCP clients ask before running them; a script does not, so try it on a test publication first.
Add only people who asked.
add_subscribersends Substack's welcome email. Importing people who did not sign up breaks Substack's rules.
Errors
The REST API answers {"error": "<code>", "message": "..."}. The MCP server returns the same code and message as a tool error.
Status | Code | What to do |
401 |
| No session, Substack signed you out, or it asks you to sign in again before a sensitive action (subscriber lists). Sign out and in at substack.com in Chrome, then run |
403 |
| Your role in the publication cannot do this. |
403 |
| The server runs read-only, or the call would change your account settings. |
403 |
| Substack refused the request or showed a bot check. Open substack.com in Chrome once, then retry. |
409 |
| Substack asks for a CAPTCHA. Solve it in Chrome. |
422 |
| An argument is missing or wrong; the message names it. |
429 |
| Substack is limiting the account. Wait a few minutes. |
502 |
| Substack answered with an error, or changed its site. |
Self-hosted or hosted
This repo | ||
Tools | the same 50 | the same 50 |
Runs | on your computer, while it is on | in the cloud, 24/7 |
Substack session | your Chrome, cookies in a local file | your own Cloud Browser in the EU, profile encrypted with AES-256-GCM |
When Substack changes its site |
| fixed for you, every tool tested daily |
Approvals | your MCP client asks per call | posts, Notes, replies and DMs wait for your OK, switchable per tool |
Works with | MCP clients on your machine, local scripts | Claude.ai and ChatGPT connectors, n8n, Make, Zapier, any HTTP client |
Who may use it | you, for noncommercial use | teams, businesses, agencies |
Price | free | free 7-day trial with 2,000 credits, no card; then one-time packs from $29 for 5,000 credits |
On the hosted version a successful call uses 20 to 30 credits (25 for most tools), failed calls are free, and the Cloud Browser uses 50 credits a day while it has an app enabled for agents. Full pricing.
FAQ
Does Substack have an official API? Only a limited one (checked 11 Oct 2026). Its Developer API looks up public creator profiles after approval, and there is no public API to write posts or Notes, manage subscribers or send email. RSS reads public posts only. Details and sources: cotlet.dev/integrations/substack-api-mcp-server.
Is there a Substack MCP server for Claude, ChatGPT or Cursor?
Yes, this one runs on your machine: substack-mcp mcp for Claude Code, Claude Desktop, Cursor and Codex. ChatGPT and Claude.ai connectors need a public HTTPS URL, which the hosted Substack MCP server gives you.
Can I schedule Substack posts from Markdown?
Yes: python examples/draft_from_markdown.py essay.md --publish-at 2026-11-03T08:00:00-05:00. The Substack editor does not import Markdown. The script sends the file as a draft with its headings, bold text, links, lists and code blocks, then schedules it. Images have to be public URLs.
Can it schedule Notes as well as posts?
Yes. publish_note takes a publish_at time and the Note waits in your scheduled Notes until then. A link card needs a published post.
Can I export my Substack subscribers to CSV?
Yes: python examples/export_subscribers.py --out subscribers.csv gives the same CSV as Export in the subscriber dashboard. list_subscribers.py --plan paid or --since 2026-10-01 gives a filtered list with plan, join date and activity rating.
Can I export my posts as Markdown?
Yes, one at a time with examples/get_post.py --post-id <id> --out post.md, including the paywalled part and drafts of your own publication. list_posts.py gives the IDs.
Is this a Substack scraper? It does what people want a scraper for (export posts, subscribers and stats) but does not parse HTML in a headless browser. It calls the same JSON endpoints the Substack web app calls, in your own account and publication.
Why does it need my Chrome? To read your Substack session. Substack signs in by an emailed code, so there is no password to give it anyway. Chrome is used once per sign-in, not for each call.
What happens when Substack signs me out?
Calls fail with auth_expired. With Chrome remote debugging on, the server reads the new cookies on the next call (click Allow when Chrome asks); otherwise run substack-mcp connect again. Subscriber lists sometimes ask for a fresh sign-in even with a valid session: sign out and in again at substack.com, then connect.
Does it need a paid Substack plan? No. Revenue, paid subscribers and cancellations exist only for publications with paid subscriptions.
Can it email all my subscribers? Only by publishing or scheduling a post, the way the editor sends it. Substack emails a post once; edits after the send show on the web and in the app.
Can it run on a VPS or in Docker?
Technically yes, with SUBSTACK_AUTH_TOKEN. Substack then sees your session from a datacenter IP, which looks less like you. For an always-on setup the hosted version keeps your session in your own Cloud Browser on a fixed IP.
Will my Substack account get banned? Requests carry Chrome's fingerprint and go out one at a time, as you would click. Nobody can promise a platform never acts. Keep to your normal use and do not add or message people in bulk.
Can I use it at work or for my clients? No, the license allows noncommercial use only. For a team, a company or client work, use Cotlet or write to contact@cotlet.dev.
Is it open source? The source is public, the license is not an open source license: noncommercial use only, no business use.
A tool broke or I need another one. Open an issue with the tool name and the error message.
License
PolyForm Noncommercial License 1.0.0. In short:
Allowed: noncommercial use: you, for your own personal purposes with your own Substack account, or a charity, school, public research or government body. Changing the code, and sharing it under the same license.
Not allowed: any commercial use, your own business included; client work; selling or offering it, or a service built on it.
Earlier versions of this repo (the scripts for the hosted API, up to commit 4399e88) stay MIT.
Maintained by Cotlet (@cotletdev). Substack is a trademark of its owner. This project is unofficial and not affiliated with, endorsed or sponsored by Substack.
Available Tools
50 toolsadd_subscriberAdd subscriberADestructiveInspect
Add one email to your list as a free subscriber.
Adds one email as a free subscriber, the same as Add subscribers in the dashboard, and Substack sends its usual welcome email. Substack adds the email in the background, so list_subscribers may show it a minute later. Add only people who agreed to hear from you.
| Name | Required | Description | Default |
|---|---|---|---|
| Yes | Subscriber email. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the mutation and open-world nature. The description adds useful behavioral context beyond annotations: Substack sends a welcome email, processing happens in the background, and list_subscribers may lag by a minute. It does not fully explain why destructiveHint is true or whether the add can be undone, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The important information is front-loaded and the description is appropriately short for a one-parameter tool. However, the first two sentences are partially redundant, both restating that one email is added as a free subscriber.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter tool with no output schema, the description covers the key operational facts: external welcome email, asynchronous visibility, dashboard equivalence, and consent requirement. There are no major gaps that would prevent correct use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the sole email parameter is already documented in the schema. The description reinforces that one email is added but does not add format or validation details beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: it adds one email as a free subscriber. It also distinguishes the scope from bulk/dashboard behavior and references the sibling list_subscribers for delayed visibility.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides clear usage context: this is the one-email add path, equivalent to Add subscribers in the dashboard, and should be used only for people who consented. It does not explicitly name alternatives for bulk adds, but it gives enough scenario guidance for correct invocation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
cancel_scheduled_postCancel scheduled postADestructiveInspect
Stop a scheduled post from going out; it stays as a draft.
Removes the scheduled time from a post, so nothing is published or emailed then; the post stays a draft with its content. Schedule it again with schedule_post. A post with no schedule returns an error.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | Post ID from list_posts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true, but the description usefully scopes that destruction: only the scheduled time is removed, content is preserved as a draft. The error-for-unscheduled-post line also effectively discloses the non-idempotent behavior implied by idempotentHint=false. It stops short of saying whether an already-published post can be passed in.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The lead sentence front-loads the action and the key outcome, and the remaining clauses each contribute (re-schedule path, error case). The draft-state outcome is stated twice in slightly different words, a minor redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter tool with annotations already covering the safety profile and no output schema, the description covers the action, the resulting state, the error condition, and the recovery path. Nothing an agent needs in order to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter with 100% schema description coverage ('Post ID from list_posts.'), so the schema already carries the semantics. The description adds no additional meaning about post_id beyond what the schema states, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Stop a scheduled post') plus the resulting state ('it stays as a draft'), which cleanly separates it from sibling mutations like delete_post, unpublish_post, and schedule_post. An agent can pick this without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the follow-up alternative explicitly ('Schedule it again with schedule_post') and gives a precondition ('A post with no schedule returns an error'). It doesn't explicitly contrast against delete_post or unpublish_post, which are the closest confusable siblings, so it stops short of a full when-not-to-use statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_draftCreate draftAInspect
New draft from Markdown. Nothing is sent until you publish or schedule it.
Creates a draft in your publication and returns its post_id and editor link. Markdown covers headings, paragraphs, bullet and numbered lists, quotes, code blocks, rules, images by public URL, bold, italic, strikethrough, inline code and links; local image files cannot be used. Sending is a separate step: schedule_post or publish_post. A draft reaches no one, so it runs without asking.
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Post title. | |
| audience | No | everyone, only_paid or founding. Default: everyone. | |
| subtitle | No | Shown under the title and in the email preview. | |
| body_markdown | Yes | Post body in Markdown. Images by public URL. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes beyond the annotations (readOnlyHint=false, destructiveHint=false, idempotentHint=false) by explaining side-effect scope: a draft is inert, nothing is sent, and the call is safe to run without confirmation. It also discloses the return payload (post_id and editor link) and an input restriction (local image files cannot be used). What it doesn't cover is whether the draft is visible to anyone in the publication dashboard or whether repeated calls create duplicates — although idempotentHint=false already hints at the latter.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the two facts that matter most (what it makes, and that nothing is sent yet), then the Markdown capability list. The Markdown enumeration is long but each item constrains what the caller can legitimately submit, so it earns its space; a tighter version could group the inline-formatting items.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-parameter creation tool with no output schema, the description covers purpose, side effects, the follow-up tools, the return values, and the content-format constraints. There is nothing an agent needs in order to call this correctly that is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so title, subtitle, audience and body_markdown are already documented, making 3 the baseline. The description adds real meaning for body_markdown by enumerating the supported Markdown subset (headings, lists, quotes, code blocks, images by public URL, inline formatting) and, importantly, the exclusion of local image files — a constraint an agent would otherwise get wrong.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb and resource ("New draft from Markdown") and immediately bounds its scope ("Nothing is sent until you publish or schedule it"). It names the sibling actions (schedule_post, publish_post) that do the sending, so an agent can distinguish this creation step from the publication steps without reading any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the when: build content now, nothing is delivered. Explicitly names alternatives: schedule_post or publish_post for sending. It even gives a decision rule ("A draft reaches no one, so it runs without asking"), which is exactly the guidance an agent needs before invoking.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_post_tagCreate post tagAInspect
New tag for grouping your posts.
Creates a post tag on your publication; Substack makes the slug from the name. A tag with no posts shows nowhere. Put posts under it with tag_post.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Tag name, e.g. Habits. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the write, non-idempotent, non-destructive profile, and the description adds real value on top: the slug is derived server-side from the name, and an empty tag is invisible in the product. It stops short of warning that repeating the call with the same name will likely create a duplicate despite the non-idempotent hint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the action and followed by consequences and next steps; every sentence carries information. The opening fragment 'New tag for grouping your posts' slightly restates the title and could be merged, keeping it just under 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter creation tool with no output schema, the description covers the action, the slug side effect, the visibility consequence, and the follow-up tool. It leaves open what the call returns and how duplicate names behave, which are the only remaining gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds meaning beyond the schema by explaining that the supplied name is transformed into a slug rather than used verbatim. That materially affects what the agent should pass.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Creates a post tag on your publication') and scopes it to posts, which distinguishes it from create_subscriber_tag and tag_subscribers in the sibling list. An agent can tell it apart without touching the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The sentence 'Put posts under it with tag_post' gives the natural follow-up call, which is genuinely useful routing. However it never says when to create a new tag versus reusing one (list_post_tags), nor what happens if the name already exists, so selection guidance is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_subscriber_tagCreate subscriber tagAInspect
New private tag for grouping subscribers.
Creates a subscriber tag on your publication. Tags are private: subscribers never see them. Put subscribers under it with tag_subscribers.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Tag name, e.g. Early readers. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this is a non-read-only, non-destructive, non-idempotent, open-world write. The description adds genuinely non-structured context that subscribers never see the tags, which matters for how an agent reasons about the effect of the call. It stops short of saying what happens when a tag with the same name already exists (relevant given idempotentHint=false).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the identity of the resource, followed by the privacy caveat and next step. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter creation tool with full annotations, the description covers purpose, privacy semantics, and the natural next call. The only gap is return behavior (no output schema exists), leaving the agent unsure whether a tag ID is returned.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required parameter with 100% schema description coverage, so the schema already carries the semantics. The description adds nothing about the name parameter beyond the schema's own example ('Early readers'), so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'Creates a subscriber tag on your publication,' with the added scope that the tag only groups subscribers. This implicitly separates it from create_post_tag, but it never names the sibling, so the differentiation is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear follow-up context: build the group with 'tag_subscribers' after creating the tag, which points to a specific sibling. It does not state exclusions or when a different tagging tool (e.g. create_post_tag) would be the right choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_commentDelete comment or NoteADestructiveInspect
Delete one of your own comments, Notes or Note replies.
Deletes something you wrote: a comment under a post, a Note or a reply to a Note. Replies other people wrote under it stay, under a deleted placeholder. Someone else's comment returns an error; on your own posts remove it with remove_comment.
| Name | Required | Description | Default |
|---|---|---|---|
| comment_id | Yes | ID of your comment, Note or Note reply. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and idempotentHint=false, so the description doesn't need to restate permanence. Instead it adds genuinely new behavior: other people's replies survive under a deleted placeholder, and deleting another user's comment fails with an error. That post-deletion state and failure mode are unavailable anywhere in the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and short overall. The middle sentence ('Deletes something you wrote: a comment under a post, a Note or a reply to a Note') largely re-enumerates what sentence one already listed, a small redundancy that keeps it out of the top band.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter destructive delete with annotations covering the safety profile and no output schema, the description supplies everything an agent needs: ownership precondition, error case, child-object outcome, and the sibling to use instead.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a single well-described comment_id, so the schema carries the load. The description adds only the ownership constraint ('your own'), which is a marginal but real addition above the schema's neutral 'ID of your comment'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Delete) plus the exact resource set — comment, Note, Note reply — and scopes it to 'your own'. An agent can immediately tell this apart from remove_comment, which is named explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use (things you wrote), when-not (someone else's comment returns an error), and the alternative (use remove_comment on your own posts). This is the full routing pattern with no inference required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_postDelete postADestructiveInspect
Delete a draft, scheduled or published post, with its comments.
Deletes one post of your publication for good: a draft, a scheduled post (its send is cancelled) or a published post, which leaves the web, the archive and the app with its comments and stats. Emails already sent stay in inboxes. Substack has no undo; unpublish_post keeps the post as a draft instead.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | Post ID from list_posts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=false, but the description adds substantial context: comments and stats are removed, the post leaves the web, archive, and app, already-sent emails remain in inboxes, and Substack offers no undo. This is exactly the behavioral detail an agent needs before invoking a destructive tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The destructive scope and irreversible consequence are front-loaded, and the unpublish_post alternative arrives before the reader has to infer it. Slight redundancy between the opening sentence and the second paragraph's enumeration of draft/scheduled/published posts keeps it from being maximally tight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter destructive tool with full schema coverage, no output schema, and strong annotations, the description supplies everything an agent needs: what is deleted, what is preserved, what cannot be undone, and which sibling to use instead. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is only one parameter, post_id, and schema description coverage is 100%, with the schema itself explaining that the ID comes from list_posts. The description adds no parameter-specific syntax or format guidance, so the baseline of 3 is appropriate when the schema carries the full burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (delete a post) and enumerates the exact scopes it covers: draft, scheduled, or published. It explicitly contrasts with the sibling tool unpublish_post, so the agent can distinguish it without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use guidance across draft, scheduled, and published posts, and names unpublish_post as the non-destructive alternative that keeps the post as a draft. It also states that scheduled sends are cancelled, which removes ambiguity about side effects.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
duplicate_postDuplicate postAInspect
Copy any post into a new draft.
Makes a new draft with the title, subtitle, body and settings of a draft or published post, as Duplicate in the post list does. Substack puts [COPY] in front of the title; change it with update_draft. Nothing is published or sent.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | Post ID from list_posts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=false, destructiveHint=false, openWorldHint=true), and the description adds two pieces of context annotations cannot express: the resulting title gets a '[COPY]' prefix, and 'Nothing is published or sent' scoping the operation to drafts only. It doesn't state that repeated calls create multiple drafts (relevant since idempotentHint=false), which would have completed the picture.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, each doing distinct work: what it copies, the title side effect, and the reassurance about publishing. The core action is front-loaded with zero filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter tool with full schema coverage and existing annotations, the description covers the mutation's behavior, its visible side effect, and the natural next step. The one gap is that with no output schema it never says what comes back (presumably the new draft's ID), which an agent needs to chain into update_draft.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter is documented as 'Post ID from list_posts', which already tells the agent where to source it. The description adds no format, constraint, or behavior detail about post_id beyond that, so this sits at the documented baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Copy any post into a new draft') and immediately enumerates what is carried over: title, subtitle, body and settings. This clearly separates it from create_draft (blank draft) and update_draft (edits an existing draft).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear usage context ('as Duplicate in the post list does') and points to update_draft for the follow-up rename, which is genuinely actionable routing. It does not explicitly contrast with create_draft when the agent wants a fresh post, so it falls just short of full when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_subscribersExport subscribersARead-onlyIdempotentInspect
The full subscriber list as a CSV download link, with the row count.
Builds the same CSV as Export in the subscriber dashboard: email, name, subscription type, activity rating and start date. Substack builds the file in the background; the call waits up to about a minute and otherwise asks you to try again later. The link needs no sign-in and works until expires_at, 24 hours when we recorded it. For filtered pages use list_subscribers.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say read-only/idempotent/open-world; the description adds the operationally important facts: the file is built asynchronously, the call blocks for roughly a minute, the link requires no authentication, and it expires at expires_at (24 hours when observed). These are exactly the traits an agent cannot infer from annotations or an empty schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the return value and CSV contents, then the async/expiry caveats and the alternative. Mostly earns its space, though the hedge '24 hours when we recorded it' slightly muddies an otherwise precise expiry statement.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description fully covers the return (link plus row count, column list, expiry) and the async failure mode. An agent has everything needed to call it and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so the baseline is 4. The description usefully clarifies that the export is unfiltered and that filtering belongs to a different tool, which compensates for an empty schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (export the full subscriber list) plus the return shape — CSV download link with row count. Explicitly contrasts with the dashboard 'Export' equivalent and with list_subscribers, so an agent can tell it apart from the filtered-listing sibling instantly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative tool and the condition that selects it: 'For filtered pages use list_subscribers.' It also tells the agent what to do on the failure path — retry later if the background build takes more than about a minute.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
follow_userFollow userAIdempotentInspect
Follow or unfollow a Substack user, so their Notes reach your feed.
Follows a person on Substack, as Follow on their profile does, or unfollows them. Following is not subscribing: you get their Notes and activity in the app, not their newsletter by email. They see the follow.
| Name | Required | Description | Default |
|---|---|---|---|
| user | Yes | Handle (e.g. @mayachen) or user ID. | |
| unfollow | No | Unfollow instead. Default: false. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, openWorldHint=true, idempotentHint=true and destructiveHint=false, so the safety profile is covered. The description adds genuinely non-structured context: this is a public social action ('They see the follow') and that the tool is bidirectional via the unfollow flag rather than being a separate endpoint. It does not mention auth or rate limits, but nothing important is contradicted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and effect, and kept to three short sentences. There is mild redundancy between 'Follow or unfollow' in sentence one and 'or unfollows them' in sentence two, which repeats rather than adds.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter, non-destructive, idempotent action with a fully documented schema and no output schema, the description covers purpose, effect on the caller's feed, and the distinction from email subscription. Only edge behavior (e.g., already-following) is left implicit, which the idempotentHint already implies.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% — the schema already documents 'user' as a handle or user ID and 'unfollow' as a boolean defaulting to false. The description reinforces that unfollowing is the same operation in reverse, but adds no format, lookup, or error semantics beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb+resource ('Follow or unfollow a Substack user') and states the effect ('so their Notes reach your feed'). It also distinguishes the action from the nearest conceptual sibling — subscribing — which an agent would otherwise confuse with add_subscriber.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the condition for use (get their Notes and activity in the app) and explicitly excludes the adjacent alternative: 'Following is not subscribing: you get their Notes and activity in the app, not their newsletter by email.' The relation to the Follow button on a profile gives an agent a concrete mental model.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_audience_insightsGet audience insightsARead-onlyIdempotentInspect
Where your subscribers live, and which publications share your readers.
Returns Analytics > Statistics > Audience: subscriber counts per country (region world, ISO codes such as us, gb) or per US state (region usa, codes such as ny, ca), all subscribers or paid only, the number of countries and states with any subscriber, and the publications whose readers overlap most with yours. Substack computes these in the background; a new publication has empty lists for a while.
| Name | Required | Description | Default |
|---|---|---|---|
| region | No | world (by country) or usa (by state). Default: world. | |
| paid_only | No | Count paid subscribers only. Default: false. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the safety profile is covered. The description adds genuinely non-obvious behavior beyond that: the statistics are precomputed asynchronously, so results can be stale or empty on new publications.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence and the second sentence carries only substantive detail (dimensions, enums, caveat). The list-heavy second sentence is dense but every element maps to an actual output field, so little is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing return values, and it does: per-country/state counts, totals of countries and states with subscribers, and overlapping publications. Combined with the async caveat, an agent has enough to call and interpret it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds value by giving concrete ISO examples (us, gb) and state codes (ny, ca) and by framing paid_only as 'all subscribers or paid only' rather than merely restating the flag. It stops short of explaining how the counts are aggregated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names the resource and the two distinct outputs (subscriber geography and overlapping publications), and the second sentence pins down the exact surface: 'Returns Analytics > Statistics > Audience'. An agent can distinguish this from list_subscribers or get_publication_stats from the text alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It establishes the context in which the tool makes sense (audience geography / reader overlap) and closes with a caveat that effectively says when not to bother: a new publication has empty lists while Substack computes in the background. It does not, however, name alternative sibling tools for related questions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_conversationGet conversationARead-onlyIdempotentInspect
The latest messages of one direct-message conversation, oldest first.
Returns who is in the conversation and its latest messages as the chat window first shows them, oldest first, with sender, text and time. Opening a conversation this way marks nothing read.
| Name | Required | Description | Default |
|---|---|---|---|
| conversation_id | Yes | Conversation ID from list_conversations. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this a safe, idempotent read, and the description adds a genuinely non-obvious behavioral fact: 'Opening a conversation this way marks nothing read.' It also characterizes the response contents (participants, latest messages with sender, text and time, in chat-window order), which annotations alone cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, return semantics first, then the read-state caveat. 'Oldest first' appears in both sentences, a minor redundancy that keeps it just short of a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does the work of explaining the return payload and ordering, and it covers the one subtle side effect. It omits how many messages 'latest' means and whether more can be paged, a small gap for a tool that returns a windowed message list.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single conversation_id parameter is documented there, including a pointer to list_conversations. The description adds no further parameter meaning such as ID format or behavior when the ID is unknown, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: 'The latest messages of one direct-message conversation, oldest first.' That is enough to distinguish it from list_conversations, which enumerates conversations rather than fetching one conversation's messages, though the description never names that sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the noun phrase 'one direct-message conversation' and by the pointer to list_conversations in the schema, but the description itself gives no explicit when-to-use guidance and no alternatives or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_daily_statsGet daily statsARead-onlyIdempotentInspect
Day by day: total and paid subscribers, followers and views.
Returns one row per day of the period, as the charts on the dashboard home and in Audience: total subscribers, paid subscribers and followers at the end of the day, and the day's views across your site and the app. Days Substack has no number for are null; a young publication starts on the day it was made.
| Name | Required | Description | Default |
|---|---|---|---|
| period | No | Default: 30d. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior, and the description adds useful data semantics beyond that. It explains one-row-per-day output, what each row represents, null handling for missing days, and the start date for young publications.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and remains efficient. The second sentence repeats the metric list somewhat, but overall it is appropriately sized and easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read-only stats tool with no output schema, the description gives enough return-shape context: row granularity, included metrics, null behavior, and publication start handling. It could be stronger only by clarifying how it relates to sibling stats tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter, period, is fully documented in the schema with an enum and default. The description references the period but adds no extra meaning beyond the schema, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific resource and granularity: daily rows containing total subscribers, paid subscribers, followers, and views. It is understandable without opening the schema, but it does not explicitly distinguish this tool from neighboring stats tools such as get_publication_stats or get_audience_insights.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The usage is implied by the description: use it for day-by-day audience metrics matching the dashboard home and Audience charts. However, it does not say when to choose this over sibling stats tools or when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_feedGet feedARead-onlyIdempotentInspect
Your Substack home feed: posts and Notes, For you or Following.
Returns one page of the home feed of the Substack app, split into posts and Notes in feed order. for_you is Substack's own mix; following holds only people and publications you follow or subscribe to. Suggestions of people to follow are left out. Reading marks nothing seen. Page with next_cursor; the feed is personal and changes between calls.
| Name | Required | Description | Default |
|---|---|---|---|
| tab | No | for_you (Substack's picks) or following (whom you follow). Default: for_you. | |
| cursor | No | next_cursor from the previous page. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent and non-destructive, yet the description adds non-obvious behavior: reading marks nothing seen, suggestions are omitted, and the feed is personal and changes between calls. That is real value beyond the structured fields; only the shape of returned items is left unstated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with what the feed is, followed by mode semantics, exclusions, and pagination. Nothing is repeated and every sentence carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description covers the return split (posts and Notes in feed order), pagination, and the personal/ephemeral nature of results. Only the concrete item structure is unspecified, which is a minor gap for a read tool with full annotation coverage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented. The description restates the tab semantics (Substack's mix vs. whom you follow) and pagination via next_cursor, adding only marginal meaning over the schema, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first line names a specific resource (Substack home feed) and its contents (posts and Notes) plus the two modes, so an agent can distinguish it from list_posts, list_notes, or search_substack without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains what for_you and following each contain and that suggestions are excluded, which shapes selection, but it never states when to prefer this tool over siblings like list_notes or list_posts. Usage is implied rather than prescribed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_postGet postARead-onlyIdempotentInspect
Full post: title, subtitle, body as Markdown, audience, URL and dates.
Returns one post of your publication, draft, scheduled or published, with its full body as Markdown, including the paywalled part. Images come back as URLs. Buttons, embeds and footnotes come back as plain text, so writing the body back with update_draft drops them. A scheduled post also has publish_at.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | Post ID from list_posts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, it discloses important return behavior: the full paywalled body is included, images are URLs, and buttons/embeds/footnotes become plain text. It also notes that scheduled posts include publish_at, which materially helps an agent understand the response.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The return fields are front-loaded, followed by the full-body/paywall behavior and then the lossy Markdown caveat. The description is compact and every sentence contributes useful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the burden of explaining the return shape; it does so well, including field coverage and Markdown limitations. Annotations already cover safety, and no critical invocation detail is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single post_id parameter is fully documented in the schema as coming from list_posts. The description does not add syntax or alternate lookup behavior beyond what the schema already provides, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: it returns one post with title, subtitle, Markdown body, audience, URL, and dates. It distinguishes this from list-oriented siblings by emphasizing a single post ID and the full body, including the paywalled portion.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clarifies that the post may be a draft, scheduled, or published, and warns that round-tripping the body through update_draft will lose buttons, embeds, and footnotes. It does not explicitly say when to use this versus list_posts, but the single-post scope is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_post_engagementGet post engagementARead-onlyIdempotentInspect
Who liked and commented on a post, and the subscribers it won and lost.
Returns the Engagement and Growth parts of a post's stats: like and comment counts with the people behind them (name and handle, never email), and the free signups, paid subscriptions and unsubscribes Substack credits to the post. Counts keep changing for days after a send.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | Post ID from list_posts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower, and the description still adds real value: it discloses the privacy constraint (name and handle, never email) and the eventual-consistency trait that counts keep changing for days after a send. It does not describe response shape, but no output schema exists to rely on.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with the headline summary front-loaded and no filler. The opening fragment is a slightly awkward lead-in, but the body is dense and each sentence carries content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With one well-documented parameter and no output schema, the description must convey what comes back, and it does by naming the returned data (counts, people with name/handle, signups, paid subs, unsubscribes) and the timeliness caveat. Only the response structure/format is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Single parameter with 100% schema description coverage ('Post ID from list_posts'), so the schema does the work. The description adds no format or source guidance beyond what the schema already states, which is the baseline-3 case.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource and enumerates what the tool returns: likers/commenters with name and handle, plus free signups, paid subscriptions and unsubscribes. It carves out 'the Engagement and Growth parts of a post's stats,' which implicitly separates it from get_post_stats and get_post_traffic, but never names those siblings outright.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can infer this is the tool for per-post engagement detail versus aggregate stats, but there is no explicit 'use this when / use X instead' routing and no stated prerequisites. Adequate but leaves the choice among get_post, get_post_stats and get_post_traffic to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_post_statsGet post statsARead-onlyIdempotentInspect
Recipients, opens, open rate, views, likes, restacks and subscribers gained.
Returns the engagement numbers of one published post, as on its stats page in the dashboard. Email numbers cover the send; views include the web; likes are reactions. A draft or scheduled post returns an error. Numbers keep growing for days after a send, so check again later.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | Post ID from list_posts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered. The description adds real behavioral context beyond that: the error behavior for unpublished posts and the fact that figures are eventually-consistent and keep growing for days after a send.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, no filler. The leading metric list is useful but slightly awkward as an opener since the actual framing sentence follows it; otherwise well ordered, ending with the important staleness caveat.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does the heavy lifting by enumerating the returned fields and clarifying their scope (email vs web views, likes as reactions). It also covers the failure mode. Only the return structure/format is left unstated, which is minor.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema itself ties post_id to list_posts. The description adds only the implicit constraint that the referenced post must be published, but gives no format hints or extra meaning for post_id beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Returns the engagement numbers of one published post') and enumerates the exact metrics returned (recipients, opens, open rate, views, likes, restacks, subscribers gained). The scope qualifier 'one published post' distinguishes it from aggregate siblings like get_publication_stats and get_daily_stats.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives one useful usage condition — a draft or scheduled post returns an error, so only published posts qualify — plus the 'check again later' guidance for growing numbers. However, it never addresses the closest alternatives (get_post_engagement, get_post_traffic) which sound nearly identical, leaving the agent to guess which per-post metric tool to pick.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_post_trafficGet post trafficARead-onlyIdempotentInspect
Where a post's readers came from: sources, categories and devices.
Returns the Traffic part of a post's stats: each source (app, email, a website, search) with its views, share of all views and the free and paid subscribers it brought, the share per source category and per device. A post nobody has read yet returns empty lists.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | Post ID from list_posts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only, idempotent and non-destructive behavior, so the description's added value is the return semantics: the per-source breakdown, share-of-views and free/paid subscriber attribution, plus the empty-list edge case for unread posts. It does not state whether a time window applies or whether results are paginated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded one-liner stating the resource, then a detail sentence, then an edge-case sentence. The enumeration of source types and metrics is dense but earns its place; no filler or restated title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly takes on responsibility for describing the return shape and the empty-result case. The main gap is the absence of any time-range scoping note, which matters for a stats tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single post_id parameter is documented as coming from list_posts, so the schema carries the load. The description adds nothing further about the parameter, which matches the baseline 3 for high-coverage schemas.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — retrieves the Traffic part of a post's stats — and enumerates what that covers (sources, categories, devices, views, subscriber conversions). It distinguishes itself implicitly from get_post_stats by naming the sub-section, but never names that sibling outright.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: 'Returns the Traffic part of a post's stats' suggests get_post_stats is the broader call, and the empty-list note hints at when results may be barren. There is no explicit statement of when to choose this over get_post_stats or list_traffic_sources.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_publication_statsGet publication statsARead-onlyIdempotentInspect
Total and paid subscribers, new subscribers, paid cancellations and estimated revenue for a period.
Totals are from the publisher dashboard at the end of the period (7, 30 or 90 days). subscribers_churned counts paid cancellations only; Substack keeps no count of free unsubscribes. subscribers_new is the growth in total subscribers plus those cancellations. revenue_usd is not money received: it is the dashboard's annualized revenue at the end of the period, times the period's share of a year.
| Name | Required | Description | Default |
|---|---|---|---|
| period | No | 7d, 30d or 90d. Default: 30d. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds genuinely non-obvious behavior: totals are snapshot at the end of the period, subscribers_churned excludes free unsubscribes because Substack doesn't track them, subscribers_new is derived rather than counted, and revenue_usd is annualized dashboard revenue, not cash received. These are exactly the semantics that would otherwise cause misreporting.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the metric list, then a definitions paragraph. It's dense but every sentence in the second paragraph corrects a plausible misreading (churn scope, derived new-subscriber count, annualized revenue), so little is wasted. Slightly heavy for a one-parameter read tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must carry return-value semantics and it does so well for the four headline metrics. It doesn't state whether the response contains only those fields or describe the object shape, which is the remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the enum already documents 7d/30d/90d with a 30d default. The description restates the same options ('7, 30 or 90 days') without adding format or edge-case detail, so it neither helps nor hurts beyond the schema baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the exact metric set returned (total and paid subscribers, new subscribers, paid cancellations, estimated revenue) for a time period, so an agent knows precisely what it gets. It doesn't explicitly distinguish itself from close siblings like get_daily_stats, get_audience_insights, or get_post_stats, so sibling disambiguation is left to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the framing — period-aggregated publication-level stats — but there is no explicit 'use this when you want X, use get_daily_stats instead when you want Y' guidance. For a tool sitting next to four other stats siblings, that omission costs it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_unread_countsGet unread countsARead-onlyIdempotentInspect
How many unread direct messages, message requests and activity notifications you have.
Returns the badges of the Substack app: unread direct messages, pending message requests and unread activity (likes, replies, new followers, restacks). Reading them marks nothing read.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint/destructiveHint=false, so the safety profile is covered. The description adds genuinely non-obvious context beyond that: the counts map to app badges, activity includes likes, replies, new followers and restacks, and 'reading them marks nothing read' clarifies there is no side effect on the unread state.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with what is counted and followed by the scope of activity types plus the no-mark-as-read note. Minor redundancy between 'badges of the Substack app' and the enumerated categories, but everything earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the return values must be described — and they are: three distinct counts (unread DMs, pending requests, unread activity) plus what counts as activity. That is sufficient for an agent to call it and interpret the result without further detail.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, which is the baseline-4 case; nothing about arguments needs to be explained and the description wastes no words on them.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific resource and metric: unread direct messages, pending message requests and unread activity counts (badges). It clearly conveys it is a count/summary tool rather than a listing tool, though it never names the nearby siblings (list_conversations, list_activity) that an agent might confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can infer this is the lightweight way to check whether anything needs attention before calling list_conversations or list_activity. There is no explicit when-to-use or when-not-to-use guidance, and no alternatives are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
like_commentLike comment or NoteAIdempotentInspect
Like or unlike a comment or a Note as you.
Adds your heart to any Note or Note reply, or to a comment under a post of your publication, or removes it with unlike. Comments and Notes share one ID space, so a Note ID from list_notes or search_substack works too. The author sees your like in their activity.
| Name | Required | Description | Default |
|---|---|---|---|
| unlike | No | Remove your like instead. Default: false. | |
| comment_id | Yes | Comment ID from list_comments, or a Note ID. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true, destructiveHint=false, and readOnlyHint=false; the description adds useful context beyond that: the action is performed 'as you' (authenticated user identity) and 'the author sees your like in their activity' (a visible side effect). It does not describe the return payload, but the extra behavioral detail is meaningful.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening sentence front-loads the core action cleanly. The second sentence is somewhat redundant, restating 'like or unlike' as 'adds your heart ... or removes it with unlike', but the remainder (ID space, author visibility) earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter, annotation-covered mutation with no output schema, the description supplies what an agent needs: scope, identity behavior, visibility side effect, and the ID-space caveat. Only the response shape is unaddressed, a minor gap for this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented, including that unlike defaults to false and that comment_id accepts a Note ID. The description reinforces the shared ID space and names extra ID sources (list_notes, search_substack), which adds slight value but is largely duplicative of the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb pair (like/unlike) and its exact resource (a comment or a Note), and implicitly carves out the boundary with the sibling like_post by restricting scope to comments/Notes rather than posts. An agent can identify the operation without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear usage context—use it to add/remove a heart on a Note, Note reply, or a comment under your publication's post—and explains the unlike path for removal. It stops short of explicitly naming alternatives such as like_post, so routing between the two like-tools still requires inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
like_postLike postAIdempotentInspect
Like or unlike any Substack post as you.
Adds your heart to a post on any publication, as the heart under a post does, or removes it with unlike. The author sees your like in their activity. Liking twice keeps one like.
| Name | Required | Description | Default |
|---|---|---|---|
| unlike | No | Remove your like instead. Default: false. | |
| post_id | Yes | Post ID from search_substack, list_posts or a post's data. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare that this is a non-read-only, open-world, idempotent, and non-destructive operation. The description adds useful behavioral context beyond that: the author sees the like in their activity, and liking twice results in one like, reinforcing idempotency in user-facing terms.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loaded with the main action. The second sentence explains the effect and the third clarifies idempotency, with only minor redundancy between 'Like or unlike' and the following explanation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter mutation with rich annotations and full schema coverage, the description covers the essential behavior: identity, target, unlike semantics, social visibility, and idempotency. It does not mention authentication requirements or edge cases, but those are not critical for this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already documented. The description adds only that unlike removes the like and that the action targets any Substack post, which aligns with the schema but does not add syntax or format details beyond it.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Like or unlike any Substack post as you.' It clearly distinguishes this action from sibling tools such as like_comment and follow_user by naming the target as a Substack post and the identity as the authenticated user.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use it by saying it likes or unlikes any Substack post, and it explains that unlike removes the like. However, it does not explicitly name alternatives or exclusions, such as using like_comment for comments or when not to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_activityList activityARead-onlyIdempotentInspect
Your Substack notifications: replies, likes, new followers, restacks, newest first.
Returns the Activity tab of the Substack app, newest first. type is Substack's own name, e.g. note_reply, note_like, comment_reply, comment_like, post_like, follow, restack or mention. from lists the latest people behind a grouped item and people counts all of them. A reply or mention carries its comment_id and text; on_comment_id and on_post_id point at what it was about. Reading the list marks nothing read. Page with next_cursor.
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | No | next_cursor from the previous page. | |
| filter | No | all, replies (replies and mentions) or restacks. Default: all. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/non-destructive, and the description adds genuinely new context: 'Reading the list marks nothing read', grouped items aggregated with a people count, and pagination via next_cursor. It stops short of describing rate limits or empty-state behavior, but the safety profile is well complemented.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with what the list contains, then behavior, then paging — no filler sentences. Slightly dense with response-field detail (comment_id, on_post_id) that could be tighter.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully describes the returned shape (type, from, people, comment_id, on_comment_id, on_post_id) and the paging contract. Complete enough for a zero-required-parameter list tool; only edge behaviors like empty results are unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both cursor and the filter enum are already documented in the schema; baseline 3 applies. The description adds no parameter syntax or format detail beyond repeating that paging uses next_cursor and enumerating the 'type' names, which are response fields rather than inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource (Substack notifications / Activity tab) with the concrete item types it contains (replies, likes, new followers, restacks) and the ordering (newest first). An agent can tell this apart from list_comments, list_note_replies and get_unread_counts without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the use case (reading the Activity tab, paging with next_cursor) and explains the filter values, but never names an alternative or says when to prefer this over list_comments, list_note_replies, or get_unread_counts. Usage is inferable rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_commentsList commentsARead-onlyIdempotentInspect
Comments on a post, with author, text and whether you replied.
Returns all comments of one post at once, oldest first, with replies nested under their parent. Deleted comments are left out. replied is true when you answered anywhere in the thread under the comment; unanswered_only keeps only top-level comments where you did not. Pass comment_id to reply_to_comment.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | Post ID from list_posts. | |
| unanswered_only | No | Skip threads you already replied to. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say read-only/idempotent; the description adds substantive behavior the annotations cannot convey: the whole thread is returned at once with no pagination, ordering is oldest-first, replies are nested under parents, and deleted comments are omitted. That is exactly the context an agent needs before calling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the resource and its fields, then return shape, then the sibling handoff. No filler and nothing repeated from the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the return-shape burden and does so fully: field set, nesting, ordering, exclusion of deleted items, and the meaning of the replied flag. Nothing an agent needs in order to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline would be 3, but the description adds real meaning: replied means answered anywhere in the thread under the comment, and unanswered_only applies to top-level comments only — nuances not present in the schema's "Skip threads you already replied to".
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("Comments on a post") and enumerates the returned fields (author, text, replied). It also names the follow-on sibling ("Pass comment_id to reply_to_comment"), so an agent can separate this from reply_to_comment and get_post without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear use context (fetch all comments of one post) and an explicit sibling handoff to reply_to_comment, plus the condition that selects unanswered_only. It stops short of naming when to prefer an alternative listing tool (e.g. get_conversation or list_note_replies), so no explicit exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_conversationsList conversationsARead-onlyIdempotentInspect
Your direct-message conversations, latest first, with the last message.
Returns your Substack chat inbox: one-to-one and group direct messages with who they are with, the last message, its time, your unread count and whether it is a message request from someone you do not follow. Publication chats are left out. Reading the list does not mark anything read. Pass conversation_id to get_conversation or send_message.
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | No | next_cursor from the previous page. | |
| unread_only | No | Only conversations with unread messages. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the read-only annotations, the description discloses ordering (latest first), returned fields, exclusions (publication chats left out), and the important side-effect clarification that reading the list does not mark anything read. It does not discuss pagination behavior or rate limits in the description, though cursor pagination is covered by the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core action and then efficiently adds the inbox scope, returned fields, exclusions, side-effect behavior, and next-step guidance. Every sentence contributes useful information without repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even without an output schema, the description explains the returned contents, ordering, exclusion rules, and read-state behavior. Combined with annotations covering safety and schema covering parameters, an agent has enough information to call and interpret this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 100% description coverage for both parameters, so it already documents cursor and unread_only. The description does not add parameter-specific meaning beyond that baseline, which is appropriate for a fully documented two-parameter schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific resource (direct-message conversations) and scope (Substack chat inbox, latest first, with last message). It clearly distinguishes this from publication chats by explicitly excluding them and explains the returned fields.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives useful context for using the returned conversation_id with get_conversation or send_message, and it clarifies that publication chats are excluded. However, it does not explicitly say when to use this tool versus sibling tools such as get_unread_counts, leaving some alternative-choice guidance implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_note_repliesList Note repliesARead-onlyIdempotentInspect
Replies under a Note, with author, text and likes.
Returns the direct replies under one Note (yours or anyone's), in Substack's order. replies is the count under each reply; list those by passing its note_id. Substack sends no handle with replies, so author.handle is empty and url is null. Page with next_cursor.
| Name | Required | Description | Default |
|---|---|---|---|
| cursor | No | next_cursor from the previous page. | |
| note_id | Yes | Note ID from list_notes or search_substack. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent annotations, it discloses ordering (Substack's order) and two non-obvious data quirks: author.handle is empty and url is null because Substack sends no handle with replies. It also states pagination happens via next_cursor. These are exactly the surprises that would otherwise mislead an agent parsing results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with what the tool returns, then scope, then quirks, then pagination. No filler. The opening sentence being a bare noun phrase rather than a full clause is a minor structural weakness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden and does so well: it names the returned fields, ordering, null-handling, and pagination. It stops short of saying whether pagination terminates or how deep reply nesting goes, which an agent calling repeatedly would want.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: note_id points at 'one Note' whose replies you want, and it explicitly warns that the `replies` field is a count that can itself be passed as a note_id. That disambiguates a confusing name collision the schema alone would not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The second sentence states precisely what is returned: 'the direct replies under one Note (yours or anyone's), in Substack's order.' That distinguishes it from list_notes (top-level notes) and reply_to_note (a write). The first line is a fragment ('Replies under a Note, with author, text and likes') but the following sentence supplies the verb and scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clarifies the scope is one Note, 'yours or anyone's', and gives an actionable recursion rule: reply objects carry a `replies` count, and you drill in by passing that as note_id. It does not explicitly name alternatives such as list_notes or get_conversation, so it falls short of full when/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_notesList NotesARead-onlyIdempotentInspect
Notes posted by you or any other Substack user, newest first, with likes and replies.
Returns the Notes on a profile's Notes tab, newest first: text, time, likes, restacks, reply count and link. Without user it lists yours. Posts and restacks of posts on the profile are left out. Page with next_cursor. Pass note_id to list_note_replies, like_comment or reply_to_note.
| Name | Required | Description | Default |
|---|---|---|---|
| user | No | Handle (e.g. @mayachen) or user ID. Default: you. | |
| cursor | No | next_cursor from the previous page. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/openWorld safety, so the bar is lower; the description still adds useful substance — the fields returned (text, time, likes, restacks, reply count, link), the exclusion of posts/restacks, and cursor-based paging. It doesn't state whether results are capped or how large a page is, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded and compact at four short sentences, with the exclusion and paging facts easy to scan. The opening sentence and second sentence partly duplicate the 'newest first' and content summary, which is mild waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does the job of telling the agent what comes back (text, time, likes, restacks, replies, link) plus how to paginate and which tools consume note_id. Only page-size limits and empty-result behavior are unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented in the schema. The description only restates the user default and cursor paging, adding no syntax or format detail beyond the schema — the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Notes posted by you or any other Substack user'), its scope ('Notes tab'), ordering ('newest first'), and explicitly excludes posts and restacks of posts. An agent can distinguish it from list_note_replies and list_posts without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the key default ('Without user it lists yours') and an explicit hand-off: pass note_id to list_note_replies, like_comment or reply_to_note. That routes the agent well, though it never states when to prefer a different listing tool or any prerequisite/precondition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_postsList postsARead-onlyIdempotentInspect
Posts of your publication, newest first, with status and audience.
Lists posts of your publication, newest first. Filter by status to see drafts or scheduled posts. Scheduled posts include their publish time. Pages hold up to 50 posts; pass next_cursor back as cursor for the next page.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | 1 to 50. Default: 20. | |
| cursor | No | Next page cursor from the previous call. | |
| status | No | published, draft or scheduled. Default: published. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior, so the bar is lower. The description still adds real signal: newest-first ordering, page cap of 50, cursor round-trip semantics, and that scheduled posts carry a publish time.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening line is immediately echoed by the first sentence ("Posts of your publication, newest first" / "Lists posts of your publication, newest first"), which is wasted space. The remaining pagination and status notes are well front-loaded and earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing returns, and it does reasonably: status, audience, ordering, and the scheduled publish time. Pagination is covered; per-post fields are only sketched, not enumerated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents limit, cursor, and the status enum with defaults. The description restates the same defaults and the cursor pattern rather than adding new parameter nuance; baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Lists posts of your publication") plus the ordering and returned fields. It is unambiguous against siblings like get_post or list_notes, though it never names an alternative explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context for the key filter ("Filter by status to see drafts or scheduled posts") and explains the pagination loop. It stops short of explicit when-not-to-use guidance or pointing to get_post for single-post retrieval.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_post_tagsList post tagsARead-onlyIdempotentInspect
Tags your publication uses to group posts.
Returns every post tag of your publication with its ID, name and slug; readers see tagged posts on /t/{slug}. hidden tags group posts without a public page. Pass tag_id to tag_post.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this as a read-only, idempotent, non-destructive listing operation. Beyond that, the description adds useful behavioral context: readers see tagged posts at /t/{slug}, and hidden tags group posts without a public page.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loaded: it first establishes what post tags are, then details the return shape and URL behavior, then hidden-tag semantics, then downstream use. No sentence is wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no parameters, no output schema, and rich annotations, this description gives enough detail to call the tool correctly: it returns every post tag with ID/name/slug and explains hidden tags. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
This tool has zero parameters, so the schema carries no parameter semantics to explain. The mention of tag_id refers to tag_post rather than this tool, but it is still useful workflow context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the resource as publication post tags and says it returns every post tag with ID, name, and slug. It implicitly distinguishes post tags from subscriber tags and from creation tools, but it does not explicitly name a sibling alternative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The intended use is implied by 'Returns every post tag' and the note that tag_id is passed to tag_post, which helps an agent understand the workflow. However, there is no explicit when-to-use guidance, no exclusions, and no direct comparison to list_subscriber_tags or create_post_tag.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_recommendationsList recommendationsARead-onlyIdempotentInspect
Publications you recommend, or that recommend you, with the subscribers each sent.
Returns Audience > Recommendations: with direction given, the publications you recommend; with received, the ones recommending you, and whether you recommend them back (mutual). subscribers_sent counts subscribers the recommendation brought. The table is rebuilt by Substack in the background, so a recommendation made minutes ago may be missing while counts already include it; publication_id checks one recommendation of yours directly.
| Name | Required | Description | Default |
|---|---|---|---|
| direction | No | given (publications you recommend) or received (that recommend you). Default: given. | |
| publication_id | No | Check one publication instead: does yours recommend it (given only). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the read-only and idempotent annotations, the description discloses important eventual-consistency behavior: the table is rebuilt in the background, recent recommendations may be missing while counts already include them. That caveat is operationally valuable and not captured by annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is front-loaded and contains no filler, but the second sentence is long and combines output fields, background rebuild caveats, and parameter behavior. It is efficient overall, though the density reduces scannability slightly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description explains what is returned, including direction-specific results, mutual status, and subscriber counts, and it covers the main behavioral caveat. It does not mention pagination, limits, or whether the list is ever truncated, which is a notable gap for a list-style tool with no output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already documented, including the enum values and default for `direction` and the `given only` restriction on `publication_id`. The description reinforces these meanings and adds related output context such as mutual recommendations, but it does not add substantial new parameter semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the specific resource and distinguishes both directions: publications the user recommends versus publications that recommend the user. It also clarifies that subscribers each sent are included, which makes the tool’s scope concrete and distinguishable from adjacent recommendation actions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains how to interpret and use the `direction` values and how `publication_id` checks one recommendation directly. It does not explicitly contrast with siblings such as `recommend_publication` or `list_subscriptions`, but the context is otherwise clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_sectionsList sectionsARead-onlyIdempotentInspect
Sections of your publication, the separate newsletters inside it.
Returns each section with its ID, name, description and slug. live is false while Substack still sets a new section up. subscribed_by_default tells whether new subscribers get its emails. A publication without sections returns an empty list.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnly, idempotent, non-destructive behavior. The description adds useful behavioral context beyond that: returned fields, the meaning of live while Substack sets up a new section, what subscribed_by_default controls, and that no sections yields an empty list.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three compact sentences, front-loaded with the core resource definition and followed by relevant return-field semantics. Every sentence contributes useful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There are no parameters and no output schema, so the description carries the return-value burden itself. It names the key returned fields and explains the two non-obvious field meanings, making the tool complete enough for an agent to call correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
This tool has zero parameters, so the baseline is 4. The description appropriately does not invent parameter guidance where none is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb/resource framing: listing the sections of a publication, explicitly defined as the separate newsletters inside it. That resource is distinct from the many list_* siblings such as list_post_tags and list_subscribers, so an agent can identify what this tool covers.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The context of use is clear from 'Sections of your publication,' implying it should be called to retrieve section data rather than posts, tags, or subscribers. It does not explicitly name alternatives or when not to use it, which keeps it below the top score.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_subscribersList subscribersARead-onlyIdempotentInspect
Subscribers with plan, start date and activity rating.
Lists subscribers, newest first, from the subscriber dashboard. Activity rating is the 0 to 5 score Substack shows there. Pages hold up to 500 rows; pass next_cursor back as cursor. The plan and since filters apply inside each page, so a filtered page can be short or empty while next_cursor still points further. Someone added a minute ago may not show yet: Substack fills the table in the background. paid includes founding members.
| Name | Required | Description | Default |
|---|---|---|---|
| plan | No | all, free, paid, comp or founding. Default: all. | |
| limit | No | 1 to 500. Default: 100. | |
| since | No | Only subscribers who joined on or after this date. | |
| cursor | No | Next page cursor from the previous call. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, non-destructive), and the description adds real behavioral context on top: eventual consistency ('someone added a minute ago may not show yet' via background table fill), short/empty filtered pages that still have a next_cursor, and the 'paid includes founding members' semantics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the return payload and ordering, then pagination caveats — every sentence carries information. The opening sentence is a fragment and the density of caveats makes it slightly harder to scan, keeping it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates well by naming the returned fields and ordering, and it fully covers pagination and staleness. It doesn't say how end-of-list is signalled (e.g. missing next_cursor) or whether a total count is returned, a minor remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description goes further by clarifying that 'paid includes founding members' and by explaining cursor/filter interaction, which the schema alone does not convey. The 'since' date format and limit bounds are left to the schema, which is acceptable.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
A specific verb and resource ('Lists subscribers ... from the subscriber dashboard') plus the returned fields (plan, start date, activity rating) and ordering (newest first). It does not explicitly differentiate itself from siblings like export_subscribers or list_subscriber_tags, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Strong operational guidance: it explains cursor round-tripping, page size, and that 'the plan and since filters apply inside each page'. It never says when to prefer export_subscribers or list_subscriber_tags over this tool, so the alternative-selection guidance is absent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_subscriber_tagsList subscriber tagsARead-onlyIdempotentInspect
Tags you use to group subscribers.
Returns the subscriber tags of your publication with their IDs, as Audience > Subscribers > Tags shows them. Subscribers never see tags. Pass tag_id to tag_subscribers.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only, idempotent, non-destructive behavior, so the bar is lower. The description adds genuinely non-obvious context: tags are internal-facing ('Subscribers never see tags') and correspond to a specific UI location, which helps the agent trust the output.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with what the resource is, then what is returned, then what to do with it. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description does describe the return (tags with IDs). It does not mention ordering, empty results, or pagination, but for a zero-arg listing tool this is close to complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters means the baseline is 4; there is nothing for the description to compensate for. It nonetheless mentions tag_id as the identifier to use downstream, which links this tool to tag_subscribers.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Returns the subscriber tags of your publication with their IDs') and implicitly separates itself from list_post_tags by scoping to subscriber tags. Could be sharper about sibling differentiation since both list_post_tags and create_subscriber_tag exist.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent forward: 'Pass tag_id to tag_subscribers' tells it what to do with the result. It does not state when not to use it (e.g. versus list_post_tags), which keeps it short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_subscriptionsList subscriptionsARead-onlyIdempotentInspect
Publications you subscribe to, with your plan and whether their emails reach you.
Returns every publication your account subscribes to, as Settings > Subscriptions lists them: name, link, plan (free, paid, comp, founding or gift, as Substack names the membership) and whether you get its emails. Your own publications are left out.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld, so safety is covered; the description adds genuinely non-obvious behavior: it returns the complete set unfiltered and deliberately excludes the caller's own publications. It does not discuss auth requirements, ordering, or any size limits, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the resource and its identity, then the return shape. The plan enumeration (free, paid, comp, founding, gift) and the exclusion clause each earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the full burden of describing return values and does so concretely — fields and their possible values are enumerated, and the one surprising exclusion is stated. An agent can call this correctly and interpret the result without further information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4 and there is nothing for the description to compensate for. The description correctly avoids inventing filter options that the empty schema would reject.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Returns every publication your account subscribes to" names the resource and its direction clearly, and the field list (name, link, plan, email delivery) pins down what comes back. It implicitly separates itself from list_subscribers by direction (what you subscribe to, not who subscribes to you) but never names that sibling, so the differentiation is inferential rather than explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The Settings > Subscriptions analogy gives a usable mental model for when this tool is the right one, and "Your own publications are left out" is a real scoping remark. But there is no explicit statement of when to prefer this over the other list_* tools, nor any note that no filtering/pagination is offered, leaving usage implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_traffic_sourcesList traffic sourcesARead-onlyIdempotentInspect
Where your publication's visitors came from in a period, most views first.
Returns Analytics > Traffic > Traffic sources: each source (the app, email, a website, search, social) with its category, views, unique visitors and the free and paid subscribers it brought. Sorted by views; page with next_cursor.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Default: 20. | |
| cursor | No | next_cursor from the previous page. | |
| period | No | Default: 30d. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the description's added value is the sorting rule ('sorted by views; page with next_cursor') and the exact return fields per source. It stops short of noting timezone/period-anchoring semantics, which is a minor gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core question the tool answers, then the returned payload and ordering. No filler or restated title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does the heavy lifting by enumerating the returned fields (source, category, views, unique visitors, free/paid subscribers) plus sort order and pagination. It omits how the period is anchored in time, which slightly limits interpretation of results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and documents limit, cursor, and the 7d/30d/90d/365d period enum with defaults, so the bar is baseline. The description only restates 'in a period' and confirms next_cursor paging without adding syntax or behavior beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource and dimension: where a publication's visitors came from, broken out by source with views/visitors/subscribers. That is clearly distinguishable from analytics siblings like get_post_traffic or get_audience_insights, though no sibling is named explicitly to sharpen the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied by 'in a period' plus the period enum; it never states when to choose this over get_post_traffic, get_daily_stats, or get_audience_insights. No exclusions or prerequisites are given, leaving the agent to infer the comparison traffic-vs-audience split.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pin_commentPin commentAIdempotentInspect
Pin a comment to the top of your post's comments, or unpin it.
Pins one comment on a post of your publication above all others, as Pin in the comment menu does, or unpins it. A comment on someone else's post returns an error.
| Name | Required | Description | Default |
|---|---|---|---|
| unpin | No | Unpin instead. Default: false. | |
| comment_id | Yes | Comment ID from list_comments. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare non-read-only, idempotent, non-destructive behavior, so the description is not obliged to restate them. It adds real value beyond them by disclosing the ownership error case and the ordering effect ('above all others'), which an agent cannot get from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and short overall. The second sentence largely restates the first ('or unpins it' appears twice), which is minor redundancy but not damaging.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter, annotation-covered tool with no output schema, the description is nearly sufficient: it covers ownership constraints and the resulting comment ordering. Only the return behavior and whether only one comment can be pinned at a time are left unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and both parameters (comment_id, unpin) are documented in the schema, so the baseline applies. The description mentions unpinning but adds no syntax, defaults, or format detail beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Pin a comment to the top of your post's comments') and names the reciprocal action (unpin). It is clearly distinct from siblings like like_comment or delete_comment, though it never explicitly contrasts with them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: it references 'as Pin in the comment menu does' and notes that comments on someone else's post error out. There is no explicit guidance on when to prefer this over related siblings (like_comment, reply_to_comment) or on prerequisites beyond the ownership constraint.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
publish_notePublish NoteADestructiveInspect
Short post in Substack Notes, now or at a set time, optionally with a link card to one of your posts.
Posts a Note under your name. Without publish_at it goes out now; with it, the Note waits in your scheduled Notes, status is scheduled and published_at is that time. Text is 1 to 1,000 characters. link_post_id must be a published post.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Note text, up to 1,000 characters. | |
| publish_at | No | ISO 8601 with time zone. Omit to post now. | |
| link_post_id | No | Attach one of your published posts as a link card. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safety profile (readOnly false, destructive true, openWorld true, non-idempotent), so the description only needs incremental context — and it delivers real state behavior: what the Note's status and published_at become when scheduled, and the character bound. It does not disclose what the response contains (e.g., a Note ID) or the public/irreversible consequence of posting under the user's name, which is the main residual gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The lead line front-loads resource and scope, and the second paragraph packs timing behavior, limits, and the link-card precondition into three sentences. Slight redundancy in "Text is 1 to 1,000 characters" duplicating the schema description keeps it from a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter write tool with no output schema, it covers the essentials — timing semantics, character bound, and link-card eligibility. Missing are the return shape and any note about visibility/reversibility of the published Note, which matter given destructiveHint=true.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description earns above baseline by adding semantics the schema lacks: the downstream effect of publish_at (status becomes scheduled, published_at equals that time) and the constraint that link_post_id must reference an already-published post. The character range restates the schema and adds nothing.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb+resource ("Short post in Substack Notes ... Posts a Note under your name") and implicitly separates Notes from long-form posts in the sibling set (publish_post) by framing link_post_id as attaching "one of your posts." It never names publish_post, schedule_post, or reply_to_note explicitly, so sibling differentiation is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear conditional for the timing fork: "Without publish_at it goes out now; with it, the Note waits in your scheduled Notes," and a hard precondition that link_post_id must be a published post. It stops short of naming alternatives or exclusions, so an agent must infer that scheduling here replaces a separate schedule_post call and that reply_to_note handles threaded replies.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
publish_postPublish postADestructiveInspect
Publish a draft now.
Publishes a draft immediately, on the web and, unless send_email is false, by email, to the audience set on the draft. Substack's own pre-publish check runs first; a missing title or an empty body stops the call. A sent email cannot be recalled. On a publication with sections the post goes to section_id, else to the section already set on the draft, else to the main publication.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | Post ID from list_posts. | |
| section_id | No | Section ID from list_sections, or main. Default: the draft's section, else main. | |
| send_email | No | Email it to subscribers. Default: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true and non-idempotent, and the description goes further by disclosing the irreversible consequence ('A sent email cannot be recalled') and the abort conditions of the server-side check. The section routing fallback chain adds operational context not available in the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The imperative one-liner is front-loaded and the remaining sentences are dense with distinct facts. The slight restatement between 'Publish a draft now' and 'Publishes a draft immediately' is the only waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter mutation with no output schema, the definition covers failure modes, email irreversibility, and section routing. It stops short of describing what is returned (post URL, publish status) or what state the draft is left in afterward.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning: it explains that send_email=false suppresses email while still publishing on the web, and it spells out the three-step resolution order for section_id. Only the post_id sourcing is left entirely to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The definition opens with a specific verb-and-resource pair plus a timing qualifier ('Publish a draft now') that separates it from schedule_post and update_draft. The second sentence confirms the effect without restating the title verbatim.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It establishes clear operating conditions: the pre-publish check runs first and fails on missing title or empty body, and the audience comes from the draft. It does not explicitly name the alternatives (schedule_post, unpublish_post) that an agent might confuse it with, so exclusions are inferred rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
recommend_publicationRecommend publicationADestructiveIdempotentInspect
Recommend another publication to your readers, or stop recommending it.
Adds a publication to your Recommendations, as Growth > Recommendations does: Substack suggests it to people who subscribe to you and notifies its author. blurb is the short reason readers see. With remove it takes the recommendation back.
| Name | Required | Description | Default |
|---|---|---|---|
| blurb | No | Why you recommend it, shown to your readers (optional). | |
| remove | No | Stop recommending it instead. Default: false. | |
| publication_id | Yes | Publication ID, e.g. from search_substack posts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes meaningfully beyond the annotations: it discloses the outward-facing consequences that a caller could not infer from hints alone — the publication is suggested to people who subscribe to the caller and the recommended author is notified. It also clarifies that the same tool reverses the effect, which supports the idempotentHint. It does not describe the response payload or how un-recommending interacts with an existing blurb.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the action and its inverse, then the mechanics. Slight overlap between 'Recommend another publication to your readers' and 'Adds a publication to your Recommendations', but nothing is wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-parameter toggle tool with no output schema and rich annotations, the description covers the effect, the side effects, and the reversal path. The remaining gap — what a successful call returns and whether an existing recommendation's blurb is replaced — is minor but real.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all three parameters are already documented in the schema, and the description largely restates them ('blurb is the short reason readers see', 'with remove it takes the recommendation back'). The blurb phrasing adds a small amount of audience context, but this is baseline-level value, not compensation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (recommend / stop recommending) applied to a specific resource (another publication), and the dual-mode nature is spelled out up front. It does not name its read-side sibling list_recommendations, but the action is distinct enough from every other sibling in the set that confusion is unlikely.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The UI anchor 'as Growth > Recommendations does' and the note that `remove` reverses the action give an implied picture of when to use each mode. However, there is no explicit when-to-use framing, no prerequisite (e.g. must be subscribed/authorized), and no pointer to list_recommendations for checking current state.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_commentRemove commentADestructiveInspect
Remove someone's comment from your post as the publication's moderator.
Hides a comment on a post of your publication, as Remove in the comment menu does: readers see that a moderator removed it, the text is gone, replies under it stay. Use delete_comment for your own comments. A comment on someone else's post returns an error.
| Name | Required | Description | Default |
|---|---|---|---|
| comment_id | Yes | Comment ID from list_comments. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructive/non-idempotent, so the description is free to add what they cannot: readers see a moderator-removal notice, the comment text is gone, but replies underneath persist. It also discloses the moderator-role requirement and the error path for out-of-scope comments.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and sized to its content. The first sentence and the opening of the second partially restate each other ('Remove someone's comment from your post' / 'Hides a comment on a post of your publication'), which is mild redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
One required parameter, no output schema, and the description covers effect, audience visibility, role requirement, error condition, and the sibling alternative. The only omission is whether the removal can be reversed, which matters for a destructive operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and comment_id's provenance ('from list_comments') is already documented in the schema. The description adds only indirect scoping context (your publication's post) and no format or lookup detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb (remove/hide) plus resource (comment) and the exact permission scope ('as the publication's moderator'). The second paragraph defines the operation concretely as the UI's 'Remove' action, which distinguishes it unambiguously from the nearby delete_comment sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: 'Use delete_comment for your own comments.' It also states a hard exclusion — a comment on someone else's post returns an error — so the agent knows both the alternative tool and the precondition for success.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
remove_subscriberRemove subscriberADestructiveInspect
Remove one email from your subscriber list.
Removes a subscriber from your list, as Remove in the subscriber's menu does: they get no more emails from you and no notice. A paid subscription is cancelled and Substack refunds the unused part. An email not on your list returns an error; add_subscriber takes about a minute before the address is listed.
| Name | Required | Description | Default |
|---|---|---|---|
| Yes | Subscriber's email address. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations, which only say destructive, non-idempotent, and open-world. The description discloses the user-visible consequence (no notice sent), the billing consequence (paid subscription cancelled with a prorated refund from Substack), and the failure mode (error on unknown email). That is exactly the side-effect detail an agent needs before invoking a destructive tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action, then layered with consequences, error behavior, and a timing caveat — every sentence contributes. The first two clauses partially restate the same removal act ('Remove one email…' / 'Removes a subscriber…'), a small redundancy that keeps it short of a 5.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter destructive mutation with no output schema, the description covers side effects, refunds, error behavior, and a race condition with add_subscriber. It stops short of saying whether removal is reversible or can be re-added, which is the remaining question an agent might have before a destructive call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required parameter and the schema documents it fully at 100% coverage, so the baseline of 3 applies. The description's 'one email' phrasing confirms cardinality and that the address must already be on the list, but adds no format or normalization guidance beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Remove one email from your subscriber list') with an explicit scope of one address, and the follow-up sentence anchors it to the concrete UI action ('as Remove in the subscriber's menu does'). An agent can immediately distinguish this from sibling list_subscribers, add_subscriber, and tag_subscribers.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the operative condition: an address not on the list returns an error, and warns that add_subscriber takes about a minute before the address is listed, which implies you must wait before removal succeeds. It does not explicitly name a preferred alternative or state exclusions, but no sibling performs removal, so the routing gap is minor.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reply_to_commentReply to commentADestructiveInspect
Reply as you under a comment on your post.
Posts a reply under one comment on a post of your publication, under your name, visible to everyone who can read the post. A comment elsewhere on Substack returns an error. The author gets Substack's usual reply notification.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Reply text. | |
| comment_id | Yes | Comment ID from list_comments. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare non-read-only, non-idempotent, open-world, destructive; the description adds genuine value on top — public visibility scope ('visible to everyone who can read the post'), notification side effect for the author, and the error behavior for out-of-scope comments. It doesn't say whether the reply can be edited/removed afterward, which is the main remaining gap for a mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the action, then scope, then side effect. Minor redundancy between 'Reply as you' and 'under your name' but nothing wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter mutation with no output schema, the description covers identity, visibility, scope errors, and notification behavior. Only post-action reversibility/editability is unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so comment_id and body are already documented in the schema itself. The description only adds the constraint that the referenced comment must live on your publication; no format or length guidance beyond that.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (reply) and resource (a comment on your post), plus the identity it posts under. The scoping ('on a post of your publication', 'a comment elsewhere on Substack returns an error') cleanly separates it from siblings like reply_to_note, like_comment, or pin_comment.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly bounds when it applies: only comments on your own publication's posts; comments elsewhere error out. It does not explicitly name the alternative path for other cases (reply_to_note / get_conversation), so it stops short of full when-to-use routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reply_to_noteReply to NoteADestructiveInspect
Reply as you under any Note or Note reply.
Posts a reply under a Note (yours or anyone's) or under a reply to one, visible to everyone who sees the Note. Text is 1 to 1,000 characters; Markdown bold, italics and links work. The author gets Substack's usual notification.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Reply text, up to 1,000 characters. | |
| note_id | Yes | Note ID from list_notes, list_note_replies or search_substack. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag this as a non-idempotent, open-world, destructive write; the description adds real context beyond them: audience ('visible to everyone who sees the Note'), the author notification, supported Markdown, and the 1–1,000 character bound. It does not explain why the operation is flagged destructive (irreversibility, inability to edit/delete) — the one remaining gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and target in the first sentence; the second sentence packs visibility, limits, formatting, and notification without filler. Slightly dense but every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With only two required parameters, full schema coverage, and annotations covering the safety profile, the description supplies the remaining behavioral essentials. The only omission is what a successful call returns (reply ID/object), which matters somewhat since no output schema exists.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents note_id sources and the 1,000-char limit. The description adds formatting semantics for body (bold, italics, links render) and reinforces the 1-character minimum, which the schema omits.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('reply') and resource ('Note or Note reply') plus the acting identity ('as you'), which lets an agent distinguish it from publish_note and reply_to_comment. It stops short of naming those siblings explicitly, so the differentiation is inferential rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Specifies that the target may be a top-level Note or a reply to one ('yours or anyone's'), which resolves the main targeting ambiguity. However, it never names an alternative tool or says when not to use this one — e.g. that replies to comments belong to reply_to_comment.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
schedule_postSchedule postADestructiveIdempotentInspect
Publish a draft at a set time, on the web and by email.
Schedules a draft to go live at the time you set, on the web and, unless send_email is false, by email, to the audience set on the draft. The time needs a time zone and must be in the future. Substack's own pre-publish check runs first; a missing title or an empty body stops the call. A scheduled post stays editable until it goes out. On a publication with sections the post goes to section_id, else to the section already set on the draft, else to the main publication.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | Post ID from list_posts. | |
| publish_at | Yes | ISO 8601 with time zone. | |
| section_id | No | Section ID from list_sections, or main. Default: the draft's section, else main. | |
| send_email | No | Email it to subscribers. Default: true. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare this is a mutating, destructive, idempotent, open-world operation. The description adds valuable context beyond that: pre-publish checks can block the call, missing titles or empty bodies stop scheduling, scheduled posts remain editable until publication, and section fallback behavior is explained.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and well structured, moving from the core action to constraints and fallback behavior. The first two sentences are slightly redundant, but the overall text is efficient and every remaining sentence carries useful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a four-parameter scheduling mutation with annotations and full schema coverage, the description is nearly complete. It covers constraints, failure conditions, editability, and audience routing; only the expected return or confirmation behavior is not described, which is a minor gap given the absence of an output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters are already documented in the schema. The description reinforces key semantics such as time zone, future time, email default, and section fallback, but does not add much beyond the schema's own descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: scheduling a draft to publish at a future time. It also clarifies the channels (web and email) and audience behavior, making the tool's purpose immediately clear and distinct from generic publishing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear conditions for use: the time must include a time zone and be in the future, and the draft must pass Substack's pre-publish check. However, it does not explicitly contrast this with siblings like publish_post for immediate publishing or cancel_scheduled_post for cancellation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_substackSearch SubstackARead-onlyIdempotentInspect
Search all of Substack for people, posts and Notes.
Runs Substack's search as the search box does and splits the results into people, posts and Notes. Use the IDs with follow_user, like_post, like_comment, reply_to_note, send_message or recommend_publication. Page with next_cursor; later pages may hold only posts and Notes.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Words to search for. | |
| cursor | No | next_cursor from the previous page. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, openWorld, idempotent and non-destructive, so the bar is lower. The description still adds real value: result partitioning into people/posts/Notes, the caveat that later pages may hold only posts and Notes, and the fact it mirrors the live search box (implying variable, non-exhaustive results).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with purpose, then chaining guidance, then pagination caveat. No filler and nothing repeated from the title or schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the return-shape burden and does: it says results come back split into people, posts and Notes, that IDs are reusable in specific write tools, and how to paginate. An agent has everything needed to call and consume it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline would be 3; the description earns above that by explaining the paging model ('Page with next_cursor; later pages may hold only posts and Notes'), which tells the agent what the cursor parameter actually does and why page 2+ looks different.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Search all of Substack for people, posts and Notes') and clarifies the scope is the whole platform, not the user's feed or subscriptions. This distinguishes it from siblings like get_feed, list_posts and list_subscriptions without needing the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly explains how it behaves ('runs Substack's search as the search box does') and gives concrete downstream chaining with follow_user, like_post, reply_to_note, send_message and recommend_publication. It does not name a when-not-to-use case or contrast with get_feed/list_posts for browsing, which keeps it from a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_messageSend messageADestructiveInspect
Send a direct message on Substack, in a conversation or to a person.
Sends a private chat message under your name. With conversation_id it replies there; with user it writes to that person, in your existing conversation with them or a new one. Someone who does not follow you gets it as a message request. Give one of conversation_id or user. A sent message cannot be recalled.
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Message text. | |
| user | No | Or start one with this handle (e.g. @mayachen) or user ID. | |
| conversation_id | No | Reply in this conversation from list_conversations. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true, non-idempotent and open-world, and the description is consistent, reinforcing irreversibility with 'A sent message cannot be recalled'. It adds genuinely non-annotated behavior: messages are sent under your name, and non-followers receive the message as a request. It omits rate limits and failure modes for invalid handles.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the action, then targeting, then the delivery caveat, ending on the destructive warning. No sentence is disposable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a mutation tool with no output schema, the description covers targeting, delivery semantics and irreversibility, which is most of what an agent needs. It does not indicate what the call returns (e.g. a message or conversation identifier), leaving a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline would be 3, but the description adds real meaning beyond the schema: the mutual-exclusivity constraint ('Give one of conversation_id or user') and what the `user` path does behaviorally (reuses an existing conversation or creates one, and becomes a message request if the person does not follow you).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Send a direct message on Substack') plus the two targeting modes (conversation vs person) and the nature of the channel ('private chat message'), which implicitly separates it from the public reply_to_comment / reply_to_note siblings. An agent can tell what this does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'With conversation_id it replies there; with user it writes to that person' plus 'Give one of conversation_id or user' clearly routes the agent between the two invocation modes. It stops short of naming alternatives or stating when not to use this tool (e.g. public reply vs private DM), so it is clear context without explicit exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tag_postTag postAIdempotentInspect
Add a tag to a post, or take it off.
Puts one of your post tags on a draft or published post, or removes it with remove. A post can have several tags. Tagging twice keeps one tag.
| Name | Required | Description | Default |
|---|---|---|---|
| remove | No | Take the tag off instead. Default: false. | |
| tag_id | Yes | Tag ID from list_post_tags or create_post_tag. | |
| post_id | Yes | Post ID from list_posts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true and destructiveHint=false; the description adds concrete meaning by saying a post can have several tags and tagging twice keeps one tag. It does not cover permissions or error behavior, but with annotations present this is useful added context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loads the add/remove action, but the first two sentences partly repeat the same idea. The behavioral sentences earn their place, so it is efficient overall but not maximally tight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple three-parameter mutation with rich annotations and no output schema, the description covers scope (draft/published), remove behavior, multiple tags, and idempotency. Nothing critical for correct invocation appears missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so post_id, tag_id, and remove are already documented. The description only echoes that remove takes the tag off and that tag_id refers to one of your post tags, adding little beyond what the schema provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Add a tag to a post, or take it off') and clarifies that it assigns existing post tags to draft or published posts. This implicitly separates it from create_post_tag (which creates a tag) and tag_subscribers (which targets subscribers), so an agent can distinguish it from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains the remove parameter and that it works on draft or published posts, but it does not explicitly say when to choose tag_post over create_post_tag or list_post_tags, nor does it name alternatives. Usage is implied rather than fully guided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tag_subscribersTag subscribersAInspect
Put a tag on subscribers by email, or take it off.
Adds one of your subscriber tags to up to 50 subscribers, or removes it with remove. Emails not on your list come back in not_found and nothing else fails. A subscriber added a minute ago may not be findable yet; try again shortly.
| Name | Required | Description | Default |
|---|---|---|---|
| emails | Yes | Subscribers' email addresses, up to 50. | |
| remove | No | Take the tag off instead. Default: false. | |
| tag_id | Yes | Tag ID from list_subscriber_tags or create_subscriber_tag. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Well beyond the annotations, it discloses partial-success semantics ('Emails not on your list come back in not_found and nothing else fails') and eventual consistency ('A subscriber added a minute ago may not be findable yet; try again shortly'), which is exactly the retry-relevant behavior an agent needs. It doesn't cover permissions or what removing a tag from an untagged subscriber does.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight paragraphs, front-loaded with the core operation, then the batch/failure behavior, then the retry caveat. Every sentence carries distinct information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 3-parameter mutation with no output schema, the description covers batching limits, partial failure, and timing hazards. It stops short of describing the full return shape or any permission requirements, but nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3, but the description reinforces the two semantics that matter most: the 50-subscriber cap and the `remove` toggle direction. It adds meaning rather than duplicating the schema verbatim.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening line states a specific verb and resource: 'Put a tag on subscribers by email, or take it off.' It also distinguishes itself from siblings like list_subscriber_tags, create_subscriber_tag, and tag_post by making clear this operates on subscribers (not posts) and only assigns/removes an existing tag rather than creating one.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives concrete usage context: pass `remove` to take the tag off, and it points at the failure case to expect. It doesn't explicitly contrast with tag_post or add_subscriber, but the subscriber-tag scope makes the intended use unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unpublish_postUnpublish postADestructiveInspect
Take a published post off the web and back to drafts.
Turns a published post back into a draft, as Unpublish in the editor does: it leaves your site, archive and the Substack app, and its link stops working. Comments and stats stay with the draft. Emails already sent stay in inboxes. Publish it again with publish_post. A post that is not published returns an error.
| Name | Required | Description | Default |
|---|---|---|---|
| post_id | Yes | Post ID from list_posts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructive=true, openWorld=true and idempotent=false; the description adds real value on top by disclosing concrete consequences — the post leaves the site, archive and app, its link stops working, comments and stats are retained on the draft, already-sent emails stay in inboxes, and re-unpublishing errors out. That is precisely the extra context annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core action is front-loaded in the first sentence and every subsequent sentence supplies a distinct, decision-relevant fact (visibility effects, data retention, email caveat, reversal path, error condition). No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter mutation with no output schema, the description covers the effect, side effects, reversibility, retained data and failure mode, and the annotations cover the safety profile. Nothing an agent needs in order to call it safely is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single required parameter, post_id, and schema coverage is 100% with the schema itself pointing at list_posts as the source. The description adds no further semantics about the identifier, which is the expected baseline when the schema already carries the burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource+result: 'Take a published post off the web and back to drafts,' then immediately reinforces it with 'Turns a published post back into a draft.' An agent can distinguish this from publish_post, delete_post, cancel_scheduled_post and update_draft without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the reverse operation explicitly ('Publish it again with publish_post') and gives a hard precondition ('A post that is not published returns an error'), which effectively excludes drafts and scheduled posts. It never explicitly contrasts with delete_post for permanent removal or cancel_scheduled_post, so the routing guidance is strong but not complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_draftUpdate draftAInspect
Change the title, subtitle, body or audience of a draft.
Changes the fields you pass and leaves the others as they are. body_markdown replaces the whole body. Drafts and scheduled posts only: a published post returns an error. Nothing reaches your subscribers, so it runs without asking.
| Name | Required | Description | Default |
|---|---|---|---|
| fields | Yes | JSON object with any of title, subtitle, body_markdown, audience, e.g. {"title": "New title"}. | |
| post_id | Yes | Post ID from list_posts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the safety profile (readOnlyHint=false, destructiveHint=false), and the description adds real behavioral context beyond them: partial-update merge semantics, that body_markdown replaces the entire body, the error condition for published posts, and that no subscriber notification is triggered so confirmation can be skipped.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, each carrying distinct information — scope, merge semantics, applicability, and safety — with the core action front-loaded. No filler or restatement of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter mutation with no output schema, the description covers what changes, how partial updates behave, when the call fails, and whether confirmation is needed. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds meaning the schema lacks: the fields object is a patch (only passed fields change), and body_markdown is a full replacement rather than an append. It does not elaborate on the audience field's accepted values.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (change) and resource (draft) and enumerates the mutable fields: title, subtitle, body, audience. It is clear what the tool does, though it never names a sibling like create_draft or publish_post to sharpen the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete applicability boundary — 'Drafts and scheduled posts only: a published post returns an error' — which tells the agent when not to call it. It stops short of pointing to an alternative tool for the published-post case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
50 tool updates
v0.1.0- First observed
add_subscriber - First observed
cancel_scheduled_post - First observed
create_draft - First observed
create_post_tag - First observed
create_subscriber_tag - First observed
delete_comment - First observed
delete_post - First observed
duplicate_post - First observed
export_subscribers - First observed
follow_user - First observed
get_audience_insights - First observed
get_conversation - First observed
get_daily_stats - First observed
get_feed - First observed
get_post - First observed
get_post_engagement - First observed
get_post_stats - First observed
get_post_traffic - First observed
get_publication_stats - First observed
get_unread_counts - First observed
like_comment - First observed
like_post - First observed
list_activity - First observed
list_comments - First observed
list_conversations - First observed
list_note_replies - First observed
list_notes - First observed
list_post_tags - First observed
list_posts - First observed
list_recommendations - First observed
list_sections - First observed
list_subscriber_tags - First observed
list_subscribers - First observed
list_subscriptions - First observed
list_traffic_sources - First observed
pin_comment - First observed
publish_note - First observed
publish_post - First observed
recommend_publication - First observed
remove_comment - First observed
remove_subscriber - First observed
reply_to_comment - First observed
reply_to_note - First observed
schedule_post - First observed
search_substack - First observed
send_message - First observed
tag_post - First observed
tag_subscribers - First observed
unpublish_post - First observed
update_draft
TDQS
Scored across 50 tools
Despite the large surface, most tools target distinct resources and actions, and the descriptions clearly separate tricky pairs such as delete_comment vs remove_comment and post vs publication analytics. A few analytics/listing/export tools could still be confused at a glance, so it is not perfect.
Tool names consistently use snake_case verb_noun patterns such as list_posts, create_draft, publish_post, and tag_subscribers. Compound names like get_post_engagement and list_traffic_sources remain predictable and readable.
Fifty tools is excessive for an MCP surface, even for a broad platform like Substack. Many analytics, subscriber, tag, and comment variants are individually justified but collectively impose a high selection cost.
The surface covers the core lifecycle for posts, drafts, scheduling, publishing, subscribers, tags, comments, Notes, DMs, recommendations, search, and analytics. The main gap is that published posts cannot be edited directly without unpublishing first, and sections are list-only rather than fully managed.
Maintenance
Related MCP Connectors
- beehiivOAuthcom.beehiiv
Manage beehiiv newsletters, posts, podcasts, community, subscribers, and analytics.
Draft, schedule, and analyze content for Substack, Medium, LinkedIn, X, Bluesky, and Threads.
Manage WordPress blogs and WooCommerce shops from Claude, ChatGPT, Cursor and other MCP apps.
Agent social posting via your logged-in Chrome. Remote MCP + OAuth. Not clawpost.dev.
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 gradedqualityDmaintenanceCreate, manage, and publish Substack posts with full rich text formatting directly from Claude Desktop or any MCP-compatible client.26 npm25MIT
- AlicenseNot gradedqualityDmaintenanceEnables managing Substack publications: publish Notes and posts, manage drafts, pull analytics, and read any publication's public feed via MCP.MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to draft, publish, and schedule posts on Substack, bypassing the lack of an official publishing API.134-