# create_note (/docs/build/mcp-reference/create_note)

{/* GENERATED by scripts/generate-mcp-reference.mjs from the MCP server tools/list. Do not edit. */}

| Group | Access | MCP name |
| --- | --- | --- |
| Notes | Writes data | `create_note` |

## Description [#description]

The description the MCP server sends to the model, word for word. Its rules apply to every call.

> Create a new note draft or ready note. The content body must be in Markdown format. When generating new note content (not when the user already provided the full body), call get_writing_style first unless they pasted complete style instructions. If the content includes a link (https:// URL or bare domain like example.com), ask the user if they'd like a link preview before calling this tool; pass includePreviews: true only if they confirm. Prefer full https:// URLs in the content. To attach images, pass imageUrl as an array of remote image URLs (max 5) — WriteStack fetches and stores them like CSV import. You can also enable auto-restack by passing autoRestackAfterHours (1–168 hours) — the note will automatically be restacked that many hours after it's published. To cross-post to Buffer, call list_buffer_channels first and pass bufferChannelIds and/or bufferChannelPosts (per-channel text and images). Tags you assign also decide which reserved queue times this note can take later (OR match; untagged notes only use open or untagged-only times). Very important: New line MUST be with double newlines (
> 
> ).

## Arguments [#arguments]

| Argument | Type | Required | Description |
| --- | --- | --- | --- |
| `autoRestackAfterHours` | `integer \| null` | No | Optional auto-restack delay in hours (1–168). If set, after the note is published WriteStack will automatically restack (re-post) it the given number of hours later to boost visibility. Pass null or omit to disable auto-restack on the note. Requires the WriteStack browser extension v1.4.78 or higher to actually fire. Min 1. Max 168. |
| `bufferChannelIds` | `string[]` | No | Optional array of Buffer channel IDs to cross-post this new note to once it publishes on Substack. Call list_buffer_channels first to get the valid IDs — only IDs returned by that tool are accepted. Maximum 20 channels per note — requests with more are rejected. Channel IDs from bufferChannelPosts are merged in automatically. Omit or pass an empty array to skip Buffer cross-posting unless you also pass bufferChannelPosts. Requires a connected Buffer account. Platform limits still apply: Instagram requires an image or video, and Instagram feed images must be between 4:5 and 1.91:1 aspect ratio for automatic posting (otherwise Buffer falls back to Notify Me). See https://support.buffer.com/article/622-instagrams-accepted-aspect-ratio-ranges |
| `bufferChannelPosts` | `object[]` | No | Optional per-channel Buffer post overrides when a channel should have different text or images than the Substack note. Call list_buffer_channels first. Each item needs bufferChannelId and, unless reset is true, a plain-text body (max 5000). Those channel IDs are also selected on the note (merged with bufferChannelIds, still max 20). imageUrl attaches images to that channel only — they are not added to the Substack note. Omit imageUrl to keep existing channel images; pass [] to clear them. includePreviews adds a link card from the first URL in that channel's body (max 1). reset: true deletes the override so the channel falls back to the note. Removing a channel from bufferChannelIds does not delete a saved override. Platform limits still apply: Instagram requires an image or video, and Instagram feed images must be between 4:5 and 1.91:1 aspect ratio for automatic posting (otherwise Buffer falls back to Notify Me). See https://support.buffer.com/article/622-instagrams-accepted-aspect-ratio-ranges Max items 20. |
| `bufferChannelPosts[].body` | `string` | No | Plain-text override for this channel (max 5000). Required unless reset is true. This is what Buffer publishes for this channel instead of the Substack note. Max length 5000. |
| `bufferChannelPosts[].bufferChannelId` | `string` | Yes | Buffer channel ID from list_buffer_channels |
| `bufferChannelPosts[].imageUrl` | `string[]` | No | Remote image URLs for this channel only (max 5). WriteStack fetches and stores them. They are not added to the Substack note. Omit to keep existing channel images; pass [] to clear them. Max items 5. |
| `bufferChannelPosts[].includePreviews` | `boolean` | No | If true, attach a rich link-preview card from the first URL in this channel's body. Max 1 preview per channel. |
| `bufferChannelPosts[].reset` | `boolean` | No | If true, delete this channel's custom post so it falls back to the Substack note. The channel stays selected. |
| `content` | `string` | Yes | The note body text |
| `imageUrl` | `string[]` | No | Optional remote image URLs to attach to the note (same as CSV import image_url). WriteStack fetches each URL and stores the image. Max 5. Pass full https:// URLs. Invalid or unreachable URLs are skipped. Max items 5. |
| `includePreviews` | `boolean` | No | If the note's content contains a link (full https:// URL or bare domain like writestack.io), ask the user whether they want a rich link-preview card (image, title, description) attached before creating/updating the note - do not assume yes. If they confirm, pass includePreviews: true. Prefer writing links as full https:// URLs in the content so previews resolve reliably. Only one preview can be attached per note; if there are multiple links, the first link in the content is used. |
| `status` | `string` | No | Note status One of: `"draft"`, `"ready"`. Default `"draft"`. |
| `tags` | `string[]` | No | Category/tag names to assign. Tags also decide which reserved queue times this note can take: a note matches a reserved slot if it shares ANY of the slot's tags. Untagged notes only use open or untagged-only times. Call list_tags first to show available names. |

## Example call [#example-call]

The smallest valid request: required arguments only, with placeholder values.

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "create_note",
    "arguments": {
      "content": "…"
    }
  }
}
```

## Result [#result]

The result has `structuredContent` that matches this schema. The same data is also in `content` as JSON text.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `attachments` | `any[]` | No |  |
| `autoRestackAfterHours` | `number \| null` | Yes |  |
| `bufferChannelIds` | `string[]` | No |  |
| `bufferChannelPosts` | `object[]` | No |  |
| `bufferChannelPosts[].attachments` | `object[]` | Yes |  |
| `bufferChannelPosts[].attachments[].type` | `string` | Yes |  |
| `bufferChannelPosts[].attachments[].url` | `string` | Yes |  |
| `bufferChannelPosts[].body` | `string` | Yes |  |
| `bufferChannelPosts[].bufferChannelId` | `string` | Yes |  |
| `bufferChannelPosts[].reset` | `boolean` | No |  |
| `linkPreview` | `object` | No |  |
| `linkPreview.added` | `boolean` | Yes |  |
| `linkPreview.reason` | `string` | No |  |
| `linkPreview.url` | `string` | No |  |
| `message` | `string` | Yes |  |
| `noteId` | `string` | Yes |  |
| `status` | `string` | Yes |  |

## Annotations [#annotations]

| Hint | Value |
| --- | --- |
| `readOnlyHint` | `false` |
| `destructiveHint` | `false` |
| `openWorldHint` | `true` |

The full input and output JSON Schemas for every tool are in [/mcp-tools.json](/mcp-tools.json).
