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

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

| Group | Access | MCP name |
| --- | --- | --- |
| Schedule | Irreversible | `schedule_notes` |

<Callout type="warn">This tool changes data in a way that cannot be undone. Confirm with the writer before calling it.</Callout>

## Description [#description]

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

> Schedule notes to the user's next available posting slots based on their recurring schedule template. Each note is routed by its own tags: first open or matching reserved lane. Untagged notes only use open or untagged-only slots. You can also set or update each note's autoRestackAfterHours at the same time (1–168 hours; null clears it). To also cross-post the notes to Buffer channels when they publish, pass bufferChannelIds (call list_buffer_channels first to get valid IDs) — the same channels are applied to every note in the batch, except a slot with its own Buffer channels replaces those for the note that lands there. Queue routing: each weekly time can reserve tags, accept only untagged notes, or stay open for any note, and may also set default Buffer channels. A time with tags is a reserved lane — it stays empty until a note shares ANY of those tags (OR). A time marked untaggedNotesOnly (and with no tags) accepts only notes with no tags; tagged notes never take those times, including Add to Queue leftovers. Untagged notes never take reserved lanes. When filling the next template times (schedule_notes), a tagged note takes the first open (any-note) time or matching reserved lane, whichever comes first. An untagged note takes the first open or untagged-only time. If a time has Buffer channels, those replace the note's channels when the note lands there (apply-on-schedule only). Substack still always posts. Call get_schedule to see each slot's tags, untaggedNotesOnly, and bufferChannels. You MAY create notes without asking. CRITICAL: Scheduling in WriteStack does NOT push notes to Substack. After scheduling, the user must open WriteStack and click the yellow Sync/Warning button so the Chrome extension syncs them — you cannot do this for them. BEFORE calling this tool, you MUST ask the user to confirm they understand they need to sync manually afterward, then pass userConfirmedManualSync: true. Never set that flag unless they explicitly confirmed in this conversation. IMPORTANT: Call get_schedule_capacity first. NEVER, under any circumstances, schedule more than the reported `remaining` (unless unlimited=true). If the user asks to schedule more than `remaining`, schedule only the first `remaining` notes, leave the rest as ready/drafts, and tell the user how many were scheduled and why the rest were not. Scheduling sets the notes' status to scheduled and assigns posting times; this integration cannot unschedule them, so the user would have to undo it in WriteStack.

## 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. When provided here, the same value is applied to every note in this batch. To set different values per note, call update_note for each one after scheduling. Min 1. Max 168. |
| `bufferChannelIds` | `string[]` | No | Optional array of Buffer channel IDs to cross-post this 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. When set, WriteStack will also post the note to these Buffer channels (e.g. LinkedIn, X/Twitter, Threads) shortly after it goes live. Pass an empty array or omit to leave cross-posting unchanged; pass the channels you want to keep, since this replaces any previously set channels. 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 When provided here, the same channels are applied to every note in this batch, unless the slot the note lands on has its own Buffer channels — those replace the batch value for that note. |
| `noteIds` | `string[]` | Yes | Array of note IDs to schedule, in order |
| `userConfirmedManualSync` | `boolean` | Yes | Must be true. Only set this after the user has explicitly confirmed they understand they must manually sync these notes in WriteStack (yellow Sync/Warning button) after scheduling, because this MCP cannot push them to Substack. Do not assume confirmation. |

## 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": "schedule_notes",
    "arguments": {
      "noteIds": [
        "…"
      ],
      "userConfirmedManualSync": true
    }
  }
}
```

## Result [#result]

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

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `assignments` | `object[]` | Yes |  |
| `assignments[].autoRestackAfterHours` | `number \| null` | No |  |
| `assignments[].bufferChannelIds` | `string[]` | No |  |
| `assignments[].bufferChannelsOverridden` | `boolean` | No |  |
| `assignments[].noteId` | `string` | Yes |  |
| `assignments[].notePreview` | `string` | Yes |  |
| `assignments[].scheduledAt` | `string` | Yes |  |
| `assignments[].source` | `string` | No | One of: `"lane"`, `"open"`, `"any"`. |
| `autoRestackAfterHours` | `number \| null` | No |  |
| `message` | `string` | Yes |  |
| `requestedCount` | `number` | Yes |  |
| `scheduledCount` | `number` | Yes |  |
| `warnings` | `string[]` | No |  |

## Annotations [#annotations]

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

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