create_note
Publish short-form content to Substack using markdown format. This tool creates notes that are published immediately without a draft state.
Instructions
Create a Substack Note (short-form content). Accepts markdown text. Publishes immediately — there is no draft state for notes.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| body | Yes | Note content in markdown format |
Implementation Reference
- src/server.ts:267-297 (handler)Tool registration and handler for 'create_note'. Registers the tool with Zod schema validation (body: string), then handles the request by converting markdown to ProseMirror format, calling client.createNote(), and returning the created note details.
server.tool( "create_note", "Create a Substack Note (short-form content). Accepts markdown text. Publishes immediately — there is no draft state for notes.", { body: z.string().describe("Note content in markdown format"), }, async ({ body }) => { const bodyJson = { type: "doc" as const, attrs: { schemaVersion: "v1" as const }, content: markdownToProseMirrorContent(body), }; const note = await client.createNote(bodyJson); return { content: [ { type: "text", text: JSON.stringify( { id: note.id, body: note.body, date: note.date, message: "Note published successfully.", }, null, 2, ), }, ], }; }, - src/api/client.ts:182-202 (handler)API client method that creates a note by constructing the payload with bodyJson, tabId, surface, and replyMinimumRole, then makes a POST request to the Substack API endpoint /api/v1/comment/feed.
async createNote( bodyJson: NoteCreatePayload["bodyJson"], attachmentIds?: string[], ): Promise<SubstackNote> { const payload: NoteCreatePayload = { bodyJson, tabId: "for-you", surface: "feed", replyMinimumRole: "everyone", }; if (attachmentIds?.length) { payload.attachmentIds = attachmentIds; } return this.request<SubstackNote>( `${this.publicationUrl}/api/v1/comment/feed`, { method: "POST", body: JSON.stringify(payload), }, ); } - src/api/types.ts:93-115 (schema)Type definitions for the note creation payload (NoteCreatePayload) with bodyJson structure, and the response type (SubstackNote) with id, body, date, and other metadata fields.
export interface NoteCreatePayload { bodyJson: { type: "doc"; attrs: { schemaVersion: "v1" }; content: unknown[]; }; tabId: string; surface: string; replyMinimumRole: string; attachmentIds?: string[]; } export interface SubstackNote { id: number; body: string; body_json?: unknown; date: string; name: string; reaction_count: number; restacks: number; children_count: number; attachments: unknown[]; } - Helper function that converts markdown text to ProseMirror content array format, used by the create_note handler to format the note body before sending to the API.
/** * Returns the raw ProseMirror content array (for Notes, which wrap it in their own doc envelope). */ export function markdownToProseMirrorContent(markdown: string): PMNode[] { const doc = JSON.parse(markdownToProseMirror(markdown)); return doc.content; }