# Narrareach MCP tool reference

Use these tools through your authorized Narrareach MCP connection. Your client receives the exact input schemas when it connects; use those schemas for field types, choices, and limits.

- Connector URL: https://www.narrareach.com/mcp
- Setup guide: https://www.narrareach.com/api-docs
- REST contract: https://www.narrareach.com/openapi.json

## Agent rules

1. Use `list_workspaces` before acting for another writer or when the target workspace is ambiguous.
2. Read the relevant draft, Note, or schedule before changing it.
3. Ask for confirmation before scheduling, replying, archiving, cancelling, or otherwise changing user data.
4. Preserve returned identifiers and URLs so status, reschedule, and cancellation calls target the accepted item.
5. After a timeout, check the correct content list below before retrying. Do not assume an empty article list means a Note was not scheduled.
6. Treat advisories as status information unless the response explicitly says the operation failed.

## Choose the account

Call `list_workspaces` to see the teams and writers you can access. Team access is supported by `list_content_versions`, `create_article_from_note`, `list_notes`, `get_note`, `schedule_note`, `list_linkedin_destinations`, `list_social_accounts`, `list_instagram_destinations`, `list_scheduled_items` (Notes only), `get_stats_insights`, `get_voice_profile`, `save_voice_preference`, `add_voice_material`, `decide_voice_suggestion`, `update_voice_rule`, `remove_voice_rule`, and `undo_voice_change`. The per-tool account selection below tells you which selectors to send. Other draft tools, article scheduling, and schedule changes currently use your personal account.

For a team Note, keep the same workspace when listing, reading, and scheduling. Use a writer returned by `list_workspaces` when selecting another writer. If the account or writer is unclear, ask the user. Never switch to personal publishing to work around a team access error.

## Check the right content

| Content | Find it | Read its current state |
| --- | --- | --- |
| Notes and social posts | `list_notes` | `get_note` with its returned `id`; retain `workspace` for team content |
| Articles | `list_scheduled_posts` | Find the returned schedule `id` in that list; use `from`, `to`, and `status` filters as needed |

For personal-account schedules, use `reschedule_scheduled_item` or `cancel_scheduled_item` with the returned schedule id and `kind: "note"` or `kind: "article"`. A draft id is not a schedule id. These mutation tools do not currently accept team selectors. If a team Note needs changing, use the team workspace in the Narrareach dashboard instead.

An absent result is not proof that a timed-out request failed: check the correct account, filters, and list limit. If you cannot determine whether the item exists, ask the user to check Narrareach before submitting again.

## Edit scheduled LinkedIn posts with ChatGPT or another MCP assistant

1. Find the post with `list_scheduled_items` and inspect it with `get_scheduled_item_readiness` using its schedule id and `kind: "note"`.
2. Read the exact queued text with `get_note` using that same id.
3. Call `amend_scheduled_note_content` with `id`, the readiness `revision` as `expectedRevision`, and the full replacement `content`. Omit `apply` to preview without changing the post.
4. Show the preview to the user. After confirmation, repeat with `apply: true`. If the item changed, read it again and request a new confirmation.

This edits only text-only LinkedIn posts in your personal account before publishing starts. It does not edit posts with media, published posts, or scheduled articles. For timing changes, use `amend_scheduled_item` with the same preview-and-confirm process.

For articles, readiness returns a `draftId` for `get_draft`. That body is your Narrareach draft, not a verified copy of the article scheduled on the publishing platform. `update_draft` can change an unscheduled draft's title, body, or cover; it cannot edit an active article schedule. Cover-only changes keep the existing body and subscribe controls. Do not cancel and recreate a schedule without the user's approval.

## Getting new tools in an existing MCP connection

Official Narrareach plugin: new or changed tools become available after OpenAI approves them. Installing again or reconnecting does not bypass that review. Try a new chat with Narrareach selected once the update is available.

Custom connection: open its settings in ChatGPT in a browser. If Refresh is available, select it, check the tool list, then start a new conversation. Reconnect or Change connection may only repeat sign-in; they do not confirm that new tools were added.

If Refresh is missing or Substack verification is still unavailable, contact Narrareach support with the missing action and whether you use the official plugin or a custom connection. Keep your existing draft and publishing accounts connected. A managed workspace may need an administrator to review and enable new actions.

See [OpenAI’s connection guide](https://developers.openai.com/plugins/deploy/connect-chatgpt).

## Field examples

- **Save a draft:** `create_draft` with `{"title":"Weekly update","contentHtml":"<p>Approved article body.</p>"}`. The returned `id` is used by `get_draft`, `update_draft`, and `archive_draft`.
- **Read a Note:** `get_note` with `{"id":"note_id"}`; add `workspace` only for a team Note.
- **Upload an image:** `upload_media` with `{"kind":"image","sourceType":"base64","data":"BASE64_IMAGE_BYTES","mimeType":"image/png"}`. Replace the example bytes; use `kind: "video"` and the matching MIME type for video. Keep the returned `publicUrl`.
- **Prepare pilot inspiration:** call `get_benchmark_inspiration` without arguments, then send the selected `recordId` and the writer's `niche` to `prepare_benchmark_inspiration`.

For `schedule_note`, supply approved `content` or a suitable saved `draftId`, plus `platforms` and `scheduledFor`. For `schedule_article`, supply a saved `draftId` or new `title` and `contentHtml`, plus `platforms` and a schedule through `scheduledFor` or `platformSchedules`. Schema-required fields are listed below; these content and timing choices are also needed to schedule successfully.

MCP scheduling and rescheduling use the user's local wall-clock time with an IANA `timezone`, for example `scheduledFor: "2026-12-01T09:00:00"` and `timezone: "America/New_York"`. Do not convert it to UTC yourself. The REST API has a separate timestamp contract in OpenAPI. Uploaded media uses a structured object, not an arbitrary attachment id; follow the client's media schema.

## Notes

### `preview_note_quote`

Preview a public Substack Note as a quote source; no dedicated quote field is available yet.

- **Use it when:** Inspect the source before planning a quote. The result always has publishable: false.
- **Access:** Available only when Quote Notes preview is enabled.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** `url`
- **Accepted fields:** `url`, `workspaceId`, `substackConnectionId`
- **Conditional fields:** None
- **Returns:** Live source metadata and publishable: false; nothing is published. A Substack Note URL in Note text is attached as a quote and stays visible in the text.

### `list_notes`

Find scheduled, published, or failed Notes and social posts, by date range or content tag, with their latest stored metrics.

- **Use it when:** Use to locate a Note, review recent short-form publishing work, or analyse performance over a period or by tag.
- **Access:** Personal account or an authorized team workspace.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `limit`, `status`, `platform`, `query`, `from`, `to`, `tag`, `cursor`, `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** Note identifiers, content summaries, tags, destinations, current states, latest metrics (with the follows and subscriptions Substack attributes to each note, and platform-reported saves, views, reach and follows where available), and a page cursor.

### `get_note`

Read one authorized Note and its destination state.

- **Use it when:** Use when the user supplies a Note identifier or selects one from list_notes.
- **Access:** Personal account or an authorized team workspace.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. This tool does not accept writer.
- **Changes data:** No.
- **Required fields:** `id`
- **Accepted fields:** `id`, `workspace`
- **Conditional fields:** None
- **Returns:** Note content, schedule, destination, public status information, recent metric snapshots, and platform-reported metrics.

### `schedule_note`

Schedule short-form content to supported connected publishing destinations.

- **Use it when:** Use after the user approves the content, destinations, and schedule.
- **Access:** Eligible plan plus write access to every selected destination.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `scheduledFor`, `platforms`
- **Accepted fields:** `draftId`, `title`, `content`, `scheduledFor`, `timezone`, `platforms`, `socialAccountIds`, `instagramDestinations`, `linkedInAccountId`, `linkedInOrganizationUrn`, `workspace`, `writer`, `publication`, `confirmProfileDestination`, `substackConnectionId`, `imageUrls`, `videoUrls`, `threadsTopicTag`, `firstReply`, `platformVersions`, `media`
- **Conditional fields:** `postingAs`: Available only when your connected tool schema includes it. Select a connected Substack pen name, profile handle, or publication label. Use postingAs or publication, not both. This field does not grant access to another account.
- **Returns:** Accepted schedule records, Narrareach URLs, adjustedPlatforms for any destination that posts other text than the note as written, and destination-specific advisories. Warnings include a note going to X with more than one cashtag ($SYMBOL): X accepts one per post and may refuse the note, so keep one and take the $ off the others.

### `list_linkedin_destinations`

Refresh and list connected LinkedIn profiles and Company Pages for short-form posts. Does not publish content.

- **Use it when:** Call before scheduling a LinkedIn post when the destination is ambiguous.
- **Access:** Connected LinkedIn account with post access in the selected account.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** None
- **Accepted fields:** `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** Available personal and organization destinations.

### `list_social_accounts`

List connected Threads, Facebook, TikTok, Pinterest and X accounts for short-form posts. Does not publish content.

- **Use it when:** Call before scheduling to one of these platforms when more than one account may be connected, or when schedule_note says an account must be chosen.
- **Access:** A connected account on at least one of these platforms in the selected account.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** Per platform: each account id and label, the account used when none is named, and whether an account must be named because several are connected with no default.

### `list_instagram_destinations`

List connected Instagram accounts for short-form posts. Does not publish content.

- **Use it when:** Call before scheduling to Instagram when more than one account is connected, or to send one Note to several accounts.
- **Access:** Connected Instagram account in the selected account.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** Each account id and label, the account used when none is named (and whether that is only a fallback), and how many accounts one Note may target.

### `list_hashtag_sets`

List your saved hashtag sets.

- **Use it when:** Use when the user wants to reuse a saved group of hashtags in a Note.
- **Access:** Personal account with related content enabled (rolling out).
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** None
- **Conditional fields:** None
- **Returns:** Each saved set name and its hashtags.

### `save_hashtag_sets`

Save your hashtag sets: up to 20 sets of up to 30 hashtags each. Never inserts hashtags into content or publishes anything.

- **Use it when:** Use after the user approves the full list. Call list_hashtag_sets first and include every set to keep, because saving replaces the whole list.
- **Access:** Personal account with related content enabled (rolling out).
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `sets`
- **Accepted fields:** `sets`
- **Conditional fields:** None
- **Returns:** The saved list of sets.

### `update_scheduled_note_account`

Send an already scheduled Threads, Facebook, TikTok, Pinterest or X post from a different connected account.

- **Use it when:** The writer asks to move a scheduled post to another of their accounts on the same platform. Get the account id from list_social_accounts first.
- **Access:** Authenticated personal account; the post must belong to you and must not have started sending.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `id`, `accountId`
- **Accepted fields:** `id`, `accountId`
- **Conditional fields:** None
- **Returns:** The post id, platform and new account, whether a held post resumed, and whether it now needs a new time because its original time passed.

### `amend_scheduled_note_content`

Preview and edit the text of a queued, text-only LinkedIn post.

- **Use it when:** Read readiness and queued text, preview the full replacement, and apply only after user confirmation.
- **Access:** Authenticated personal account; the post must belong to you and publishing must not have started.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `id`, `expectedRevision`, `content`
- **Accepted fields:** `id`, `expectedRevision`, `content`, `apply`
- **Conditional fields:** None
- **Returns:** A preview when apply is omitted or false; the updated queued text when apply is true. Media posts, published posts, and scheduled articles are not supported. Read readiness again if the item has changed.

## Workspace

### `list_workspaces`

List the personal account and authorized team workspaces, writers, and publications.

- **Use it when:** Call before acting for another writer or when the user has more than one workspace.
- **Access:** Authenticated Narrareach MCP connection.
- **Account selection:** Uses your signed-in account to discover available context; no selectors needed.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** None
- **Conditional fields:** None
- **Returns:** Authorized workspace choices and the writer identities available in each workspace.

### `get_user_profile`

Read the current user profile, plan, timezone, connection status, and available publishing context.

- **Use it when:** Use at the start of a workflow that depends on timezone, plan access, or connected platforms.
- **Access:** Authenticated Narrareach MCP connection.
- **Account selection:** Uses your signed-in account to discover available context; no selectors needed.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** None
- **Conditional fields:** None
- **Returns:** Profile context and user-visible integration readiness.

### `get_settings`

Read your main Settings: preferences such as UTM tagging and article link placement, the default account on each platform, connection health, and email notifications.

- **Use it when:** Use when the user asks how their account is set up, which account a platform posts to by default, or whether a connection needs attention.
- **Access:** Authenticated personal account.
- **Account selection:** Uses your signed-in account to discover available context; no selectors needed.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** None
- **Conditional fields:** None
- **Returns:** Current preferences, default accounts per platform, connection status per platform, and notification settings. It shows what Narrareach has stored and does not refresh connections.

### `update_settings`

Change your timezone, generated Note capitalization, article link placement, or UTM tagging for article links.

- **Use it when:** Use only after the user asks to change one of these preferences. Default accounts and connections are changed in Narrareach Settings; update_scheduled_note_account moves one scheduled Note to another account.
- **Access:** Authenticated personal account.
- **Account selection:** Uses your signed-in account to discover available context; no selectors needed.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** None
- **Accepted fields:** `preferredTimezone`, `capitalizeGeneratedNotes`, `articleLinkPlacement`, `tagArticleLinksWithUtm`
- **Conditional fields:** None
- **Returns:** The fields that changed and the saved preferences. Only the supplied fields change.

## Drafts

### `list_drafts`

Find drafts in your personal account by title or status.

- **Use it when:** Use when the user wants to find an existing draft before reading or editing it.
- **Access:** Authenticated personal account.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `limit`, `status`, `query`
- **Conditional fields:** None
- **Returns:** Draft identifiers, titles, status, previews, and timestamps.

### `get_draft`

Read the complete content and metadata for one authorized draft.

- **Use it when:** Use after list_drafts or when the user supplies a Narrareach draft identifier.
- **Access:** Authenticated personal account; the draft must belong to you.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** `id`
- **Accepted fields:** `id`
- **Conditional fields:** None
- **Returns:** The draft content and public editing metadata.

### `create_draft`

Save an article draft in your personal account without scheduling it.

- **Use it when:** Use when the user wants content saved for review rather than published or scheduled.
- **Access:** Authenticated personal account.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `title`
- **Accepted fields:** `title`, `contentHtml`
- **Conditional fields:** None
- **Returns:** The draft id, title, and creation timestamp. Omit contentHtml only to create an empty draft.

### `update_draft`

Update the title, body, or cover image of an unscheduled article draft.

- **Use it when:** Use after the user asks to revise or attach media to an existing draft.
- **Access:** Authenticated personal account; the draft must belong to you.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `id`
- **Accepted fields:** `id`, `title`, `contentHtml`, `coverImage`
- **Conditional fields:** None
- **Returns:** The updated draft summary. Only supplied fields are changed. Cover-only edits preserve the existing body and subscribe controls. Active article schedules must be handled before editing the draft; this tool does not change a scheduled copy on another platform.

### `archive_draft`

Archive an owned draft after active schedules have been handled.

- **Use it when:** Use only after the user clearly asks to archive a draft.
- **Access:** Authenticated personal account; the draft must belong to you.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `id`
- **Accepted fields:** `id`
- **Conditional fields:** None
- **Returns:** Archive confirmation or a public recovery instruction when the draft is still scheduled.

### `list_content_versions`

List a saved Note and the article drafted from it, each with its own status and destinations.

- **Use it when:** Use to check whether a Note already has a linked article before creating one.
- **Access:** Personal account or an authorized team workspace with related content enabled (rolling out).
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** No.
- **Required fields:** `draftId`
- **Accepted fields:** `draftId`, `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** The Note and its linked article, with independent statuses and destinations.

### `create_article_from_note`

Create a linked article draft from a saved Note. The Note is kept, and nothing is published.

- **Use it when:** Use when the user wants to expand a Note into an article. Repeating the request opens the same article and does not overwrite its edits.
- **Access:** Personal account or an authorized team workspace with related content enabled (rolling out).
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `draftId`
- **Accepted fields:** `draftId`, `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** The Note and its linked article draft.

## Articles

### `list_scheduled_posts`

List article schedules in your personal account.

- **Use it when:** Check an article schedule before retrying, moving, or cancelling it. For Notes and social posts, use list_notes.
- **Access:** Authenticated personal account.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `limit`, `status`, `from`, `to`
- **Conditional fields:** None
- **Returns:** Article schedule ids, draft summaries, times, destinations, and status.

### `cancel_scheduled_post`

Cancel an article schedule from list_scheduled_posts.

- **Use it when:** Use with an article schedule id after the user approves cancellation. Prefer cancel_scheduled_item for workflows that handle both articles and Notes.
- **Access:** Authenticated personal account; the schedule must belong to you.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `id`
- **Accepted fields:** `id`
- **Conditional fields:** None
- **Returns:** The schedule id and cancellation status.

### `schedule_article`

Schedule a full article to supported connected long-form destinations.

- **Use it when:** Use after title, article body, audience settings, destinations, and time are approved.
- **Access:** Eligible plan plus article write access to every selected destination.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `platforms`
- **Accepted fields:** `draftId`, `title`, `contentHtml`, `subtitle`, `coverImage`, `media`, `tags`, `sendToNewsletter`, `isPaidContent`, `paywallMarker`, `addSearchMetadata`, `linkedinShareCommentary`, `linkedinPublicationType`, `linkedinAuthorUrn`, `linkedinNewsletterUrn`, `scheduledFor`, `platformSchedules`, `timezone`, `platforms`, `publication`, `substackConnectionId`, `mediumPublicationId`, `mediumNotifyFollowers`
- **Conditional fields:** `mediumPublicationId`: Only valid when platforms includes MEDIUM. Call list_medium_publications and pass its returned id; never guess one. When canPublish is false the story is submitted for editorial review and left unscheduled until an editor accepts it. A rejection by the publication is best-effort — the story still goes to the personal profile and the rejection is returned as a warning. `mediumNotifyFollowers`: Only valid when platforms includes MEDIUM. Defaults to false (no subscriber email).
- **Returns:** Accepted article schedules, Narrareach URLs, and non-blocking advisories.

### `get_substack_verification_status`

Check whether your Substack connection needs a code.

- **Use it when:** Check before requesting a code or after an uncertain verification reply.
- **Access:** The connected Substack account owner.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** `connectionId`
- **Accepted fields:** `connectionId`
- **Conditional fields:** None
- **Returns:** The selected publication and any waiting code request. Does not request a code or publish.

### `start_substack_verification`

Request a Substack verification code in this conversation.

- **Use it when:** The owner wants to continue a publishing request that needs verification.
- **Access:** The connected Substack account owner.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `connectionId`
- **Accepted fields:** `connectionId`
- **Conditional fields:** None
- **Returns:** A code prompt, or confirmation without a code. Confirmation may resume previously approved articles; check their status.

### `complete_substack_verification`

Submit the Substack code provided by the user.

- **Use it when:** The owner supplies the code for this connection and code request. Do not guess or automatically repeat it.
- **Access:** The connected Substack account owner.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `connectionId`, `id`, `code`
- **Accepted fields:** `connectionId`, `id`, `code`
- **Conditional fields:** None
- **Returns:** Connection confirmation and article recovery status. Check a known schedule or retry the same saved draft if none exists.

### `cancel_substack_verification`

Cancel one Substack code request.

- **Use it when:** The owner asks to cancel the verification request.
- **Access:** The connected Substack account owner.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `connectionId`, `id`
- **Accepted fields:** `connectionId`, `id`
- **Conditional fields:** None
- **Returns:** Code-request cancellation. Does not cancel schedules, delete drafts, or disconnect the publication.

### `verify_substack`

Request and enter a Substack code in your current conversation.

- **Use it when:** Substack asks you to confirm before scheduling or publishing. Check status, request a code if needed, then submit the code the user provides here. If already confirmed, skip code entry.
- **Access:** The connected Substack account owner; an eligible plan is required.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `action`, `connectionId`
- **Accepted fields:** `action`, `connectionId`, `id`, `code`
- **Conditional fields:** None
- **Returns:** A plain prompt and code request details, or connection confirmation. Poll a known schedule afterward. If the failed attempt returned only a draft, promptly retry that same draft with the original settings; existing schedules are checked before creation. Confirmation alone does not mean scheduled or published.

### `list_linkedin_article_destinations`

Refresh and list LinkedIn article profiles, Company Pages, and newsletters. Does not publish content.

- **Use it when:** Call before scheduling a LinkedIn article when the author or newsletter is not explicit.
- **Access:** Connected personal-account LinkedIn integration with article publishing access.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** None
- **Accepted fields:** `authorUrn`, `refresh`
- **Conditional fields:** None
- **Returns:** Available authors, organizations, and newsletters.

### `list_medium_publications`

List the Medium publications the connected account can submit stories to. Does not publish content.

- **Use it when:** Call before scheduling a Medium article to a publication rather than the personal profile, so the user can confirm the destination and whether it publishes directly or goes to editorial review.
- **Access:** Connected personal-account Medium integration.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `refresh`
- **Conditional fields:** None
- **Returns:** Connection status and each publication's id, name, and whether the account can publish directly (canPublish) or would submit for editorial review.

### `list_scheduled_items`

Review Notes and articles together with their destinations, times, and readiness checks.

- **Use it when:** Use to audit upcoming publishing before changing or resubmitting an item.
- **Access:** Personal account, or authorized team Notes; team articles are not included.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `kind`, `status`, `from`, `to`, `limit`, `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** Schedule ids, revisions, readiness checks, issues, and suggested next actions based on stored status, not a fresh check of the publishing platform.

### `get_scheduled_item_readiness`

Inspect one scheduled Note or article before making changes.

- **Use it when:** Use the schedule id to check the current revision and any missing publishing elements.
- **Access:** Authenticated personal account; the schedule must belong to you.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** `id`
- **Accepted fields:** `id`, `kind`
- **Conditional fields:** None
- **Returns:** The revision, linked draftId, destination, readiness checks, and next action. Read article content with get_draft using draftId, or queued Note text with get_note using the schedule id. Article content is the local draft, not a verified copy of the platform schedule.

### `amend_scheduled_item`

Preview and confirm a time change for a scheduled Note or article.

- **Use it when:** Read readiness first, preview the new time, and apply only after user confirmation.
- **Access:** Authenticated personal account; the schedule must belong to you.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `id`, `expectedRevision`, `scheduledFor`
- **Accepted fields:** `id`, `kind`, `expectedRevision`, `scheduledFor`, `timezone`, `apply`
- **Conditional fields:** None
- **Returns:** A preview when apply is omitted or false; the updated schedule when apply is true. This changes timing, not content, media, audience, or destination.

### `reschedule_scheduled_item`

Move an authorized queued Note or article to a new time.

- **Use it when:** Use after confirming the existing item and replacement time with the user.
- **Access:** Authenticated personal account; the schedule must belong to you.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `id`, `scheduledFor`
- **Accepted fields:** `id`, `kind`, `scheduledFor`, `timezone`
- **Conditional fields:** None
- **Returns:** The revised schedule and current destination state.

### `cancel_scheduled_item`

Cancel an authorized queued Note or article without deleting its source draft.

- **Use it when:** Use only after the user clearly identifies the scheduled item to cancel.
- **Access:** Authenticated personal account; the schedule must belong to you.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `id`
- **Accepted fields:** `id`, `kind`
- **Conditional fields:** None
- **Returns:** The item kind, id, and cancellation status. Cancellation does not retract published content.

## Media

### `upload_media`

Upload supported image or video bytes for later use in an authorized publishing workflow.

- **Use it when:** Use when an agent has media bytes, a data URI, or a file the user attached in ChatGPT that a publishing tool cannot fetch directly.
- **Access:** Eligible plan and authenticated upload access.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `kind`
- **Accepted fields:** `kind`, `sourceType`, `url`, `data`, `mimeType`, `fileName`, `file`
- **Conditional fields:** None
- **Returns:** A public media URL and reusable media metadata.

## Inspiration

### `list_inspiration_posts`

Browse inspiration posts saved by the authenticated user.

- **Use it when:** Use when the user asks to draw from their saved inspiration library.
- **Access:** Authenticated inspiration read access.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `limit`, `platform`, `tag`
- **Conditional fields:** None
- **Returns:** Saved inspiration summaries and source context.

### `get_benchmark_inspiration`

Read saved writing experiments and optional inspiration for eligible pilot accounts.

- **Use it when:** Use only when the tool is visible and the user asks for eligible benchmark inspiration.
- **Access:** Conditional pilot access.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** None
- **Conditional fields:** None
- **Returns:** Eligible experiment summaries and supporting inspiration.

### `prepare_benchmark_inspiration`

Prepare low-confidence draft comparisons from saved examples for eligible pilot accounts.

- **Use it when:** Use only when visible, with the user expecting review rather than automatic publication.
- **Access:** Conditional pilot access.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `recordId`, `niche`
- **Accepted fields:** `recordId`, `niche`
- **Conditional fields:** None
- **Returns:** Reviewable comparison material; it does not publish content.

## Audience

### `create_reader_reply_draft`

Save a reply for review; generate in the writer’s voice when text is omitted.

- **Use it when:** Save a reviewable response before deciding whether to publish.
- **Access:** Existing MCP capability and selected-publication ownership.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `activityId`
- **Accepted fields:** `activityId`, `text`, `substackConnectionId`
- **Conditional fields:** None
- **Returns:** Saved draft and full review context; nothing is published.

### `update_reader_reply_draft`

Edit a pending reply and record its revision.

- **Use it when:** Revise the pending reply after the user requests changes; use its current updatedAt.
- **Access:** Existing MCP capability and selected-publication ownership.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `draftId`, `text`, `expectedUpdatedAt`
- **Accepted fields:** `draftId`, `text`, `expectedUpdatedAt`, `substackConnectionId`
- **Conditional fields:** None
- **Returns:** Updated draft with a new updatedAt revision.

### `send_reader_reply_draft`

Publish one explicitly approved reply draft.

- **Use it when:** Use only after the user approves the exact reply and target; use its current updatedAt.
- **Access:** Existing MCP capability and selected-publication ownership.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `draftId`, `expectedUpdatedAt`
- **Accepted fields:** `draftId`, `expectedUpdatedAt`, `substackConnectionId`
- **Conditional fields:** None
- **Returns:** Posted draft or unconfirmed SENDING state. Recovery is app-only in Narrareach Activity; never blindly retry with a new draft.

### `list_reader_reply_drafts`

List saved replies for the selected publication.

- **Use it when:** Find pending or previously handled replies for the selected publication.
- **Access:** Existing MCP capability and selected-publication ownership.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `status`, `activityId`, `limit`, `substackConnectionId`
- **Conditional fields:** None
- **Returns:** Saved drafts with text, status, and current revision.

### `list_reader_activities`

List owned Substack likes, comments, and restacks.

- **Use it when:** Use to review the audience inbox or locate a comment before replying. New items arrive in the Inbox; History holds the activity imported at connect plus items moved out of the Inbox (handled or replied). Use range to see the dates each state covers.
- **Access:** Reader activity read access for the selected publication.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `state`, `type`, `sort`, `cursor`, `limit`, `substackConnectionId`, `intent`
- **Conditional fields:** None
- **Returns:** Owned reader activity (newest first with sort time; ranked by reply priority with sort relevance), with pagination, the date range of the page and of the requested state, and sync freshness.

### `reply_to_reader_activity`

Publish a reply to an owned, replyable Substack comment.

- **Use it when:** Use only after the user approves the reply and target comment.
- **Access:** Reader activity write access for the selected publication.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `activityId`, `text`
- **Accepted fields:** `activityId`, `text`, `idempotencyKey`, `substackConnectionId`
- **Conditional fields:** None
- **Returns:** Reply confirmation and updated inbox state.

### `update_reader_activity`

Move an owned reader activity item between Inbox and History.

- **Use it when:** Use when the user asks to triage a specific activity item.
- **Access:** Reader activity write access for the selected publication.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `activityId`, `triageState`
- **Accepted fields:** `activityId`, `triageState`, `substackConnectionId`
- **Conditional fields:** None
- **Returns:** The updated activity state.

## Analytics

### `get_platform_analytics`

Read supported account and post analytics, or stored metrics. Metrics a platform does not report are null, not 0.

- **Use it when:** Use for platform-specific performance questions, including connected LinkedIn posts.
- **Access:** Eligible plan and a connected platform in your personal account.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** `platform`
- **Accepted fields:** `platform`, `recentLimit`
- **Conditional fields:** None
- **Returns:** Available platform metrics with source and time-window context.

### `list_social_posts`

List your own posts on connected social accounts, including ones published outside Narrareach, with the latest metrics each platform reported.

- **Use it when:** Use to compare performance across all of a writer’s Instagram, Threads, Facebook, LinkedIn, Bluesky, Pinterest, TikTok or X posts over a period, not only those sent through Narrareach.
- **Access:** Eligible plan and a connected social account in your personal account.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `platform`, `source`, `from`, `to`, `includeDeleted`, `limit`, `cursor`
- **Conditional fields:** None
- **Returns:** Posts with platform, account, source (narrareach or external), URL, a content excerpt, published time, and likes, comments, shares, saves, sends, clicks, views, reach, impressions, follows and reposts (null when not reported), plus a page cursor.

### `refresh_medium_stats`

Sync Medium stats from Medium and store them. Does not publish content.

- **Use it when:** Use when no Medium stats are stored yet or the writer asks for fresh Medium numbers.
- **Access:** Eligible plan and a connected Medium account in your personal account.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** None
- **Accepted fields:** `recentLimit`
- **Conditional fields:** None
- **Returns:** Medium account and post stats, as get_platform_analytics returns them.

### `refresh_substack_benchmark`

Recompute and save the Substack Notes benchmark from the latest public notes. Does not publish content.

- **Use it when:** Use when the writer asks to update an old benchmark score from get_platform_analytics. Defaults to the saved benchmark publication, then the default connected Substack publication.
- **Access:** Eligible plan in your personal account. Limited to once every 6 hours; when limited, the saved benchmark is returned unchanged.
- **Account selection:** Personal account only; do not send workspace or writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** None
- **Accepted fields:** `publicationUrl`
- **Conditional fields:** None
- **Returns:** The average score, baseline score, analysis time, note count, and whether the benchmark was refreshed or rate limited.

### `get_stats_insights`

Read stored Narrareach Stats insights for a selected period.

- **Use it when:** Use for reach, engagement, conversion, publishing rhythm, timing, and audience-snapshot questions.
- **Access:** Eligible plan and Stats read access.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. This tool does not accept writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `period`, `from`, `to`, `platforms`, `contentTypes`, `publicationId`, `workspace`
- **Conditional fields:** None
- **Returns:** Stored Stats outcomes with the selected period and evidence context.

## Voice

### `get_voice_profile`

Read the writer's voice profile: how they sound, their do and don't rules, topics, stances, real material, instructions, and a few of their own posts as examples.

- **Use it when:** Call before drafting or rewriting anything in the writer's voice.
- **Access:** Accounts with voice profiles enabled (rolling out).
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** No.
- **Required fields:** None
- **Accepted fields:** `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** The voice profile, example posts, and whether this connection can save to it.

### `save_voice_preference`

Save one writing preference the writer has just stated as a rule in their voice profile.

- **Use it when:** Use when the writer states a lasting preference in their own words, such as "stop ending with a moral". Do not infer a preference from one edit.
- **Access:** Accounts with voice profiles enabled (rolling out). Your own voice, or a team writer's voice if you are a workspace owner or manager. Up to 5 saves per day per voice.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `kind`, `text`
- **Accepted fields:** `kind`, `text`, `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** Whether the rule was saved or already existed. The writer can undo it in Narrareach.

### `add_voice_material`

Save a real story, number, opinion, or example the writer has just shared to their material bank.

- **Use it when:** Use when the writer supplies something of their own that future drafts should draw on. Never save anything they did not say.
- **Access:** Accounts with voice profiles enabled (rolling out). Your own voice, or a team writer's voice if you are a workspace owner or manager. Up to 20 saves per day per voice.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `type`, `text`
- **Accepted fields:** `type`, `text`, `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** Whether the material was saved or already existed.

### `decide_voice_suggestion`

Record the writer's answer to one suggestion about how they write: approve, dismiss, or ask later.

- **Use it when:** Use only after asking the writer about a suggestion from get_voice_profile and hearing their answer. One suggestion per call.
- **Access:** Accounts with voice profiles enabled (rolling out). Your own voice, or a team writer's voice if you are a workspace owner or manager.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `suggestionId`, `decision`
- **Accepted fields:** `suggestionId`, `decision`, `text`, `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** The recorded decision and how many suggestions remain.

### `update_voice_rule`

Reword one rule in the writer's voice profile.

- **Use it when:** Use when the writer asks to change a rule. Rule ids come from get_voice_profile.
- **Access:** Accounts with voice profiles enabled (rolling out). Your own voice, or a team writer's voice if you are a workspace owner or manager.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `ruleId`, `text`
- **Accepted fields:** `ruleId`, `text`, `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** Whether the rule changed.

### `remove_voice_rule`

Remove one rule from the writer's voice profile.

- **Use it when:** Use when the writer asks to drop a rule. Rule ids come from get_voice_profile.
- **Access:** Accounts with voice profiles enabled (rolling out). Your own voice, or a team writer's voice if you are a workspace owner or manager.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** `ruleId`
- **Accepted fields:** `ruleId`, `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** Whether the rule was removed.

### `undo_voice_change`

Undo the most recent change to the writer's voice profile.

- **Use it when:** Use when the writer asks to undo the last change to their voice.
- **Access:** Accounts with voice profiles enabled (rolling out). Your own voice, or a team writer's voice if you are a workspace owner or manager.
- **Account selection:** Personal account by default; pass workspace for an authorized team workspace. Pass writer with workspace to select a team writer.
- **Changes data:** Yes. Confirm the intended target and outcome before calling.
- **Required fields:** None
- **Accepted fields:** `workspace`, `writer`
- **Conditional fields:** None
- **Returns:** Whether a change was undone, and which one.
