Skip to main content
Glama

substack-mcp

一个用于 Substack 的 MCP 服务器,让 AI 助手能够读取你的发布数据并管理草稿。

设计安全: 此服务器可以创建和编辑草稿,但无法发布或删除文章。你始终需要通过 Substack 编辑器手动审核并发布。

工具

读取

工具

描述

get_subscriber_count

获取你发布内容的当前订阅者数量

list_published_posts

列出已发布的文章(支持分页)

list_drafts

列出草稿文章

get_post

通过 ID 获取已发布文章的完整内容

get_draft

通过 ID 获取草稿的完整内容

get_post_comments

获取已发布文章的评论

写入

工具

描述

create_draft

从 Markdown 创建新草稿

update_draft

更新现有草稿(仅限未发布)

upload_image

上传图片到 Substack 的 CDN

create_note

发布 Substack 笔记(短文,立即发布)

create_note_with_link

发布带有链接卡片附件的笔记

特意排除的功能

  • 发布文章 — 发布长文应是人类的审慎行为

  • 删除 — 对 AI 工具而言破坏性过大

  • 定时发布 — 请使用 Substack 编辑器进行定时发布

Related MCP server: substack-mcp

设置

1. 获取凭据

在浏览器中打开你的 Substack,然后:

  1. 会话令牌 (Session token): 导航到你的发布页面,打开开发者工具 (DevTools) → Application → Cookies → 复制 connect.sid 的值(以 s%3A 开头的 URL 编码字符串)

  2. 用户 ID (User ID): 在开发者工具控制台中运行:fetch('/api/v1/archive?sort=new&limit=1').then(r=>r.json()).then(d=>console.log(d[0]?.publishedBylines?.[0]?.id))

  3. 发布 URL (Publication URL): 你的 Substack URL,如果使用了自定义域名,请包含该域名(例如 https://newsletter.yourdomain.com 或 https://yourblog.substack.com)

2. 配置你的 MCP 客户端

Claude Desktop

添加到你的 claude_desktop_config.json:

{
  "mcpServers": {
    "substack": {
      "command": "npx",
      "args": ["-y", "@conorbronsdon/substack-mcp"],
      "env": {
        "SUBSTACK_PUBLICATION_URL": "https://yourblog.substack.com",
        "SUBSTACK_SESSION_TOKEN": "your-session-token",
        "SUBSTACK_USER_ID": "your-user-id"
      }
    }
  }
}

Claude Code

添加到你的 .mcp.json:

{
  "mcpServers": {
    "substack": {
      "command": "npx",
      "args": ["-y", "@conorbronsdon/substack-mcp"],
      "env": {
        "SUBSTACK_PUBLICATION_URL": "https://yourblog.substack.com",
        "SUBSTACK_SESSION_TOKEN": "your-session-token",
        "SUBSTACK_USER_ID": "your-user-id"
      }
    }
  }
}

3. 验证

询问你的 AI 助手:“我有多少个 Substack 订阅者?”

令牌过期

Substack 会话令牌会定期过期(通常约为 90 天)。如果遇到身份验证错误,请从浏览器中获取新的 connect.sid cookie 并更新环境变量。复制 cookie 时请确保已禁用广告拦截器。

Markdown 支持

create_draft 和 update_draft 工具接受 Markdown 并将其转换为 Substack 的原生格式。支持:

  • 段落、标题 (h1–h6)

  • 粗体、斜体、inline code

  • 链接

  • 图片

  • 无序和有序列表

  • 代码块(带语言标识)

  • 引用块

  • 水平分割线

重要说明

  • 此服务器使用 Substack 的非官方 API。如果 Substack 更改其端点,此服务可能会失效。

  • 会话令牌以 cookie 形式发送。请妥善保管你的 SUBSTACK_SESSION_TOKEN。

  • 服务器会在启动时验证身份验证,如果你的令牌已过期,它将立即报错。

开发

git clone https://github.com/conorbronsdon/substack-mcp.git
cd substack-mcp
npm install
npm run build

本地运行:

SUBSTACK_PUBLICATION_URL=https://yourblog.substack.com \
SUBSTACK_SESSION_TOKEN=your-token \
SUBSTACK_USER_ID=your-id \
npm start

免责声明

本账户所表达的所有观点、意见和陈述均仅代表我个人,并以个人身份作出。它们不反映,也不应被解释为反映 Modular 的观点、立场或政策。本账户与 Modular 没有任何关联、授权或背书。

许可证

MIT

Available Tools

34 tools
add_free_subscriberA

Add one explicitly opted-in reader to this publication's free newsletter. Changes email distribution: future newsletter emails may be delivered. Requires verified newsletter consent; never infer consent from a meeting alone. Dry-run by default; set dry_run=false to write. Set send_welcome_email=true to request Substack's welcome email for a new addition; delivery is not verified. Never grants paid access or overrides suppression. Existing members are skipped. An unverified result MUST be reconciled using get_subscriber, not automatically retried. Automated callers must persist an attempt ledger BEFORE invoking this tool; in-memory duplicate protection does not survive restarts or separate HTTP sessions.

ParametersJSON Schema
NameRequiredDescriptionDefault
emailYes
dry_runNo
consent_evidenceNoRequired for a live add: the source reference and timestamp of this email address's explicit newsletter opt-in. Retain the underlying evidence privately; this field records caller attestation, not independent proof.
consent_confirmedYes
send_welcome_emailNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteYes
emailYes
statusYes
subscriberNo
publicationYes
consent_evidenceNo

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavioral context beyond the annotations: it changes future email distribution, default dry-run behavior, welcome email delivery is unverified, it never grants paid access or overrides suppression, existing members are skipped, and automated callers must persist an attempt ledger before invoking. These are non-obvious effects an agent could not infer from readOnlyHint or destructiveHint alone.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place: it opens with the core operation, then covers side effects, consent requirements, dry-run behavior, failure handling, and cross-session persistence. There is no filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has an output schema and five parameters including nested consent evidence, the description is complete: it covers prerequisites, side effects, reconciliation, duplicate protection, and non-idempotency. Nothing needed for safe invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 20%, and the description compensates by explaining dry_run, send_welcome_email, and the consent requirement. consent_evidence already has its own schema description, and email is self-explanatory. The description therefore adds meaning to the most behavior-critical parameters even though not every parameter is individually discussed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a precise verb and resource: 'Add one explicitly opted-in reader to this publication's free newsletter.' It also scopes the operation to free access and explicitly says it 'Never grants paid access,' which distinguishes it from any subscription or payment-related sibling tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives concrete usage rules: requires verified newsletter consent, never infer consent from a meeting, dry-run by default with dry_run=false to write, and existing members are skipped. It also names the right reconciliation path: 'An unverified result MUST be reconciled using get_subscriber, not automatically retried.'

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_draftA

Create a new draft post. Accepts markdown body which is converted to Substack's format. Does NOT publish — creates a draft only.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyNoPost body in markdown format
titleYesPost title
audienceNoWho can see this posteveryone
subtitleNoPost subtitle
allow_unsupportedNoAcknowledge conversion diagnostics and retain unsupported Markdown literally in this private draft

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
titleNo
messageYes
unsupported_nodesYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only indicate readOnlyHint=false, destructiveHint=false, and openWorldHint=false. The description adds meaningful behavioral context beyond that: it accepts markdown and converts it to Substack's format, and it creates a draft without publishing. This helps the agent understand side effects and scope without contradicting 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.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with no filler. The primary action and the most important caveat ('Does NOT publish') are front-loaded, and the markdown conversion detail earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a create tool with five parameters, a full output schema, and annotations covering the safety profile, the description is sufficient: it names the resource, the format conversion, and the non-publishing behavior. It could be slightly more complete by explicitly distinguishing from update_draft, but that gap is minor.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds extra meaning to the body parameter ('converted to Substack's format'), which enriches what the schema says. It doesn't detail every parameter, but the schema already covers those well.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('Create a new draft post') on a specific resource, and explicitly distinguishes it from publishing by saying 'Does NOT publish — creates a draft only.' The word 'new' also differentiates it from sibling tools like update_draft and export_draft.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly implies when to use the tool: to create a draft rather than publish. It also states an explicit exclusion ('Does NOT publish'). However, it does not explicitly name alternatives such as update_draft for existing drafts or create_note for notes, so it stops short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_noteA

Create a Substack Note (short-form content). Accepts markdown text. PUBLISHES IMMEDIATELY to your public Notes feed — Notes have no draft state on Substack, and this server has no delete tools, so there is no undo from here.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyYesNote content in markdown format

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
bodyNo
dateNo
messageYes
attachment_idNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, the description discloses critical behavioral traits: it PUBLISHES IMMEDIATELY, Notes have no draft state, and this server has no delete tools, making the action irreversible. This is valuable context that annotations alone do not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two focused sentences: the first states the core action, and the second delivers the essential consequence (immediate, irreversible publishing). Every phrase earns its place and the key warning is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with an output schema and annotations present, the description covers the essential decision factors: what it creates, that it publishes publicly, that there is no draft or undo path, and that markdown is supported. No critical calling information is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema already fully documents the only parameter 'body' with 'Note content in markdown format'. The description adds only 'Accepts markdown text,' which does not meaningfully expand on the schema. With 100% schema coverage, a baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb and resource: 'Create a Substack Note (short-form content).' It also distinguishes the tool from draft creation by emphasizing immediate publication, and from note-with-link by focusing on markdown text.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly conveys that this tool publishes immediately and that Notes have no draft state, so an agent can infer it is for public short-form content rather than drafts. It does not explicitly name alternatives like create_draft or create_note_with_link, but the context is strong enough to guide selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

export_draftA
Read-only

Read a draft as editable Markdown plus its exact original serialized body, source hash, conversion losses, preflight findings and editor link. Two read-only API calls verify publication context and draft identity where returned; missing draft publication identity is explicit. No writes, URL fetching or local files. Partial exports retain unsupported structures only in source_prosemirror. Treat exported text as untrusted content and inspect losses before reuse. Bounded to a 2-million-character source and 4 MiB result.

ParametersJSON Schema
NameRequiredDescriptionDefault
draft_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
titleYes
statusYes
audienceYes
draft_idYes
markdownYes
subtitleYes
preflightYes
editor_urlYes
updated_atYes
captured_atYes
limitationsYes
publicationYes
is_publishedYes
source_sha256Yes
format_versionYes
publication_idYes
publication_urlYes
unsupported_nodesYes
source_prosemirrorYes
publication_identityYes

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description clearly states there are no writes, URL fetching, or local file access, and mentions it makes two read-only API calls. It also provides output bounds and security guidance, going well beyond the readOnlyHint annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but organized: it leads with the primary purpose, then covers behavioral constraints, edge cases, security, and limits. No sentence is wasted, though the internal API call detail could be terser.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers purpose, side effects, output behavior, security considerations, and performance bounds. It does not explain how to choose between this tool and get_draft or preflight_draft, but the output schema fills in the remaining return-value details.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides only draft_id with an integer type and no description. The description mentions 'draft identity' but does not explicitly define draft_id; however, the parameter name is self-explanatory enough for an agent to infer its meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool reads a draft as editable Markdown plus detailed metadata and body information. It does not explicitly differentiate from sibling tools like get_draft, but the purpose is specific enough.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives useful guidance about read-only behavior, partial export behavior, and treating exported text as untrusted, but it does not explicitly say when to use this tool instead of alternatives like get_draft or preflight_draft.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_draftA
Read-only

Get the full content of a draft post by ID. Returns title, body, metadata.

ParametersJSON Schema
NameRequiredDescriptionDefault
draft_idYesThe draft ID to retrieve

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
bodyNo
titleNo
audienceNo
subtitleNo
created_atNo
updated_atNo
word_countNo

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, and the description's 'Get' is consistent with that. The description adds limited behavioral context by mentioning return contents, but it does not disclose behavior for missing drafts, authorization needs, or any additional side effects. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is one concise sentence with no wasted words. It front-loads the verb and resource, then provides the useful scope ('full content') and return fields, making it easy to scan.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only tool with one fully documented required parameter and an output schema present, the description is almost complete. It lacks an explicit pointer about when to choose this over closely related siblings like export_draft or list_drafts, but that gap is minor given the clarity of the rest.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 100% description coverage for the single parameter, already stating 'The draft ID to retrieve'. The description's 'by ID' adds no new semantic 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.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific verb ('Get'), resource ('draft post'), and selection criterion ('by ID'), and further specifies 'full content' with return fields ('title, body, metadata'). This distinguishes it from siblings like list_drafts, get_post, and export_draft.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use the tool: when the agent has a draft_id and needs the full content of a specific draft. However, it does not explicitly name alternatives or exclusions, such as when to prefer list_drafts or export_draft, so guidance is only implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_growth_sourcesA
Read-only

Read growth sources for an ordered inclusive date range of at most 366 days ending no later than tomorrow UTC. One authenticated read, or two when include_events is true; no writes. Optional events report available items or an unavailable reason without discarding sources; authentication failure still stops the call. Returns up to 20 top-level sources by default, at most 50, in Substack's users-descending order. Processes at most 500 nodes, depth 3 and 400 timeseries points per metric; truncation flags identify cut data. total_sources and has_more describe only the unpaginated response's top-level array, not all upstream sources or complete attribution.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
to_dateYes
from_dateYes
include_eventsNo
include_timeseriesNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
eventsNo
totalsYes
sourcesYes
to_dateYes
has_moreYes
returnedYes
from_dateYes
truncatedYes
publicationYes
total_sourcesYes

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the readOnlyHint annotation. It discloses the number of authenticated reads (1 or 2 with include_events), explicitly states 'no writes', and details edge cases: authentication failure stops the call, truncation flags identify cut data, and the scope of total_sources/has_more. It also explains the processing limits (500 nodes, depth 3, 400 timeseries points) and the default/max return count. This is rich behavioral context that the annotation alone does not provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single dense paragraph that front-loads the core purpose and constraints before delving into details. Every sentence carries information – no filler. It could be improved with bullet points for readability, but it is appropriately sized given the number of behavioral details it conveys. It is efficient and structured logically: purpose → read count → events → limits → truncation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has an output schema, so the description need not explain return values. Given that, the description is remarkably complete: it covers authentication, read counts, date range constraints, pagination/limit behavior, event behavior, truncation flags, and the scope of summary fields. It even notes that authentication failure stops the call. There is no obvious missing information an agent would need to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With schema description coverage at 0%, the description must compensate. It explains from_date/to_date via 'ordered inclusive date range', limit via 'up to 20 top-level sources by default, at most 50', and include_events via 'two when include_events is true' and the optional events report. However, include_timeseries is not explicitly described – the mention of '400 timeseries points per metric' hints at it but does not clarify the parameter's role. The description covers most parameters but leaves include_timeseries implicit, so it only partially compensates for the missing schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Read growth sources' – a specific verb and resource – and adds a precise scope (ordered inclusive date range, ≤366 days, ending ≤tomorrow UTC). This distinguishes it from sibling tools like get_publication_stats or get_post_analytics, which target different metrics. The purpose is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

While the description clearly states what the tool does and its constraints (date range, limits, events), it does not explicitly tell the agent when to choose this over alternatives, nor does it mention any sibling tools or exclusions. The agent must infer that growth sources are distinct from analytics or subscriber tools. There is no 'use this instead of X when...' guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_note_threadA
Read-only

Anonymous public Note thread read, no credentials sent. Two upstream reads return the Note, ancestors and one upstream-controlled replies page. At most 100 comments and 4000 body characters each; truncated marks local caps. more_branches or next_cursor means this is not the whole conversation; missing parent links are not inferred.

ParametersJSON Schema
NameRequiredDescriptionDefault
cursorNo
comment_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
rootYes
branchesYes
ancestorsYes
truncatedYes
next_cursorYes
completenessYes
more_branchesYes

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation, it discloses concrete behavioral constraints: two upstream reads, an upstream-controlled replies page, 100-comment and 4000-character caps, truncation semantics, and the meaning of more_branches/next_cursor. It also warns that missing parent links are not inferred.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three dense sentences with no filler. The most important facts (anonymous, public, no credentials) are front-loaded, and each sentence adds distinct operational value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple read-only nature, annotations, and a present output schema, the description covers most of what an agent needs: scope, safety, limits, truncation, and incomplete-conversation signals. The only notable gap is input cursor usage, which is somewhat inferable from next_cursor.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for the undocumented comment_id and cursor parameters. It mentions next_cursor in the output context but never explains the input cursor parameter or how comment_id identifies the thread.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with 'Anonymous public Note thread read', a specific verb plus resource, and immediately clarifies that no credentials are sent. This distinguishes it from authenticated or post-comment tools without needing to open the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly signals when this tool applies: anonymous public Note threads with no credentials. It does not explicitly name sibling alternatives or state when not to use it, so it stops 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.

get_postA
Read-only

Get the full content of a published post by ID. Returns title, body HTML, metadata.

ParametersJSON Schema
NameRequiredDescriptionDefault
post_idYesThe post ID to retrieve

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
urlNo
slugNo
titleNo
audienceNo
subtitleNo
body_htmlNo
post_dateNo
word_countNo

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotation indicates readOnlyHint, which covers the read-only nature. The description adds a constraint that the post must be published, but does not disclose other behavioral aspects such as error handling or side effects. Given the presence of the annotation, this is adequate but not exceptional.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, consisting of a single sentence that states the action and the expected return data. It is well-structured and front-loaded, making it easy to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple retrieval operation, the description is sufficiently complete: it names the input and output content. It does not address error cases or edge conditions, but given the simplicity and the presence of an output schema, this is not a significant gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema fully describes the only parameter (post_id) with a clear description. The tool description does not add any additional meaning to this parameter, so a baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: retrieving the full content of a published post by ID, and explicitly mentions the returned data (title, body HTML, metadata). It distinguishes itself from sibling tools by specifying 'published post', making its purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implicitly provides usage guidance by specifying that it operates on published posts, which contrasts with draft-related tools. However, it does not explicitly mention alternatives or when to prefer this tool over others, so it falls 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.

get_post_analyticsA
Read-only

Get performance stats (views, emails sent/delivered/opened, signups, subscribes, estimated value, comments, reactions) for a published post by ID. First reads the exact post detail (one authenticated read) and requires a published post with a post date. A draft, 403/404, malformed detail, ID mismatch, or other detail error except 401/429 triggers a scan of at most the 500 most recent published posts with up to 10 more reads. No writes. A feed-scan miss is bounded, not proof the post never existed; separate pages can shift. stats_available is false when a found post has no statistics. Per-post rates are upstream 0–1 fractions and are not added to this legacy projection.

ParametersJSON Schema
NameRequiredDescriptionDefault
post_idYesThe published post ID to get stats for

Output Schema

ParametersJSON Schema
NameRequiredDescription
idNo
noteNo
sentNo
foundYes
titleNo
viewsNo
openedNo
sourceNo
post_idNo
scannedNo
signupsNo
deliveredNo
post_dateNo
subscribesNo
feed_cappedNo
comment_countNo
search_resultNo
reaction_countNo
estimated_valueNo
stats_availableNo
detail_fallback_reasonNo

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes far beyond the readOnlyHint annotation by disclosing the one-read success path, the up-to-10-read scan fallback, the bounded semantics of a feed-scan miss, stats_available behavior, and the fact that per-post rates are upstream fractions. It also explicitly states 'No writes,' which is consistent with readOnlyHint=true.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action and immediately scannable metrics list. The trailing edge-case details—fallback scan limits, miss semantics, stats_available, and rate fractions—are dense but each adds necessary behavioral context. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return values need not be spelled out. The description covers prerequisites, error-triggered fallback behavior, read limits, miss semantics, and special values like stats_available, making the tool's behavior fully predictable for an agent about to invoke it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already fully documents the single post_id parameter (100% coverage). The description reinforces that the ID must reference a published post and mentions ID mismatches, but it does not add new syntactic or format-level meaning beyond what the schema 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.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Get performance stats... for a published post by ID' and enumerates the exact metrics returned. It is unambiguous and implicitly distinguishes this per-post analytics tool from related siblings like get_publication_stats and get_post.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly states the required precondition ('requires a published post with a post date') and explains the fallback scan behavior for drafts and errors. However, it does not explicitly say when to prefer this tool over sibling analytics or retrieval 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_post_commentsA
Read-only

Get comments on a published post. Returns commenter name, comment body, date, and reaction counts.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax comments to return (default 20)
post_idYesThe post ID to get comments for

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The readOnlyHint annotation already covers the safety profile, and the description mentions returned data rather than side effects. However, it does not disclose behaviors such as pagination, ordering, or possible empty results, so transparency is adequate but not detailed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and information-dense, with exactly two sentences and no redundant phrasing. Every word contributes to understanding the tool's purpose or output.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read operation, the description sufficiently identifies the required post_id and the returned fields. The absence of an output schema is partially mitigated by listing expected fields, though details like sorting or pagination behavior are not mentioned.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema fully documents both parameters, including constraints, defaults, and descriptions. The tool description adds no additional semantic nuance beyond what the schema already provides, so this dimension is at baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the action ('Get'), the resource ('comments on a published post'), and the returned fields. The qualifier 'published' helps distinguish from draft-related sibling tools, making the purpose immediately identifiable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides no explicit guidance on when to use this tool versus alternatives, no named sibling tools, and no conditions or exclusions. The only contextual hint is 'published post', which is implicit rather than actionable guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_post_tagsA
Read-only

Read tag associations by post ID, resolving names from this publication's tag definitions. Includes hidden tags and preserves unresolved IDs. Returns 25 rows by default, at most 100, with local snapshot pagination. Each call makes up to three reads, including the full association and definition arrays; they are not an atomic snapshot. Empty associations do not verify post existence. Nonempty draft associations are not yet live-verified. Never assigns or removes tags.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
offsetNo
post_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
tagsYes
limitYes
totalYes
offsetYes
post_idYes
has_moreYes
returnedYes
paginationYes
next_offsetYes
publicationYes
post_identityYes
publication_idYes
pagination_noteYes
resolution_noteYes
resolution_scopeYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only provide readOnlyHint: true, so the description carries the behavioral disclosure burden. It goes far beyond that by revealing hidden tag inclusion, unresolved ID preservation, pagination limits, non-atomic multi-read behavior, and the caveat that empty or draft associations have verification limits. This is exemplary transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but efficient: every sentence adds a distinct piece of actionable information, and the core action is front-loaded. Caveats are packed without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given an output schema exists to describe return values and annotations declare read-only safety, the description fills the remaining gaps: pagination semantics, transactional behavior, hidden tags, and edge-case verification limits. An agent has enough context to correctly invoke this tool and interpret unusual behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It adds meaning to limit and offset with 'Returns 25 rows by default, at most 100, with local snapshot pagination', and post_id is implied by 'by post ID'. It does not exhaustively bind every parameter, but it covers the non-obvious runtime semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb-resource pair: 'Read tag associations by post ID', and clarifies it resolves names from tag definitions, includes hidden tags, and preserves unresolved IDs. This clearly differentiates it from siblings like list_publication_tags or get_post.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the usage context clear: call this when you need tag associations for a specific post. It also states what the tool will not do ('Never assigns or removes tags'), which helps avoid using it for mutations, though it does not name alternative sibling tools explicitly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_profile_feedA
Read-only

Anonymous public profile feed, no credentials sent. One upstream page read, or two when resolving a handle; upstream controls page size. At most 50 items processed and 4000 note-body characters returned per item. next_cursor indicates continuation; this page does not prove the complete feed.

ParametersJSON Schema
NameRequiredDescriptionDefault
cursorNo
handleNo
user_idNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
user_idYes
has_moreYes
returnedYes
next_cursorYes

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavior beyond the readOnlyHint annotation: no credentials are sent, upstream page-read counts, upstream-controlled page size, item and character limits, and cursor semantics. These details give the agent an accurate mental model of side effects and pagination.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact sentences deliver high-value constraints without filler. The core qualifier 'anonymous public profile feed' is front-loaded, and each sentence adds a distinct behavioral fact.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is strong on behavior, and the presence of an output schema reduces the need to document return values. However, it omits essential parameter-selection guidance for a tool with 0% schema-described parameters, leaving an agent uncertain how to form a valid request.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for 3 parameters, so the description must compensate by explaining cursor, handle, and user_id. It does not clarify whether these are alternatives, combinable, or which is required in practice; the only cursor mention is output-oriented ('next_cursor indicates continuation').

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the resource as an 'anonymous public profile feed' and the function as retrieving that feed. It adds useful qualifiers like 'no credentials sent' and processing limits, but it does not explicitly contrast siblings such as get_user_profile or list_public_posts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear context: this tool is for anonymous, public, unauthenticated profile feed retrieval. It does not state exclusions or point to alternatives, so it leaves some routing to inference rather than fully selecting among siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_publicationA
Read-only

Read projected identity and selected settings for this publication. Verifies the returned publication host; does not verify your account identity or admin role. Missing API fields are named explicitly. No changes are made.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
publicationYes
identity_scopeYes
publication_urlYes
fields_not_returned_by_apiYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotation indicates readOnlyHint, and the description reinforces this by stating 'No changes are made.' It additionally reveals verification behavior and how missing API fields are handled, providing useful behavioral context beyond the annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is brief and to the point, consisting of two sentences that cover the purpose, verification, and read-only nature without unnecessary detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple nature of the tool (no parameters, read-only), the description provides enough context about what it reads and how it behaves. It could mention the output format, but the description already notes that missing fields are named explicitly, which is helpful. Overall, it is complete for its complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has no parameters, so all parameters are documented (none). The description does not add parameter-specific information, but this is not needed. Baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's function: reading projected identity and selected settings for the publication. It uses a specific verb ('read') and identifies the resource ('publication'), distinguishing it from sibling tools that deal with posts, drafts, or notes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not explicitly mention when to use this tool over alternatives, but it provides context about what it verifies (host) and what it does not (account identity, admin role). This gives some implicit guidance, but lacks explicit comparison to sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_publication_statsA
Read-only

Read dashboard summary and summary-v2 for a trailing range of 1–365 days (default 30). Two authenticated reads, no writes. Each metric states its unit, window, source and missing state. Summary windows beyond named Last30Days fields are undocumented; summary values are not reconciled with summary-v2. A failed group is unavailable, never zero. ARR currency is not reported. Both groups unavailable with HTTP 403/404 means analytics access is unavailable.

ParametersJSON Schema
NameRequiredDescriptionDefault
range_daysNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
rangeYes
summaryYes
range_daysYes
publicationYes

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description far exceeds what readOnlyHint=true provides: it discloses two authenticated reads, per-metric unit/window/source/missing-state reporting, undocumented summary windows, non-reconciliation between summary and summary-v2, 'a failed group is unavailable, never zero' failure semantics, missing ARR currency, and the meaning of 403/404 on both groups. This is exactly the kind of behavioral context an agent cannot derive from annotations. It aligns with, rather than contradicts, the readOnlyHint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Seven sentences, each carrying a distinct fact — purpose, auth mode, output format, two data caveats, failure semantics, currency gap, and error interpretation. No filler or restatement of schema fields, and the primary action is front-loaded in the first sentence.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema covers return shape, and annotations cover safety, so the description's job was to cover quirks — which it does thoroughly. Minor gaps remain: the 'trailing' anchor date is unspecified, and there is no guidance on when to prefer summary over summary-v2. These are small enough that the tool is still callable correctly without them.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description carries the full burden for range_days. It adds the 'trailing' temporal semantics and states the range/default, but the bounds and default are already present in the input schema, and the anchor point for 'trailing' (from the current date?) is left unspecified. The compensation is adequate for a single simple parameter but not rich.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource — 'Read dashboard summary and summary-v2 for a trailing range of 1–365 days (default 30)' — making the tool's scope precise. It doesn't explicitly name a sibling to differentiate from (e.g., get_post_analytics or get_growth_sources), but 'dashboard summary' clearly implies publication-level analytics rather than post-level, which is distinct enough for an agent to disambiguate.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage context is implied through 'dashboard summary' — the agent can infer this is for publication-wide stats rather than per-post analytics — but there is no explicit when-to-use guidance, no exclusions, and no named alternatives despite 32 siblings. The 403/404 note is diagnostic, not routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_public_postA
Read-only

Anonymous public post read by allowlisted /p/ URL, no credentials or subscription entitlements sent. One upstream read; body_html is capped at 500000 UTF-8 bytes. body_status is a heuristic from audience and body presence, not proof of full access or completeness.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
slugNo
titleNo
audienceNo
restacksNo
subtitleNo
body_htmlYes
post_dateNo
wordcountNo
body_statusYes
canonical_urlNo
comment_countNo
body_truncatedYes
reaction_countNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, so the description adds extra value: it discloses a single upstream read, a 500000-byte cap on body_html, and that body_status is a heuristic rather than proof of access or completeness. These details go well beyond the annotation and materially change how an agent interprets results. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core action and then constraints. Every clause adds essential information (auth-free, one read, size cap, heuristic status). No redundancy, and the structure makes the tool's scope immediately clear.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (one parameter) and an existing output schema, the description covers all necessary context: what it reads, the URL type, the auth model, the response size limit, and the caveat on body_status. An agent has everything needed to call it correctly and interpret results aptly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% (no description in schema), but the tool description states the URL must be an 'allowlisted /p/ URL', giving semantic meaning beyond type and maxLength. This partially compensates for the missing schema description. It would be a 5 with examples or format details, but a 4 is appropriate given the single parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Anonymous public post read'. It further specifies the mechanism ('allowlisted /p/ URL') and clarifies that no credentials are used, which distinguishes it from authenticated tools like get_post or get_draft. The purpose is unambiguous and easily differentiated from siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly indicates this tool is for anonymous reads of public posts via /p/ URLs, which implies it should be used when no authentication is available or desired. It does not explicitly name alternatives or exclusion conditions, but the context (anonymous, allowlisted) strongly guides selection. A bit more direct routing to siblings would lift this to a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_sectionsA
Read-only

List your publication's sections (categories). Returns each section's id and name. Use a section id as section_id when creating or updating a draft to file it under that section.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotation already declares readOnlyHint=true, and the description adds that it returns id and name, which is consistent and sufficient. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences: first states purpose and output, second gives usage guidance. No unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple list tool with no parameters and no output schema, the description fully covers what the tool does, returns, and how to use it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

No parameters exist, so schema coverage is 100%. The description does not need to add parameter explanations, meeting the baseline for 0 parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'list' and the resource 'sections', and it distinguishes itself from sibling tools by focusing on listing categories.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides explicit guidance on using the section ID for drafts, which is the primary use case. However, it does not mention when not to use it, but that is acceptable for a simple list tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_subscriberA
Read-only

Look up a subscriber by exact email address. A listed free subscriber is a member even without paid access. Absence does not prove the address is eligible: Substack may suppress previous unsubscribes, and dashboard data can lag. Read-only; use to reconcile uncertain adds.

ParametersJSON Schema
NameRequiredDescriptionDefault
emailYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteYes
emailYes
last_syncYes
subscriberYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint, and the description adds material behavioral caveats: a listed free subscriber counts as a member, absence may be due to suppression or lag, and absence does not prove ineligibility. These go well beyond the annotation and help the agent interpret results correctly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four sentences, each earning its place: core lookup, membership semantics, data caveats, and usage. The main action is front-loaded; only the word 'Read-only' is redundant with the annotation, which is negligible.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Complete for a one-parameter read-only lookup. Output schema covers return shape, and the description covers matching behavior, data reliability caveats, and the intended reconciliation use case. Nothing needed 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.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description compensates by specifying 'exact email address,' which clarifies matching semantics beyond the schema's email format and maxLength. For a single self-describing parameter, this is sufficient.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action ('Look up a subscriber') with an exact-match criterion on email address, which distinguishes it from sibling listing tools like list_subscribers and get_subscriber_count. The resource and lookup semantics are unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear usage context: 'use to reconcile uncertain adds.' It does not explicitly name alternatives or state when not to use it, but the exact-email lookup and reconciliation purpose are enough for an agent to select it appropriately.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_subscriber_countA
Read-only

Get the current subscriber count for your Substack publication. Returns precision: 'exact' when the API reports a true count, 'approximate' when only Substack's rounded value is available (the real number is that or higher — render it hedged, e.g. '1,000+'), or 'unavailable' with count -1. Never treat an approximate value as exact.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteYes
countYes
precisionYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The readOnlyHint annotation already indicates this is a read-only operation. The description adds valuable behavioral context by explaining the precision field (exact/approximate/unavailable) and the explicit warning 'Never treat an approximate value as exact.' This goes beyond the basic annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded with the primary purpose. It includes necessary detail about precision handling but is slightly verbose with the example and repeated caution. However, it remains focused and easy to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description sufficiently covers the return value nuances, including all possible precision values and the meaning of count -1. While an output schema is indicated as present, the description alone provides enough context for typical usage. It does not mention error cases or edge conditions beyond the precision, but these are minor gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, and the input schema is an empty object. There are no parameter semantics to explain, so the description is fully sufficient. Schema coverage is 100% by definition.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action: 'Get the current subscriber count for your Substack publication.' It also explains the output precision semantics, making the purpose unambiguous. It distinguishes itself from sibling tools like list_subscribers or get_subscriber by focusing specifically on the aggregate count.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description does not provide any guidance on when to use this tool versus alternatives. It does not mention any conditions or contrasts with sibling tools like list_subscribers or get_subscriber, leaving the decision to the agent to infer.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_user_profileA
Read-only

Anonymous public profile read by handle; one upstream read, no credentials sent. Returns minimal public fields and the primary publication when marked. Public profile data does not prove account ownership or access.

ParametersJSON Schema
NameRequiredDescriptionDefault
handleYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
bioYes
nameYes
handleYes
photo_urlYes
primary_publicationYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Even with readOnlyHint already present, the description adds meaningful behavioral detail: one upstream read, no credentials sent, returns minimal public fields, and includes the primary publication only when marked. It also surfaces a semantic limitation that public data does not prove ownership/access.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each earning its place: purpose and network/auth behavior, return scope, and an important caveat. The core purpose is front-loaded, and there is no repetition of schema or annotation fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a low-complexity tool: one parameter, a readOnlyHint annotation, and an output schema already present. The description covers auth posture, network behavior, return scope, and a key semantic caveat, leaving nothing essential for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description embeds the sole parameter ('by handle') into its purpose statement, clarifying that handle is the lookup key. The schema's pattern covers format. For a single self-describing parameter, this is adequate compensation, though not deeply enriched.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb-resource pair: 'Anonymous public profile read by handle.' It clearly distinguishes this tool from siblings like get_publication or get_subscriber by emphasizing public, anonymous profile data, and the handle-based lookup is explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description establishes clear context: use this for anonymous reads by handle with no credentials. It also warns that 'Public profile data does not prove account ownership or access,' which implicitly tells agents when not to rely on this tool. It does not explicitly name alternative sibling tools, 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.

list_draftsB
Read-only

List draft posts. Returns title, creation date, and audience for each draft.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax drafts to return (1-50; Substack rejects anything higher, so larger values are clamped)
offsetNoNumber of drafts to skip

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, and the description adds useful context by specifying the returned fields, which matters since there is no output schema. However, it does not disclose behavioral details like ordering, whether draft content/body is omitted, or pagination effects beyond what the schema already covers.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two short sentences with no filler. The first sentence gives verb and resource, and the second states the output shape. Every word contributes information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only list tool with fully documented optional parameters, this description is largely complete: it names the return fields even though no output schema exists. It could mention ordering or the lack of full draft content, but those are not essential for basic correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 100% description coverage: both limit and offset have meaningful descriptions. The tool description itself adds no parameter-level semantics, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('List draft posts') and enumerates the returned fields (title, creation date, audience). It is distinguishable from list_scheduled_posts by the word 'drafts', but it does not explicitly contrast itself with get_draft or export_draft.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to use list_drafts versus siblings like list_scheduled_posts, get_draft, or export_draft. The description only says what the tool does, with no conditions, exclusions, or alternative routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_publication_tagsA
Read-only

Read this publication's tag definitions. Includes hidden tags by default. Returns 25 rows by default, at most 100. Each call makes two reads (publication context and the full tag array), then paginates locally; results can change between calls. Validates publication identity and rejects malformed or oversized responses. Never creates or assigns tags.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
offsetNo
include_hiddenNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
tagsYes
limitYes
totalYes
offsetYes
has_moreYes
returnedYes
paginationYes
next_offsetYes
publicationYes
include_hiddenYes
publication_idYes
pagination_noteYes

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the readOnlyHint annotation by disclosing default row counts, maximum rows, local pagination behavior, the two reads per call, potential inconsistency between calls, validation behavior, and the explicit guarantee that it never creates or assigns tags. This is exemplary transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the core purpose, then adds behavioral details in a logical order. Every sentence carries useful information with no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists and the annotations provide the read-only guarantee, the description covers defaults, limits, pagination semantics, consistency caveats, validation, and side-effect absence. Nothing critical is missing for an agent to invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description explains default row counts and maximum rows, which map to limit, and mentions hidden tags by default, which maps to include_hidden. However, offset is not explicitly described; the mention of local pagination and changing results implies its behavior but does not fully compensate for the 0% schema description coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Read this publication's tag definitions.' It clearly identifies the operation and scope, and the detail about including hidden tags by default differentiates it from related tag tools like get_post_tags.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'this publication's tag definitions' gives clear context for when to use the tool, and the sibling list confirms there is a distinct get_post_tags tool for post-level tags. It does not explicitly name alternatives or exclusions, but the resource distinction is clear enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_public_postsA
Read-only

Anonymous public archive read, no credentials sent. One upstream read of 1–50 posts (default 12); sort and search are upstream controlled. A full page gives next_offset, but has_more is unknown because Substack returns no total. Public metadata does not prove access to post bodies.

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNonew
limitNo
queryNo
offsetNo
publication_urlNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
sortYes
limitYes
postsYes
queryYes
offsetYes
has_moreYes
returnedYes
next_offsetYes
publication_urlYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint, the description discloses that no credentials are sent, exactly one upstream read occurs, pagination provides next_offset but not reliable has_more, and public metadata does not guarantee body access. This is rich behavioral context with no contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, densely packed with relevant constraints and caveats, with the central purpose front-loaded. There is no filler or repetition of schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return-value details need no description. The description covers access mode, pagination behavior, and data-access limitations. The only minor gap is that publication_url is not explicitly identified as the target archive selector, though the parameter name makes it recoverable.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, but the description compensates for most parameters: limit bounds and default, sort and query behavior, and offset via next_offset are all addressed. publication_url is left to the schema name, but its meaning is clear enough.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening phrase 'Anonymous public archive read' states a specific verb, resource, and key differentiator (no credentials), clearly identifying the list operation. The count range and public scope further distinguish it from auth-required sibling tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clear context is provided: this is for reading public archives anonymously, so an agent can infer not to use it for subscriber-specific or draft operations. No explicit alternative or when-not condition is named, so it stops 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_published_postsA
Read-only

List published posts with pagination. Returns title, date, slug, and URL for each post.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax posts to return (1-50; Substack rejects anything higher, so larger values are clamped)
offsetNoNumber of posts to skip

Output Schema

ParametersJSON Schema
NameRequiredDescription
postsYes
totalNo

TDQS

A4.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The readOnlyHint annotation already covers safety; the description adds output details but does not go beyond that, so limited additional transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences, no fluff, and the key purpose is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and a clear mention of return fields, the description is complete for the intended use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Both parameters (limit and offset) have clear, detailed descriptions including clamping behavior, with full schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the action ('List published posts') and resource, distinguishing it from similar tools like list_scheduled_posts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context on pagination and return fields, but does not explicitly mention alternatives or when to prefer this over search_posts.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_scheduled_postsA
Read-only

List posts scheduled for future publication, soonest first. Read-only visibility into what's queued — scheduling itself is done in Substack's editor (this server does not schedule, publish, or delete long-form posts). Returns id, title, audience, and scheduled time (trigger_at).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax posts to return (1-50; Substack rejects anything higher, so larger values are clamped)
offsetNoNumber of posts to skip

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The readOnlyHint annotation is true and the description reinforces it by stating the tool does not schedule, publish, or delete posts. This fully discloses the tool's side effects (none).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded with purpose and read-only nature. It avoids fluff and clearly states the return fields, making every sentence valuable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

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 lists what is returned (id, title, audience, scheduled time). Combined with the read-only note and parameter descriptions, an agent has enough context to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema provides complete descriptions for both parameters (limit and offset), so the baseline is 3. The description adds no extra parameter-specific information beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the verb 'List' and resource 'posts scheduled for publication', with the ordering 'soonest first'. The read-only note and reference to scheduling in the editor distinguish it from sibling tools like list_published_posts and list_drafts.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says 'Read-only visibility into what's queued' and that scheduling itself is done in Substack's editor, clarifying when not to use this tool. It also mentions no publishing or deletion, providing clear boundaries.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_subscribersA
Read-only

Read a page of private subscriber email addresses and subscription IDs. Dashboard data may lag recent changes. Use get_subscriber for exact membership checks.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
offsetNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
lastSyncNo
subscribersYes

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The readOnlyHint annotation is reinforced by the non-destructive 'Read' wording. The description adds useful behavioral context about privacy and potential lag without contradicting the annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short, focused sentences with no redundant wording. Every clause adds value: the action, the data privacy, the lag caveat, and the alternative tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists, so output fields need no description. The privacy warning, lag caveat, and alternative-tool pointer give sufficient operational context for a straightforward paginated read operation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

limit and offset are not explicitly described, but the phrase 'Read a page' combined with the schema's defaults and bounds makes their pagination role clear enough. Slight extra explanation would be needed for full clarity, but the intent is unambiguous.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the operation ('Read a page'), the resource ('subscriber email addresses and subscription IDs'), and the privacy scope. It also distinguishes this from get_subscriber by directing exact membership checks there.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly tells agents when not to use this tool ('Use get_subscriber for exact membership checks') and warns about data lag, giving practical context for approximate/bulk membership listing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

plan_draft_updateA
Read-only

Read an unpublished draft and review proposed Markdown/metadata changes, bounded previews, conversion losses and preflight. Returns a receipt binding the observed state and exact payload for update_draft. No writes. Hashes check consistency, not human approval; stale detection is best-effort, not atomic.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyNo
titleNo
audienceNo
draft_idYes
subtitleNo
allow_unsupportedNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
changesYes
receiptYes
preflightYes
editor_urlYes
limitationsYes
changed_fieldsYes
format_versionYes
scheduling_policyYes
unsupported_nodesYes
proposed_markdown_previewYes
markdown_preview_truncatedYes
scheduling_fields_not_returnedYes

TDQS

A3.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the readOnlyHint annotation by adding 'No writes,' explaining the receipt binding observed state, and disclosing limitations: 'Hashes check consistency, not human approval; stale detection is best-effort, not atomic.' This is strong behavioral context that helps an agent trust and interpret the result.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact and front-loaded with the core purpose in the first sentence. Each sentence adds value, though the list 'bounded previews, conversion losses and preflight' is jargon-heavy and slightly awkward.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The safety profile, no-write guarantee, receipt semantics, and consistency caveats are well covered, and an output schema exists to describe return values. However, with 6 parameters and zero schema descriptions, the lack of parameter guidance is a real gap, and the relationship to preflight_draft is left implicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the burden of explaining parameters, but it never mentions draft_id, allow_unsupported, audience, or subtitle. 'Markdown/metadata changes' loosely hints at body/title/subtitle but doesn't clarify the important flags or defaults.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it reads/reviews an unpublished draft and proposed Markdown/metadata changes, and it distinguishes itself from update_draft by explicitly saying 'No writes' and returning a receipt for update_draft. However, the word 'preflight' overlaps with the sibling preflight_draft, so it doesn't fully separate itself from that tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'exact payload for update_draft' plus 'No writes' establishes clear context that this is a planning/preview step before updating a draft. It doesn't provide explicit when-not guidance or name alternatives such as preflight_draft or get_draft.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

preflight_draftA
Read-only

Read a draft and check title, audience, body structure, images and paywalls. Static review aid only: never modifies or publishes; does not guarantee rendering, link availability or publish readiness. Review the findings in Substack.

ParametersJSON Schema
NameRequiredDescriptionDefault
draft_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
countsYes
draft_idYes
findingsYes
editor_urlYes
limitationsYes
publicationYes
checks_passedYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description fully discloses that the tool is read-only and non-destructive, aligning with the readOnlyHint annotation and adding concrete details about what it does not guarantee.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, well-structured in three sentences, and covers the essential aspects without unnecessary verbosity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

It provides sufficient context about what the tool does, its limitations, and where to review results (Substack), making it complete given the output schema exists.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The only parameter, draft_id, is not described in the schema (0% coverage) and the description does not explicitly explain it beyond the tool's context, so it only partially compensates for the missing schema documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool reads a draft and checks specific aspects (title, audience, body structure, images, paywalls), making its purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly notes it is a static review aid that never modifies or publishes, and it clarifies limitations (no rendering/link/publish guarantees), guiding appropriate usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rank_postsA
Read-only

Rank posts by one metric from Substack's dashboard email statistics: views, opened, sent, open_rate, click_through_rate, signups, subscribes, estimated_value or post_date, descending or ascending. Returns 10 rows by default, at most 20 (Substack's page limit), with total and next_offset for continuation. One read; nothing is changed. Values are passed through as Substack reports them: this server does not recompute, fill in or estimate metrics, and Substack does not document rate denominators. Each row marks the ranked value as reported, null or absent; null and absent are not zero, and null rates can appear among numeric rows. For one post's stats by ID, use get_post_analytics.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
metricNoviews
offsetNo
directionNodesc

Output Schema

ParametersJSON Schema
NameRequiredDescription
rowsYes
limitYes
totalYes
metricYes
offsetYes
sourceYes
has_moreYes
orderingYes
returnedYes
directionYes
semanticsYes
next_offsetYes
publicationYes
unreported_in_pageYes

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation, the description adds critical behavior: it returns default/max rows, supports pagination via total and next_offset, passes values through unmodified, does not recompute metrics, and explains that null/absent are distinct from zero. These details prevent an agent from assuming the tool cleans or infers data.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is information-dense and front-loaded with the core purposeable immediately actionable. Every sentence contributes substantive value—purpose, pagination, read safety, data fidelity, null semantics, and sibling routing. The only minor redundancy is "One read; nothing is changed," which is short and reinforces rather than bloats.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists for return valuesстоит, the description covers everything needed to call the tool correctly: parameter meanings, defaults, limits, pagination, behavioral caveats, and alternative tool routing. It is complete enough for agent invocation without further inference.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description carries the full burden. It enumerates every metric enum value, explains the limit default and maximum, conveys offset continuation semantics through next_offset, and clarifies sort direction. It also provides important caveats about rate denominators and null handling that the schema alone could not convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: "Rank posts by one metric from Substack's dashboard email statistics." It enumerates the exact metrics and sort directions, making the tool's purpose unambiguous. The final sentence explicitly distinguishes it from get_post_analytics, which is the closely related sibling for single-post stats.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly states the intended use case—ranking multiple posts by a dashboard metric—and explicitly routes single-post stats to get_post_analytics. This gives the agent a direct decision rule for choosing between the two most similar tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_postsA
Read-only

Search this publication's published, draft, or scheduled archive using Substack's server-side query. One page per call, at most 50 results; use next_offset to continue. Matching/indexing is controlled by Substack, not a guaranteed full-text scan. Returns metadata only; get_post/get_draft fetch full content.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
queryYes
offsetNo
statusNopublished

Output Schema

ParametersJSON Schema
NameRequiredDescription
limitYes
postsYes
queryYes
totalYes
offsetYes
statusYes
has_moreYes
returnedYes
next_offsetYes
publicationYes
search_scopeYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation, the description discloses pagination behavior ('One page per call, at most 50 results'), continuation via 'next_offset', server-controlled indexing limitations, and metadata-only return values. These details set accurate expectations about how the search behaves and what it cannot guarantee.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three tight sentences with no filler. The main scoping is front-loaded, followed by pagination caveats and the metadata-only/content-fetching distinction.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the presence of an output schema and readOnly annotations, the description covers everything needed to call the tool correctly: scope, statuses, pagination limits, continuation mechanism, and search-quality caveats. The minor offset/next_offset wording ambiguity is resolvable from the input schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description compensates by explaining page size, pagination continuation, and the published/draft/scheduled statuses. However, it references 'next_offset' without explicitly mapping it to the schema's 'offset' parameter, and it leaves limit defaults to the schema's own constraints.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific action ('Search'), a precise resource ('this publication's published, draft, or scheduled archive'), and the mechanism ('Substack's server-side query'). It also explicitly distinguishes itself from content-fetching tools by stating 'Returns metadata only; get_post/get_draft fetch full content.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description routes full-content needs to get_post/get_draft and clarifies that search is not a guaranteed full-text scan. It does not explicitly contrast search_posts with the list_* siblings, so an agent must infer when to choose query-based search over simple enumeration.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_subscribersA
Read-only

Read one page of private subscriber data with Substack-side filters and sorting. One authenticated read, no writes; 1–50 rows (default 10). Returns email, subscription ID and interval by default; include selects extra fields. total_matching is Substack's count at read time; dashboard data may lag writes and pagination is not a snapshot. Search matching is controlled by Substack, and a result does not prove all current subscribers were captured.

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNocreated_desc
limitNo
offsetNo
searchNo
includeNo
created_beforeNoYYYY-MM-DD, exclusive: created before the start of this date; Substack's day boundary timezone is not verified
subscription_typesNo
activity_rating_maxNo
activity_rating_minNo
created_on_or_afterNoYYYY-MM-DD, created on or after this date

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteYes
sortYes
limitYes
offsetYes
has_moreYes
returnedYes
next_offsetYes
subscribersYes
total_matchingYes
applied_filtersYes

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation, it discloses row limits (1–50, default 10), default return fields, the include parameter behavior, total_matching caveats, pagination not being a snapshot, and that search matching is controlled by Substack. This is rich, non-obvious behavioral detail that helps an agent understand reliability and limitations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single paragraph with front-loaded purpose, followed by key constraints and caveats. It is information-dense but not bloated; every sentence contributes meaning. Could be slightly more structured but is appropriately concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 10-parameter tool with low schema coverage, the description covers critical behavioral aspects (return fields, pagination, search semantics) but leaves several parameters unexplained. An agent might still struggle to construct a correct request without additional parameter insight, though the tool name and schema provide some clues.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 20% (two date params have descriptions). The description mentions 'include selects extra fields' and implies filters/sorting, but it does not explain the meaning or usage of most parameters (sort, limit, offset, search, subscription_types, activity_rating_min/max, etc.). It fails to compensate for the low schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('read') and resource ('private subscriber data') with 'Substack-side filters and sorting'. This clearly distinguishes it from public post tools and establishes it as a read operation on subscriber data. Though it doesn't name siblings, the purpose is unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides context about server-side filtering and sorting, which implies when it should be used, but it does not explicitly state when to prefer this over alternatives like list_subscribers or get_subscriber. No exclusions or alternative routing are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_draftA
Destructive

Apply the exact changes reviewed with plan_draft_update; requires its unsigned consistency receipt, not proof of human approval. Rechecks publication, unpublished state and fingerprint before one PUT, then reads back. Rejects known stale or changed payloads. A read/write race remains. Inspect unverified/conflict outcomes in Substack; never automatically retry. Accepts Markdown; does not publish or schedule.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyNo
titleNo
receiptYes
audienceNo
draft_idYes
subtitleNo
allow_unsupportedNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
codeYes
statusYes
messageYes
draft_idYes
editor_urlYes
limitationsYes
publicationYes
changed_fieldsYes
format_versionYes
publication_idYes
request_statusYes
write_attemptsYes
mismatched_fieldsYes
unsupported_nodesYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations' destructive/read-only flags, it discloses the pre-PUT recheck, single PUT plus read-back, stale/changed-payload rejection, the remaining read/write race, and the need to inspect conflict outcomes manually. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Every sentence carries distinct operational information: precondition, verification, mutation, race, retry policy, format, and non-side-effects. No filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, race-prone update tool, the description covers preconditions, safety checks, failure behavior, retry prohibition, and side-effect boundaries. Output schema handles the return shape, so nothing needed for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the text explains the crucial receipt contract (unsigned consistency receipt, not approval), ties all editable fields to 'exact changes reviewed' in the plan, and notes Markdown support. It leaves audience and allow_unsupported implicit, but the plan-dependency makes their meaning recoverable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a precise action ('apply exact changes reviewed with plan_draft_update') and resource (draft), and explicitly excludes publishing/scheduling. This makes it immediately distinguishable from create_draft, plan_draft_update, and scheduling siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states the required precondition (receipt from plan_draft_update), clarifies that the receipt is not human approval, and tells the agent never to auto-retry. This is concrete when-to-use and when-not-to-act guidance tied to a named sibling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_draft_tagsA
Destructive

Assign or remove up to 20 distinct tag IDs per direction on a draft; refuses published or scheduled drafts before writing; not atomic — see draft_state_after. Dry-run defaults to true. Reads publication context, definitions, draft and associations (four reads); a live change rechecks the draft before writing, then reads draft state and associations after writing (up to seven reads total). Sends at most 40 sequential writes, each once, with no automatic retry. Only a confirmed request observed in readback while the draft remains unpublished is verified. Hidden tags are allowed and reported. Draft tags may become public when you later publish the draft in Substack.

ParametersJSON Schema
NameRequiredDescriptionDefault
addNo
removeNo
dry_runNo
draft_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteYes
dry_runYes
resultsYes
draft_idYes
publicationYes
write_attemptsYes
draft_state_afterYes

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the annotations (destructiveHint=true, readOnlyHint=false) by disclosing non-atomicity, a dry-run default of true, a precise read/write budget (four reads, up to seven reads total, at most 40 sequential writes with no retry), readback-based verification semantics, and the fact that hidden tags are allowed and may become public on publish. Each of these is an operational trait an agent cannot infer from the schema or annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first sentence, followed by cost- and safety-relevant behavior, and no sentence is fluff. The middle sentences on read counts and readback verification are dense and technical, arguably more operational detail than an agent needs purely for correct selection, so it is appropriately sized but slightly over-specified.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutating, non-idempotent tool whose output schema is available (covering return values), the description covers everything needed to call it correctly: accepted inputs, refusal conditions, dry-run semantics, failure/retry behavior, verification requirements, and post-publish consequences. No critical gap remains.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description carries the full parameter burden, and it mostly delivers: 'tag IDs' clarifies the add/remove arrays, 'up to 20 distinct ... per direction' adds a uniqueness constraint absent from the schema, and 'Dry-run defaults to true' explains dry_run's behavior. It does not offer concrete examples or edge-case handling (e.g., duplicate-add behavior), leaving a little to inference.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening clause 'Assign or remove up to 20 distinct tag IDs per direction on a draft' names a specific verb (assign/remove), resource (tag IDs on a draft), and a scope limit (20 per direction). This clearly distinguishes it from read-only siblings like get_post_tags and list_publication_tags, as well as the general-purpose update_draft.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states a hard refusal for 'published or scheduled drafts,' which implicitly defines when the tool is inapplicable, and notes that dry-run defaults to true, implying safe preview usage. However, it never names alternative tools (e.g., update_draft for non-tag draft edits, preflight_draft for preflight checks) or gives explicit when-to-use routing, so the guidance is implied rather than directive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

upload_imageA

Upload an image to Substack's CDN. Provide exactly one of image_base64 (a base64 data URI), image_path (a local file path) or image_url (a public HTTPS image to download first). Returns a hosted image URL that is publicly fetchable by anyone with the link (an unlisted asset — not attributed to you or added to your feed).

ParametersJSON Schema
NameRequiredDescriptionDefault
image_urlNoHTTPS URL of a PNG, JPEG, GIF, WebP or AVIF image to download and upload. Sent without Substack cookies; private, loopback, link-local, metadata and reserved destinations are refused at connection time and on every redirect (at most 3). Limits: 5 MB and 15 seconds; the bytes must match the declared type. Not available on every deployment. Mutually exclusive with image_base64 and image_path.
image_pathNoAbsolute path to a local image file (e.g., "/Users/me/pic.png"). Read and encoded automatically; MIME type inferred from the extension. Mutually exclusive with image_base64 and image_url.
image_base64NoBase64-encoded image with data URI prefix (e.g., "data:image/png;base64,..."). Mutually exclusive with image_path and image_url.

Output Schema

ParametersJSON Schema
NameRequiredDescription
image_urlYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only set flags (readOnlyHint=false, destructiveHint=false, openWorldHint=true). The description adds substantial behavioral context: the hosted URL is 'publicly fetchable by anyone with the link' and 'an unlisted asset — not attributed to you or added to your feed'. It also discloses important security details for `image_url` (sent without cookies, refusal of private/loopback destinations, redirect limit of 3). This goes well beyond what annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact but information-dense. The main action and the 'exactly one' rule appear in the first sentence, followed by necessary clarifications in parentheses. No fluff, but the parenthetical about `image_url` security is a slight digression; still, it's essential context. Overall well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has three mutually exclusive parameters, security constraints, and an output schema (which describes the return value). The description covers the input requirements, behavior, and return (hosted URL) sufficiently. There is no missing information that would prevent an agent from invoking it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already describes each parameter at 100% coverage. The description reinforces mutual exclusivity and adds practical constraints for `image_url` (5 MB, 15 seconds, type matching) and for `image_path` (MIME inferred from extension). This adds value beyond the schema without redundancy.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description states a specific verb ('Upload') and resource ('image to Substack's CDN'), which is clear and distinct from all sibling tools (export, get, list, create, etc.). No ambiguity about what this tool accomplishes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly mandates 'Provide exactly one of' the three input modes, which is a clear usage rule. It also notes that `image_url` is 'Not available on every deployment' and includes mutual-exclusivity language. However, it does not explicitly state when to prefer this tool over alternatives, though no sibling upload tool exists, so that gap is minor.

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.

  1. 10 tool updatesv1.3.0
    • Addedget_growth_sources
    • Addedget_note_thread
    • Changedget_post_analytics2 fields changed
      • addedOutput schema / properties / detail_fallback_reason
        Added value: +{
        +  "enum": [
        +    "not_found",
        +    "malformed",
        +    "id_mismatch",
        +    "forbidden",
        +    "not_published",
        +    "upstream_error"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / source
        Added value: +{
        +  "enum": [
        +    "post_detail",
        +    "published_feed_scan"
        +  ],
        +  "type": "string"
        +}
    • Addedget_profile_feed
    • Addedget_public_post
    • Addedget_publication_stats
    • Addedget_user_profile
    • Addedlist_public_posts
    • Addedsearch_subscribers
    • Addedupdate_draft_tags
  2. 3 tool updatesv1.2.0
    • Changedget_post_analytics4 fields changed
      • addedOutput schema / properties / feed_capped
        Added value: +{
        +  "type": [
        +    "boolean",
        +    "null"
        +  ]
        +}
      • addedOutput schema / properties / scanned
        Added value: +{
        +  "maximum": 9007199254740991,
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedOutput schema / properties / search_result
        Added value: +{
        +  "enum": [
        +    "archive_exhausted",
        +    "scan_bound_reached",
        +    "feed_incomplete"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / stats_available
        Added value: +{
        +  "type": "boolean"
        +}
    • Addedrank_posts
    • Changedupload_image3 fields changed
      • changedInput schema / properties / image_base64 / description
        Previous value: -"Base64-encoded image with data URI prefix (e.g., \"data:image/png;base64,...\"). Mutually exclusive with image_path."New value: +"Base64-encoded image with data URI prefix (e.g., \"data:image/png;base64,...\"). Mutually exclusive with image_path and image_url."
      • changedInput schema / properties / image_path / description
        Previous value: -"Absolute path to a local image file (e.g., \"/Users/me/pic.png\"). Read and encoded automatically; MIME type inferred from the extension. Mutually exclusive with image_base64."New value: +"Absolute path to a local image file (e.g., \"/Users/me/pic.png\"). Read and encoded automatically; MIME type inferred from the extension. Mutually exclusive with image_base64 and image_url."
      • addedInput schema / properties / image_url
        Added value: +{
        +  "description": "HTTPS URL of a PNG, JPEG, GIF, WebP or AVIF image to download and upload. Sent without Substack cookies; private, loopback, link-local, metadata and reserved destinations are refused at connection time and on every redirect (at most 3). Limits: 5 MB and 15 seconds; the bytes must match the declared type. Not available on every deployment. Mutually exclusive with image_base64 and image_path.",
        +  "maxLength": 2048,
        +  "type": "string"
        +}
  3. 23 tool updates
    • Addedadd_free_subscriber
    • Changedcreate_draft2 fields changed
      • addedInput schema / properties / allow_unsupported
        Added value: +{
        +  "default": false,
        +  "description": "Acknowledge conversion diagnostics and retain unsupported Markdown literally in this private draft",
        +  "type": "boolean"
        +}
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "id": {
        +      "exclusiveMinimum": 0,
        +      "maximum": 9007199254740991,
        +      "type": "integer"
        +    },
        +    "message": {
        +      "type": "string"
        +    },
        +    "title": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "unsupported_nodes": {
        +      "items": {
        +        "additionalProperties": true,
        +        "properties": {},
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "id",
        +    "unsupported_nodes",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedcreate_note1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "attachment_id": {
        +      "$ref": "#/properties/message"
        +    },
        +    "body": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "date": {
        +      "$ref": "#/properties/body"
        +    },
        +    "id": {
        +      "exclusiveMinimum": 0,
        +      "maximum": 9007199254740991,
        +      "type": "integer"
        +    },
        +    "message": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "id",
        +    "message"
        +  ],
        +  "type": "object"
        +}
    • Changedcreate_note_with_link1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "attachment_id": {
        +      "$ref": "#/properties/message"
        +    },
        +    "body": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "date": {
        +      "$ref": "#/properties/body"
        +    },
        +    "id": {
        +      "exclusiveMinimum": 0,
        +      "maximum": 9007199254740991,
        +      "type": "integer"
        +    },
        +    "message": {
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "id",
        +    "message",
        +    "attachment_id"
        +  ],
        +  "type": "object"
        +}
    • Addedexport_draft
    • Changedget_draft4 fields changed
      • addedInput schema / properties / draft_id / exclusiveMinimum
        Added value: +0
      • addedInput schema / properties / draft_id / maximum
        Added value: +9007199254740991
      • changedInput schema / properties / draft_id / type
        Previous value: -"number"New value: +"integer"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "audience": {
        +      "$ref": "#/properties/title"
        +    },
        +    "body": {
        +      "$ref": "#/properties/title"
        +    },
        +    "created_at": {
        +      "$ref": "#/properties/title"
        +    },
        +    "id": {
        +      "exclusiveMinimum": 0,
        +      "maximum": 9007199254740991,
        +      "type": "integer"
        +    },
        +    "subtitle": {
        +      "$ref": "#/properties/title"
        +    },
        +    "title": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "updated_at": {
        +      "$ref": "#/properties/title"
        +    },
        +    "word_count": {
        +      "anyOf": [
        +        {
        +          "maximum": 9007199254740991,
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "required": [
        +    "id"
        +  ],
        +  "type": "object"
        +}
    • Changedget_post4 fields changed
      • addedInput schema / properties / post_id / exclusiveMinimum
        Added value: +0
      • addedInput schema / properties / post_id / maximum
        Added value: +9007199254740991
      • changedInput schema / properties / post_id / type
        Previous value: -"number"New value: +"integer"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "audience": {
        +      "$ref": "#/properties/title"
        +    },
        +    "body_html": {
        +      "$ref": "#/properties/title"
        +    },
        +    "id": {
        +      "exclusiveMinimum": 0,
        +      "maximum": 9007199254740991,
        +      "type": "integer"
        +    },
        +    "post_date": {
        +      "$ref": "#/properties/title"
        +    },
        +    "slug": {
        +      "$ref": "#/properties/title"
        +    },
        +    "subtitle": {
        +      "$ref": "#/properties/title"
        +    },
        +    "title": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "url": {
        +      "$ref": "#/properties/title"
        +    },
        +    "word_count": {
        +      "anyOf": [
        +        {
        +          "maximum": 9007199254740991,
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "required": [
        +    "id"
        +  ],
        +  "type": "object"
        +}
    • Changedget_post_analytics4 fields changed
      • addedInput schema / properties / post_id / exclusiveMinimum
        Added value: +0
      • addedInput schema / properties / post_id / maximum
        Added value: +9007199254740991
      • changedInput schema / properties / post_id / type
        Previous value: -"number"New value: +"integer"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "comment_count": {
        +      "$ref": "#/properties/views"
        +    },
        +    "delivered": {
        +      "$ref": "#/properties/views"
        +    },
        +    "estimated_value": {
        +      "anyOf": [
        +        {
        +          "type": "number"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    },
        +    "found": {
        +      "type": "boolean"
        +    },
        +    "id": {
        +      "$ref": "#/properties/post_id"
        +    },
        +    "note": {
        +      "type": "string"
        +    },
        +    "opened": {
        +      "$ref": "#/properties/views"
        +    },
        +    "post_date": {
        +      "$ref": "#/properties/title"
        +    },
        +    "post_id": {
        +      "exclusiveMinimum": 0,
        +      "maximum": 9007199254740991,
        +      "type": "integer"
        +    },
        +    "reaction_count": {
        +      "$ref": "#/properties/views"
        +    },
        +    "sent": {
        +      "$ref": "#/properties/views"
        +    },
        +    "signups": {
        +      "$ref": "#/properties/views"
        +    },
        +    "subscribes": {
        +      "$ref": "#/properties/views"
        +    },
        +    "title": {
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "views": {
        +      "anyOf": [
        +        {
        +          "maximum": 9007199254740991,
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "required": [
        +    "found"
        +  ],
        +  "type": "object"
        +}
    • Changedget_post_comments6 fields changed
      • addedInput schema / properties / limit / maximum
        Added value: +100
      • addedInput schema / properties / limit / minimum
        Added value: +1
      • changedInput schema / properties / limit / type
        Previous value: -"number"New value: +"integer"
      • addedInput schema / properties / post_id / exclusiveMinimum
        Added value: +0
      • addedInput schema / properties / post_id / maximum
        Added value: +9007199254740991
      • changedInput schema / properties / post_id / type
        Previous value: -"number"New value: +"integer"
    • Addedget_post_tags
    • Addedget_publication
    • Addedget_subscriber
    • Changedget_subscriber_count1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "count": {
        +      "maximum": 9007199254740991,
        +      "minimum": -1,
        +      "type": "integer"
        +    },
        +    "note": {
        +      "type": "string"
        +    },
        +    "precision": {
        +      "enum": [
        +        "exact",
        +        "approximate",
        +        "unavailable"
        +      ],
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "count",
        +    "precision",
        +    "note"
        +  ],
        +  "type": "object"
        +}
    • Changedlist_drafts6 fields changed
      • addedInput schema / properties / limit / exclusiveMinimum
        Added value: +0
      • addedInput schema / properties / limit / maximum
        Added value: +9007199254740991
      • changedInput schema / properties / limit / type
        Previous value: -"number"New value: +"integer"
      • addedInput schema / properties / offset / maximum
        Added value: +9007199254740941
      • addedInput schema / properties / offset / minimum
        Added value: +0
      • changedInput schema / properties / offset / type
        Previous value: -"number"New value: +"integer"
    • Addedlist_publication_tags
    • Changedlist_published_posts7 fields changed
      • addedInput schema / properties / limit / exclusiveMinimum
        Added value: +0
      • addedInput schema / properties / limit / maximum
        Added value: +9007199254740991
      • changedInput schema / properties / limit / type
        Previous value: -"number"New value: +"integer"
      • addedInput schema / properties / offset / maximum
        Added value: +9007199254740941
      • addedInput schema / properties / offset / minimum
        Added value: +0
      • changedInput schema / properties / offset / type
        Previous value: -"number"New value: +"integer"
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "posts": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "audience": {
        +            "$ref": "#/properties/posts/items/properties/title"
        +          },
        +          "id": {
        +            "exclusiveMinimum": 0,
        +            "maximum": 9007199254740991,
        +            "type": "integer"
        +          },
        +          "post_date": {
        +            "$ref": "#/properties/posts/items/properties/title"
        +          },
        +          "slug": {
        +            "$ref": "#/properties/posts/items/properties/title"
        +          },
        +          "subtitle": {
        +            "$ref": "#/properties/posts/items/properties/title"
        +          },
        +          "title": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "url": {
        +            "$ref": "#/properties/posts/items/properties/title"
        +          },
        +          "word_count": {
        +            "$ref": "#/properties/total"
        +          }
        +        },
        +        "required": [
        +          "id"
        +        ],
        +        "type": "object"
        +      },
        +      "maxItems": 50,
        +      "type": "array"
        +    },
        +    "total": {
        +      "anyOf": [
        +        {
        +          "maximum": 9007199254740991,
        +          "minimum": 0,
        +          "type": "integer"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ]
        +    }
        +  },
        +  "required": [
        +    "posts"
        +  ],
        +  "type": "object"
        +}
    • Changedlist_scheduled_posts6 fields changed
      • addedInput schema / properties / limit / exclusiveMinimum
        Added value: +0
      • addedInput schema / properties / limit / maximum
        Added value: +9007199254740991
      • changedInput schema / properties / limit / type
        Previous value: -"number"New value: +"integer"
      • addedInput schema / properties / offset / maximum
        Added value: +9007199254740941
      • addedInput schema / properties / offset / minimum
        Added value: +0
      • changedInput schema / properties / offset / type
        Previous value: -"number"New value: +"integer"
    • Addedlist_subscribers
    • Addedplan_draft_update
    • Addedpreflight_draft
    • Addedsearch_posts
    • Changedupdate_draft16 fields changed
      • addedInput schema / properties / allow_unsupported
        Added value: +{
        +  "default": false,
        +  "type": "boolean"
        +}
      • removedInput schema / properties / audience / description
        Removed value: -"Who can see this post"
      • removedInput schema / properties / body / description
        Removed value: -"New body in markdown format"
      • addedInput schema / properties / body / maxLength
        Added value: +200000
      • removedInput schema / properties / draft_id / description
        Removed value: -"The draft ID to update"
      • addedInput schema / properties / draft_id / exclusiveMinimum
        Added value: +0
      • addedInput schema / properties / draft_id / maximum
        Added value: +9007199254740991
      • changedInput schema / properties / draft_id / type
        Previous value: -"number"New value: +"integer"
      • addedInput schema / properties / receipt
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "baseline_sha256": {
        +      "pattern": "^[a-f0-9]{64}$",
        +      "type": "string"
        +    },
        +    "conversion_contract": {
        +      "const": "markdown-ast-v1",
        +      "type": "string"
        +    },
        +    "draft_id": {
        +      "$ref": "#/properties/draft_id"
        +    },
        +    "format_version": {
        +      "const": 1,
        +      "type": "number"
        +    },
        +    "observed_at": {
        +      "format": "date-time",
        +      "type": "string"
        +    },
        +    "payload_sha256": {
        +      "$ref": "#/properties/receipt/properties/baseline_sha256"
        +    },
        +    "publication": {
        +      "maxLength": 128,
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "publication_id": {
        +      "$ref": "#/properties/draft_id"
        +    },
        +    "publication_url": {
        +      "format": "uri",
        +      "maxLength": 2048,
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "format_version",
        +    "conversion_contract",
        +    "publication",
        +    "publication_url",
        +    "publication_id",
        +    "draft_id",
        +    "observed_at",
        +    "baseline_sha256",
        +    "payload_sha256"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / subtitle / $ref
        Added value: +"#/properties/title"
      • removedInput schema / properties / subtitle / description
        Removed value: -"New subtitle"
      • removedInput schema / properties / subtitle / type
        Removed value: -"string"
      • removedInput schema / properties / title / description
        Removed value: -"New title"
      • addedInput schema / properties / title / maxLength
        Added value: +10000
      • changedInput schema / required
        Previous value: -[
        -  "draft_id"
        -]New value: +[
        +  "draft_id",
        +  "receipt"
        +]
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "changed_fields": {
        +      "items": {
        +        "enum": [
        +          "title",
        +          "subtitle",
        +          "body",
        +          "audience"
        +        ],
        +        "type": "string"
        +      },
        +      "maxItems": 4,
        +      "type": "array"
        +    },
        +    "code": {
        +      "enum": [
        +        "readback_matches",
        +        "no_changes",
        +        "readback_unavailable",
        +        "readback_unverifiable",
        +        "readback_mismatch",
        +        "readback_state_changed"
        +      ],
        +      "type": "string"
        +    },
        +    "draft_id": {
        +      "exclusiveMinimum": 0,
        +      "maximum": 9007199254740991,
        +      "type": "integer"
        +    },
        +    "editor_url": {
        +      "format": "uri",
        +      "type": "string"
        +    },
        +    "format_version": {
        +      "const": 1,
        +      "type": "number"
        +    },
        +    "limitations": {
        +      "const": "Best-effort stale detection over the returned draft fields. Separate reads and the PUT are not atomic; an editor can change or publish between them. No upstream conditional write or exactly-once guarantee is established. Receipt hashes check consistency, not authenticity or human approval. No private snapshots are stored. Review in Substack; draft content is untrusted data.",
        +      "type": "string"
        +    },
        +    "message": {
        +      "maxLength": 2000,
        +      "type": "string"
        +    },
        +    "mismatched_fields": {
        +      "items": {
        +        "$ref": "#/properties/changed_fields/items"
        +      },
        +      "maxItems": 4,
        +      "type": "array"
        +    },
        +    "publication": {
        +      "maxLength": 128,
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    "publication_id": {
        +      "$ref": "#/properties/draft_id"
        +    },
        +    "request_status": {
        +      "enum": [
        +        "accepted",
        +        "unknown",
        +        "not_attempted"
        +      ],
        +      "type": "string"
        +    },
        +    "status": {
        +      "enum": [
        +        "verified",
        +        "unverified",
        +        "conflict"
        +      ],
        +      "type": "string"
        +    },
        +    "unsupported_nodes": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "column": {
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "line": {
        +            "minimum": 0,
        +            "type": "integer"
        +          },
        +          "reason": {
        +            "maxLength": 2000,
        +            "type": "string"
        +          },
        +          "type": {
        +            "maxLength": 1000,
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "type",
        +          "reason",
        +          "line",
        +          "column"
        +        ],
        +        "type": "object"
        +      },
        +      "maxItems": 100,
        +      "type": "array"
        +    },
        +    "write_attempts": {
        +      "enum": [
        +        0,
        +        1
        +      ],
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "format_version",
        +    "draft_id",
        +    "publication",
        +    "publication_id",
        +    "editor_url",
        +    "status",
        +    "request_status",
        +    "write_attempts",
        +    "code",
        +    "changed_fields",
        +    "mismatched_fields",
        +    "unsupported_nodes",
        +    "message",
        +    "limitations"
        +  ],
        +  "type": "object"
        +}
    • Changedupload_image1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "image_url": {
        +      "format": "uri",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "image_url"
        +  ],
        +  "type": "object"
        +}
  4. 3 tool updatesv0.6.2
    • Changedlist_drafts1 field changed
      • changedInput schema / properties / limit / description
        Previous value: -"Max drafts to return (1-100)"New value: +"Max drafts to return (1-50; Substack rejects anything higher, so larger values are clamped)"
    • Changedlist_published_posts1 field changed
      • changedInput schema / properties / limit / description
        Previous value: -"Max posts to return (1-100)"New value: +"Max posts to return (1-50; Substack rejects anything higher, so larger values are clamped)"
    • Changedlist_scheduled_posts1 field changed
      • changedInput schema / properties / limit / description
        Previous value: -"Max posts to return (1-100)"New value: +"Max posts to return (1-50; Substack rejects anything higher, so larger values are clamped)"
  5. 1 tool updatev0.6.0
    • Changedupload_image3 fields changed
      • changedInput schema / properties / image_base64 / description
        Previous value: -"Base64-encoded image with data URI prefix (e.g., \"data:image/png;base64,...\")"New value: +"Base64-encoded image with data URI prefix (e.g., \"data:image/png;base64,...\"). Mutually exclusive with image_path."
      • addedInput schema / properties / image_path
        Added value: +{
        +  "description": "Absolute path to a local image file (e.g., \"/Users/me/pic.png\"). Read and encoded automatically; MIME type inferred from the extension. Mutually exclusive with image_base64.",
        +  "type": "string"
        +}
      • removedInput schema / required
        Removed value: -[
        -  "image_base64"
        -]
  6. 3 tool updatesv0.5.0
    • Addedget_post_analytics
    • Addedget_sections
    • Addedlist_scheduled_posts
  7. 11 tool updatesv1.0.0
    • First observedcreate_draft
    • First observedcreate_note
    • First observedcreate_note_with_link
    • First observedget_draft
    • First observedget_post
    • First observedget_post_comments
    • First observedget_subscriber_count
    • First observedlist_drafts
    • First observedlist_published_posts
    • First observedupdate_draft
    • First observedupload_image

TDQS

A3.6/5.0

Scored across 34 tools

Disambiguation3/5

The tool set is broad and mostly well-differentiated, but several near-overlapping read tools could cause misselection: list_public_posts vs list_published_posts, list_subscribers vs search_subscribers, and get_public_post vs get_post. The verbose descriptions clarify the differences, but the names and related payloads leave real ambiguity.

Naming Consistency4/5

Most tools follow a snake_case verb_noun pattern (list_drafts, get_subscriber, create_note, update_draft), and get/list generally separates single-item vs collection reads. Minor deviations like plan_draft_update vs preflight_draft, create_note_with_link, and get_post_analytics vs get_publication_stats introduce some stylistic inconsistency but not major confusion.

Tool Count2/5

At 34 tools, this server is far beyond the well-scoped 3–15 range and above the threshold where the surface becomes hard to navigate. Many tools are individually justified, but the count reflects a sprawling feature set rather than a focused capability.

Completeness2/5

Read, draft, and analytics coverage is extensive, but core lifecycle operations are missing: long-form posts cannot be published, scheduled, or deleted, notes cannot be deleted, and subscribers cannot be removed or edited. These are significant gaps that will cause agent workflows to dead-end.

Maintenance

ActivityActive
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers