# MCP tool reference

> Every tool the Convia MCP server exposes, with exact parameters, limits, return shapes, side effects, errors and the instructions it sends clients.

> For the complete documentation index, see [llms.txt](https://docs.conviapro.com/llms.txt).

The Convia Pro MCP server exposes 38 tools that read and write one workspace's content. Each entry gives exact parameters, limits, returns and side effects. To connect first, see [Connect an AI assistant (MCP)](https://docs.conviapro.com/docs/mcp-quickstart.md).

## Protocol and conventions

The Convia MCP server speaks Streamable HTTP, statelessly: each request is an HTTP `POST` of a JSON-RPC 2.0 message to your MCP URL, and each response is `application/json`. There is no session id and no event stream.

| Item | Value |
|---|---|
| Methods | `initialize`, `ping`, `tools/list`, `tools/call`. Notifications get `202` with an empty body |
| Capabilities | `tools` only |
| Server info | `name: convia-mcp`, `version: 1.0.0` |
| Protocol versions | `2025-11-25`, `2025-06-18`, `2025-03-26`, `2024-11-05`. `initialize` echoes yours if supported, otherwise answers `2025-11-25` |
| `MCP-Protocol-Version` header | Optional. Any other value returns HTTP `400` `unsupported_protocol_version` |
| Batching | A JSON array of messages is answered with an array |
| Rate limit | 60 requests per minute per credential (per IP with no credential). Over it: HTTP `429`, `Retry-After: 60`, `{"error":"rate_limited"}` |

A successful `tools/call` returns one text item holding the result as JSON. Rules for every tool:

- **One workspace.** Every call acts on the workspace in the URL. An id from another workspace is treated as unknown.
- **Nothing publishes.** No tool publishes, schedules a post to go out, approves, or queues for approval. New posts are drafts.
- **Ids** are UUIDs from earlier tool results. Never invent one.
- **Post dates.** `scheduled_date` takes a bare `YYYY-MM-DD` (preferred), which resolves to the workspace's default posting time for that platform and weekday, or ISO 8601 with an explicit offset such as `2026-11-03T14:30:00Z`. No offset is rejected. A time more than 15 minutes past is refused.
- **Trashed** posts, episodes and clips are left out of lists and searches.
- **No AI credits.** MCP runs no AI generation inside Convia and spends no [AI credits](https://docs.conviapro.com/docs/ai-credits.md).

### Paging

`list_posts`, `list_clips`, `list_ideas` and `list_scripts` return `total_count`, `returned`, `offset`, `limit`, `has_more` and `next_offset`. Pass `next_offset` as `offset` until `has_more` is `false`. Maximum `offset`: 10,000. `list_episodes`, `list_scheduled_posts` and `list_campaigns` take only `limit` and return `count` (total matching) and `returned`.

## Server instructions

The `initialize` result returns these instructions under `instructions`. They apply to every tool.

```text
Convia is the durable memory for this workspace's content. Read from it before authoring
anything, and write finished work back to it, so that work survives the session it was made in.

The standard order for authoring is: get_brand_context for voice and audience,
get_prompt_template for the format, get_text_snippets for the workspace's own standard blocks,
search_content on type transcript to verify any claim, then list_scheduled_posts and
get_schedule_settings before choosing a date. Author the copy yourself, then write it back with
create_post or create_campaign_from_plan.

Nothing written through this server is published. Posts are created as drafts, and a draft on
the calendar still needs a human to schedule it.

Anything you can create here you can also read back and revise: list_ideas and get_idea for the
backlog, get_post for a post's body, get_script for a script's, and the matching update_ tools
to change them. Prefer revising what exists to creating a near-duplicate beside it.

To take something back, use the verb for what you mean rather than editing around it.
unschedule_posts takes posts off the calendar and returns them to draft; archive_posts puts
them aside; delete_posts moves them to the trash, where a person can still restore them. Note
that update_post does NOT unschedule: editing a scheduled post deliberately leaves it
scheduled, so that fixing a typo never silently pulls a post from the calendar. Each of these
takes up to 25 posts and a short reason, and reports per post what it did and what it refused.

When something is ambiguous, ask the user before writing. A wrong draft in the workspace costs
more to find and fix than a question costs to ask.
```

## Errors

A failed tool call returns a JSON-RPC result with `isError: true` and text `{"error": "<code>", "message": "<explanation>"}`.

| Code | Meaning |
|---|---|
| `validation_error` | Missing, malformed or out-of-range argument, or a broken rule (past date, outside a campaign window, unknown platform option) |
| `not_found` | No such id in this workspace |
| `unknown_platform` | Platform not accepted by this tool |
| `feature_disabled` | The plan lacks the capability this tool needs |
| `post_immutable` | `update_post` on a published or approved post |
| `platform_account_mismatch` | `platform` and `social_account_id` disagree |
| `ambiguous_campaign` | A campaign name matched several campaigns; candidates are listed |
| `default_template_immutable`, `platform_prompts_immutable`, `retired_content_type` | Disallowed template writes. See [Prompts and templates](#prompts-and-templates) |
| `db_error`, `internal_error` | Convia could not complete the request. Retry later |

JSON-RPC errors: `-32700` parse error, `-32600` invalid request, `-32601` method not found, `-32602` unknown tool. Connection errors (HTTP `400`, `401`, `403`, `405`, `429`) come before any tool runs; see [MCP access, permissions & audit](https://docs.conviapro.com/docs/mcp-security.md).

## Plan-gated tools

Every tool needs MCP Connections on the workspace's plan. Six also need a second capability, checked per call, or they return `feature_disabled`.

| Tool | Also requires |
|---|---|
| `get_post_analytics`, `get_web_analytics`, `get_search_queries` | Advanced Analytics |
| `create_campaign_from_plan`, `get_campaign_plan`, `update_campaign_plan` | Magic Campaign |

See [Plans & billing](https://docs.conviapro.com/docs/plans-and-billing.md) for what each plan includes.

## Read: workspace context

### get_brand_context

Returns the workspace's [Brand Brain](https://docs.conviapro.com/docs/brand-brain.md): voice, point of view, topic space, goals, ideal customer profile, content rules and the host's voice profile. Read it before writing copy or revising a template.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `speaking_host_id` | string | No | Write in a specific host's voice. Omit for the workspace's default host. An id that does not match a host returns `not_found` |

Returns `has_brand_context`, `brand_context` (the prose block Convia's own generators use), structured fields (`persona_type`, `brand`, `host`, `workspace`), and a `note` if nothing is set up.

### list_social_platforms

Lists the connected social accounts. Call it to get a `social_account_id` for `create_post`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `include_inactive` | boolean | No | Include inactive accounts. Default `false` |

Returns `platforms` (up to 100: `id`, `platform`, `display_name`, `profile_image_url`, `account_type`, `needs_reauth`, `is_active`) and `count`.

### get_schedule_settings

Returns how the workspace publishes, so dates match its real schedule. Call it before choosing any date.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `platform` | string | No | Limit defaults to one publishable platform, such as `linkedin` |

Returns `timezone`, `day_window` (`start`, `end`), `platform_defaults` (`platform`, `day_of_week`, `day_name`, `time_of_day` as `HH:MM`), `unconfigured` (connected platforms with no default), `connected_platforms` and `fallback_note`. With no default, a time falls back to the platform's best-practice hours, then the start of the posting window, which is advisory.

### get_text_snippets

Returns the workspace's reusable text blocks, such as a standard outro. Reproduce them exactly.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `name` | string | No | Return only the snippet with this exact name, case-insensitive. Omit to list all |

Returns `snippets` (up to 200: `id`, `name`, `content`), `count`, and a `note` when there are none.

### list_content_conversations

Lists AI co-editing conversations with their messages, for finding recurring themes.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `content_type` | string | No | `script`, `article` or `post` |
| `limit` | number | No | 1 to 100, default 20 |
| `messages_per_conversation` | number | No | 0 to 200, default 50, most recent kept |

Returns `conversations` (`id`, `content_id`, `content_type`, dates, `messages` with `role` and `content`, `truncated`) and `count`.

## Read: episodes, clips and transcripts

### list_episodes

Lists [episodes](https://docs.conviapro.com/docs/episodes-and-clips.md), most recently published first, with what exists for each. Do not use `status` to judge whether an episode is real: read `has_transcript`, `has_media` and `clip_count`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `status` | string | No | Filter by status, for example `draft` or `published` |
| `limit` | number | No | 1 to 200, default 50 |

Returns `episodes` (title fields, `guest_names`, `episode_number`, `season_number`, `status`, `description`, dates, `duration_seconds`, `has_media`, `has_transcript`, `is_diarized`, `transcript_word_count`, `speaker_mapping_confirmed`, `clip_count`), `count` and `returned`. No transcript text.

### list_episode_guests

Returns who appeared on which episode, with job title and company. Use it to check that a post names the right person.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `episode_ids` | string[] | No | Up to 50 episode ids. Omit for the 25 most recent episodes |

Returns `episodes` (`episode_id`, `title`, `episode_number`, `published_date`, `guests` with `id`, `name`, `title`, `company`, and `legacy_guest_name`) and `returned`. Guests who asked for their data to be removed are never returned; no confirmed guest means an empty list.

### list_clips

Lists clips with their episode and how often each was used. Keyword and metadata matching, not semantic.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `episode_id` | string | No | Only this episode's clips |
| `query` | string | No | Case-insensitive match on title, description and tags |
| `limit` | number | No | 1 to 100, default 50 |
| `offset` | number | No | Rows to skip. Default 0 |
| `max_times_used` | number | No | Only clips used at most this many times. `0` means never used |
| `not_used_since` | string | No | `YYYY-MM-DD`. No post since that date (never-used clips included) |
| `sort` | string | No | `newest` (default) or `least_used` |
| `platform` | string | No | Measure use on one platform, such as `linkedin`; usage filters and sort follow it |

Returns `clips` (`id`, `title`, `description`, `tags`, `duration_seconds`, `episode_id`, `episode_name`, `has_transcript`, `text_provenance`, `times_used`, `last_used_at`, `start_seconds`, `end_seconds`, plus `utilization_platform`, `times_used_on_platform` and `last_used_on_platform_at` with `platform`) and the paging envelope, with `warnings` if a very large workspace hits a cap. `text_provenance` (`generated`, `imported`, `unknown`) marks clip text as a summary, never speech.

### get_transcript

Returns what was said in an episode, with speakers and timestamps. Read it before quoting anyone.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `episode_id` | string | Yes | Episode id from `list_episodes` |
| `clip_id` | string | No | Limit to one clip's span. The clip must belong to the episode |
| `start_seconds`, `end_seconds` | number | No | Window, episode-relative |
| `speaker` | string | No | One speaker, by resolved name or raw label such as `Speaker 2` |
| `max_segments` | number | No | 1 to 1,500, default 400 |

Returns `episode_id`, `episode_title`, `duration_seconds`, `offset_basis` (`episode` or `clip`), `source` (`asr`, `pasted`, or `null` with no transcript), `diarized`, `speaker_mapping_confirmed`, `speakers`, `segments` (`speaker_label`, `speaker_name`, `start_seconds`, `end_seconds`, `text`), `count`, `returned`, `truncated`, `next_start_seconds` and `note`. To continue, pass `next_start_seconds` as `start_seconds`. A `null` `speaker_name` means the voice is unconfirmed: do not name that speaker. With `offset_basis: clip`, offsets count from the start of the clip.

### search_content

Keyword search across episodes, clips, posts and transcripts. Search `transcript` to verify a claim before writing it as fact.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `query` | string | Yes | Literal words to find. Not semantic |
| `types` | string[] | No | Any of `episode`, `clip`, `post`, `transcript`. Default all four |
| `episode_id` | string | No | Limit transcript and clip hits to one episode |
| `limit` | number | No | 1 to 100 per type, default 30 |

Returns `episodes`, `clips` and `posts` (each with `match_context`), `transcript_segments` (`episode_id`, `episode_title`, `speaker_label`, `speaker_name`, `start_seconds`, `text`, `match_context`), `transcript_episodes_scanned`, `transcript_scan_capped` and `note`. Transcript search opens at most 25 episodes per call; `transcript_scan_capped: true` means more may match. An empty result means these exact words were not found, not that nothing similar was said.

### get_derived

Shows what was already made from an episode, clip or idea, so you do not rebuild it.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `episode_id`, `clip_id`, `idea_id` | string | Exactly one | The source |
| `limit` | number | No | 1 to 100 per list, default 50 |

Returns `source`, `clips`, `posts` (`id`, `title`, `platform`, `status`, `scheduled_date`, `published_url`, `campaign_id`, `campaign_name`), `campaigns` and `counts`. For an idea it also returns `scripts`, `clips` is always empty and posts omit `campaign_name`.

## Read: posts, ideas, scripts and campaigns

### list_posts

Finds posts, newest first. Metadata only: use `get_post` for the body.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `body_contains` | string | No | Case-insensitive text in the body, title or description, max 120. Matches include an `excerpt` |
| `parent_webcast_id` | string | No | Only posts derived from this episode |
| `platform` | string[] | No | One or more of `youtube`, `linkedin`, `linkedin_pro`, `twitter`, `instagram`, `instagram_facebook`, `tiktok`, `facebook`, `blog`, `newsletter`, `web`, `bluesky`, `threads`, `other` |
| `status` | string[] | No | One or more of `draft`, `pending_approval`, `approved`, `in_review`, `scheduled`, `published`, `archived`, `failed`, `processing` |
| `created_after`, `created_before` | string | No | ISO datetime |
| `scheduled_after`, `scheduled_before` | string | No | ISO datetime |
| `limit` | number | No | 1 to 200, default 50 |
| `offset` | number | No | Rows to skip. Default 0 |

Returns `posts` (`id`, `title`, `platform`, `post_type`, `status`, dates, `parent_webcast_id`, `campaign_id`, and `excerpt` when searching), `count` (page length) and the paging envelope. A few legacy imported posts do not match `body_contains`.

### get_post

Reads one post in full.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `post_id` | string | Yes | Post id |

Returns `id`, `title` (internal label), `published_title` (`null` means `title` is published), `content`, `subtitle`, `seo_title`, `meta_description`, `platform`, `post_type`, `article_type`, `status`, dates, `published_url`, `social_account_id`, `parent_webcast_id`, `video_clip_id`, `campaign_id`, `media_ids`, `tags`, `meta_keywords` and `url`.

### list_scheduled_posts

Lists posts on the calendar in a date window, any status, earliest first. Check it before picking dates.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `start_date` | string | Yes | ISO 8601 with an explicit offset. Inclusive |
| `end_date` | string | Yes | ISO 8601 with an explicit offset. Inclusive |
| `platform` | string | No | One publishable platform (same list as `get_schedule_settings`) |
| `limit` | number | No | 1 to 200, default 100 |

Returns `posts` (`id`, `title`, `platform`, `status`, `scheduled_date`, `campaign_id`), `count`, `returned` and `known_statuses`.

### list_ideas

Lists the [idea](https://docs.conviapro.com/docs/ideas-and-scripts.md) backlog, newest first. Read it before proposing ideas.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `status` | string | No | `new`, `researching`, `ready`, `draft`, `in_progress`, `completed` or `archived` |
| `tags` | string[] | No | Ideas carrying any of these tags |
| `query` | string | No | Case-insensitive match on title, description or notes |
| `limit` | number | No | 1 to 200, default 50 |
| `offset` | number | No | 0 to 10,000 |

Returns `ideas` (`id`, `title`, `description`, `notes_preview` (first 280 characters), `notes_truncated`, `status`, `priority`, `tags`, `category`, `derived_count`, dates) and the paging envelope.

### get_idea

Reads one idea in full, with everything derived from it.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `idea_id` | string | Yes | Idea id |

Returns the idea's fields including full `notes` and `source_type`, plus `derived` (each with `type`, `id`, `title`, `status`), `derived_count`, `derived_by_type` and `url`.

### list_scripts

Lists scripts, newest first, with a `char_count` instead of the body.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `status` | string | No | `draft`, `in_review`, `approved`, `in_production`, `recorded`, `editing`, `published` or `archived` |
| `script_type` | string | No | `podcast`, `video`, `short` or `presentation` |
| `source_idea_id`, `linked_webcast_id` | string | No | Only scripts from this idea, or linked to this episode |
| `query` | string | No | Case-insensitive match on title or description |
| `limit` | number | No | 1 to 200, default 50 |
| `offset` | number | No | 0 to 10,000 |

Returns `scripts` (metadata, `char_count`, `word_count`, `estimated_duration_seconds`, `tags`, dates) and the paging envelope.

### get_script

Reads one script in full, including the body.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `script_id` | string | Yes | Script id |

Returns the script's fields including `content`, `notes`, `generated_from` and `url`.

### list_campaigns

Lists [campaigns](https://docs.conviapro.com/docs/campaigns.md), newest first, with beat and gap counts. The full plan is not returned.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `status` | string | No | `draft`, `active`, `paused`, `stopped`, `completed` or `archived` |
| `campaign_type` | string | No | `idea`, `trend`, `seasonal`, `guest` or `promote_episode` |
| `parent_webcast_id` | string | No | Only campaigns for this episode |
| `limit` | number | No | 1 to 100, default 25 |

Returns `campaigns` (`id`, `name`, `description`, `campaign_type`, `status`, dates, `platforms`, `keywords`, `parent_webcast_id`, `has_plan`, `beat_count`, `gap_count`, `origin` (`mcp` or `in_product`)), `count` and `returned`. Plans still being drafted in the campaign builder are not listed.

### get_campaign_plan

Reads one campaign's narrative plan. Requires Magic Campaign.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | string | Yes | Campaign id |

Returns `campaign_id`, `name`, `campaign_status`, `has_plan`, `plan` (the spine and each platform's beats, each with a `beat_uid`, its move, format, schedule offset, fulfillment status, any gap, and whether it is pinned), `beat_count`, `gap_count`, `pinned_count` and `post_count`. A campaign without a narrative plan returns `has_plan: false` and a `detail` message.

## Create

### create_post

Creates one draft [post](https://docs.conviapro.com/docs/posts.md). Read `get_brand_context` first and verify figures and quotes with `search_content`. For a coordinated set of posts, use `create_campaign_from_plan`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `content` | string | Yes | Post body. Max 50,000 characters |
| `social_account_id` | string | One of two | Connected account from `list_social_platforms`. Preferred; sets the platform |
| `platform` | string | One of two | `twitter`, `linkedin`, `linkedin_pro`, `instagram`, `instagram_facebook`, `facebook`, `youtube`, `tiktok`, `threads` or `bluesky` |
| `title` | string | No | Internal label shown only in Convia. Default `Generated - ` plus the first 50 characters of `content` |
| `published_title` | string | No | Public video title on `youtube` and `facebook` only. If omitted, `title` is published |
| `post_type` | string | No | `social` (default), `article`, `promotion`, `newsletter` or `short` |
| `article_type` | string | No | `long_form` or `newsletter` |
| `scheduled_date` | string | No | Bare `YYYY-MM-DD` (preferred) or ISO 8601 with offset. Must not have passed |
| `platform_options` | object | No | Per-platform publish settings, below |
| `source_clip_id` | string | No | Clip from `list_clips`; links the post to the clip's episode. An unknown id is an error |
| `media_ids` | string[] | No | Media already in the workspace. Unknown ids are rejected. No uploads |
| `source_idea_id` | string | No | The idea this derives from. Records lineage for `get_idea` and `get_derived` |
| `subtitle` | string | No | Article standfirst, max 200. Stays on the draft; not sent to platforms |
| `seo_title`, `meta_description` | string | No | Article SEO fields, max 60 and 500 |
| `tags` | string[] | No | Internal tags, not hashtags. Junk and date tags are removed, near-duplicates merged |

`platform_options` accepts only these keys. Unknown keys and wrong types return `validation_error` naming the allowed keys.

| Platform | Keys you can set |
|---|---|
| `instagram`, `instagram_facebook` | `media_format` (`reel` or `story`), `share_to_feed` (boolean), `trial_reel` (boolean) |
| `youtube` | `category_id` (string), `playlist_ids` (string[]), `tags` (string[]), `default_audio_language` (string) |
| All other platforms | None |

TikTok privacy and branded-content settings, YouTube Made for Kids, privacy status and publish time, and Instagram collaborator and paid-partnership labels are set by a person in the composer, never through MCP.

Returns `id`, `title`, `status` (always `draft`), and when relevant `tags`, `source_clip` (`id`, `episode_id`, `times_used`), `source_idea_id`, `scheduled_date`, `schedule_source` (`explicit` for a time you supplied), `warnings` and `url`. Side effect: a draft. With a `scheduled_date` it sits on the calendar but does not publish until a person schedules it.

### create_campaign_from_plan

Creates a multi-platform campaign, its narrative spine and every post, in one call. Requires Magic Campaign. One idea per campaign; read `get_brand_context` and `list_scheduled_posts` first.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `name` | string | Yes | Campaign name, max 200 |
| `description` | string | No | The campaign's core argument, max 4,000 |
| `keywords` | string[] | No | Max 25. Use 3 to 8 durable topic terms |
| `start_date`, `end_date` | string | Yes | `YYYY-MM-DD` or ISO 8601 with offset. Window of 90 days or less, in workspace-local days |
| `parent_webcast_id` | string | No | Episode the campaign derives from |
| `spine` | object | Yes | `through_line` (the one argument, max 1,000) and `authority_objective` (what authority it earns, max 1,000). Both required |
| `posts` | object[] | Yes | 1 to 40 posts. Fields below |

Each item in `posts`:

| Field | Type | Required | Description |
|---|---|---|---|
| `platform` | string | Yes | One publishable platform (same list as `create_post`) |
| `content` | string | Yes | Post copy, max 50,000. Use `""` for a beat held with `needed_asset` |
| `scheduled_date` | string | Yes | Bare date (preferred) or ISO 8601 with offset. Must fall inside the window and not have passed |
| `title`, `published_title` | string | No | Internal label and public title (YouTube, Facebook), max 500 each |
| `content_type` | string | No | `teaser`, `clip`, `full` (default), `article` or `announcement` |
| `move` | string | No | The narrative move this beat makes, max 500 |
| `source_clip_id` | string | No | Clip from `list_clips`. An unknown id is discarded and the beat is held as a gap |
| `needed_asset` | string | No | Describe an asset you cannot supply, max 500. The post is held as a flagged draft |
| `gap_type` | string | No | `type-1` (Convia can generate it), `type-2` (a different cut of an existing clip, default), `type-3` (needs new recording) |
| `asset_instructions` | string | No | Full brief for the missing asset, max 4,000. Added as a comment on the post |
| `tags`, `hashtags` | string[] | No | Max 20 each |

Limits per call: 40 posts, 8 platforms, a 90-day window, 500,000 characters of content. A date outside the window is rejected with its index, never moved. Bare dates on the same platform and day get different times.

Returns `campaign` (`id`, `name`, `status: draft`, `url`), `posts_created`, `scheduling` (`timezone`, `day_window`, `sources`), `gaps_held`, `gaps_flagged`, `gaps` (`beat_id`, `platform`, `needed_asset`, `gap_type`) and `warnings` (such as a platform with no connected account).

Side effects: a draft campaign and dated draft posts on the calendar. Nothing schedules, publishes or enters the approval queue until a person activates the campaign. Held beats are flagged with their brief as a comment, with one notification. If the posts fail to save, the campaign is rolled back.

### create_idea

Creates an idea. Put the reasoning (angle, audience, raw material, overlap) in `notes`, and check `list_ideas` for near-duplicates first.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `title` | string | Yes | Idea title |
| `description`, `notes` | string | No | `notes` holds the reasoning a later session should read |
| `priority` | string | No | `low`, `medium` or `high` |
| `tags` | string[] | No | Normalized on write |

Returns `id`, `title`, `status` (`new`) and `tags`.

### create_script

Creates a script, optionally linked to an idea or episode.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `title` | string | Yes | Script title |
| `description` | string | No | Short description |
| `content` | string | No | Script body, max 200,000 characters |
| `script_type` | string | No | `podcast`, `video`, `short` or `presentation` |
| `source_idea_id`, `linked_webcast_id` | string | No | Idea to derive from; episode to link |

Returns `id`, `title`, `word_count` and `url`.

### create_episode

Creates an episode record. Recording and media are added later in the app.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `title` | string | Yes | Episode title |
| `webcast_name`, `description` | string | No | Internal show or episode name; description |
| `status` | string | No | `draft` (default), `scheduled` or `published` |

Returns `id`, `youtube_title` (your title) and `status`.

## Update

### update_post

Revises a post. Only the fields you supply change. Read the post with `get_post` first if you mean to edit rather than rewrite.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `post_id` | string | Yes | Post id |
| `content` | string | No | Replaces the whole body. Max 50,000 |
| `title`, `published_title` | string | No | Internal label and public title, max 500 each. `published_title: ""` clears it so `title` is published |
| `subtitle`, `seo_title`, `meta_description` | string | No | Max 200, 60 and 500 |
| `article_type` | string | No | `long_form` or `newsletter` |
| `post_type` | string | No | `social`, `article`, `promotion`, `newsletter` or `short` |
| `scheduled_date` | string | No | Bare date or ISO 8601 with offset. Must not have passed. A bare date needs the post to have a platform |
| `platform` | string | No | Publishable platform. Cannot differ from the linked account's platform |
| `social_account_id` | string | No | Moves the post to this account; the platform follows |
| `platform_options` | object | No | Same keys as `create_post`. Merged into stored options: keys you omit are kept |

Rules: `published` and `approved` posts return `post_immutable`. A `pending_approval` post returns to `draft` (`approval_reset: true`) so the edit is reviewed. A `scheduled` post stays scheduled: `update_post` never unschedules. Titles are cleaned of markdown, quotes and labels such as `Title:`. At least one field must change. `tags`, `media_ids` and `source_clip_id` cannot be changed.

Returns `id`, `title`, `status`, `platform`, `scheduled_date`, `approval_reset`, `updated_fields`, and as relevant `schedule_source`, `warnings`, `url`.

### update_idea

Revises an idea. Omitted fields are left alone; an explicit `null` clears a field. There is no delete: set `status` to `archived`.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `idea_id` | string | Yes | Idea id |
| `title`, `description`, `notes` | string | No | New values |
| `priority` | string | No | `low`, `medium` or `high` |
| `status` | string | No | Any idea status listed under `list_ideas` |
| `tags` | string[] | No | Replaces the tags. Normalized on write |

Returns `id`, `title`, `status`, `priority`, `tags` and `updated_fields`.

### update_script

Revises a script. Supplying `content` replaces the whole body.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `script_id` | string | Yes | Script id |
| `title`, `description`, `notes` | string | No | New values |
| `content` | string | No | Replaces the body. Max 200,000 |
| `script_type` | string | No | `podcast`, `video`, `short` or `presentation` |
| `status` | string | No | Any script status listed under `list_scripts` |
| `linked_webcast_id` | string | No | Episode to link |

Returns `id`, `title`, `status`, `word_count` and `updated_fields`.

### update_campaign_plan

Amends a campaign plan before any posts exist. Requires Magic Campaign. Generates no copy and publishes nothing.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `campaign_id` | string | Yes | Campaign id |
| `beats` | object[] | No | Up to 50 beats, matched on `beat_uid` (required, from `get_campaign_plan`). Each may set `move` (max 500), `format` (max 80), `schedule_offset_days` and `pinned` |
| `remove_beat_uids` | string[] | No | Up to 50 beats to remove |

A campaign that has posts is refused, including every campaign made with `create_campaign_from_plan`: edit its posts instead. An edited beat is pinned (kept by a re-plan) unless you pass `pinned: false`. Returns `campaign_id`, `beats_updated`, `beats_removed`, `beat_count`, `gap_count` and `pinned_count`.

## Lifecycle: take posts back

`unschedule_posts`, `archive_posts` and `delete_posts` share one contract. Each post is handled on its own, so one refusal does not block the rest.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `post_ids` | string[] | Yes | 1 to 25 post ids. Duplicates are merged |
| `reason` | string | Yes | Why, max 500. The first 200 characters go to the MCP audit log, not the post |

Returns `updated` (`id`, `title`, `status`, `deleted`, `previous_scheduled_date`), `unchanged` and `refused` (each with `id` and `reason`; an unknown id is refused), and a count for each. A post already in the target state is `unchanged`, not a failure.

| Tool | Acts on posts that are | Result |
|---|---|---|
| `unschedule_posts` | `draft`, `pending_approval`, `in_review`, `failed`, `scheduled` | Status `draft`, scheduled date cleared (returned as `previous_scheduled_date`) |
| `archive_posts` | `draft`, `pending_approval`, `in_review`, `failed`, `scheduled` | Status `archived`, scheduled date cleared |
| `delete_posts` | `draft`, `pending_approval`, `in_review`, `failed`, `archived` | Moved to Trash, where a person can restore it. Purged after 30 days |

All three refuse `published` posts (retract those on the platform), `approved` posts (a person signed off) and posts being published right now. `delete_posts` also refuses `scheduled` posts: call `unschedule_posts` first, then `delete_posts`. A post already in Trash is refused by the other two.

### unschedule_posts

Takes posts off the calendar and back to draft, keeping the copy: "stop this going out, decide later". Uses the shared contract above.

### archive_posts

Puts aside work that is real but not going ahead, keeping it on record. Uses the shared contract above.

### delete_posts

Moves to Trash what should never have been created, such as a bad batch or a duplicate run. Uses the shared contract above.

## Prompts and templates

Convia has two template surfaces. **Content** templates drive long-form generators (`article`, `script`, `conversation_outline`, `webcast_description`, `chapter_markers`, `webcast_promotion`) and can hold named alternatives, one of which is the live default; `thumbnail_style` holds saved thumbnail styles with no default. **Platform** templates are one prompt per social platform. Retired thumbnail types (`thumbnail_background`, `thumbnail_text_overlay`, `thumbnail_photo_composition`, `thumbnail_refinement`) return `retired_content_type`.

### list_prompt_templates

Lists templates, metadata only.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `surface` | string | No | `content` or `platform`. Omit for both |
| `content_type`, `platform` | string | No | Limit to one content type (such as `article`) or platform (such as `linkedin`) |
| `limit` | number | No | 1 to 200, default 100 |

Returns `templates` (`id`, `surface`, `content_type` or `platform`, `post_type`, `name`, `is_default`, `resolves_as` (`default` or `available`), `char_count`, `updated_at`, and `has_best_practices` for platform templates), `count` and `note`.

### get_prompt_template

Returns one template's full text and the `{placeholder}` variables it uses.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `template_id` | string | One of two | A template id from `list_prompt_templates` |
| `surface` | string | One of two | `content` or `platform`, to get the live template |
| `content_type` or `platform` | string | With `surface` | Such as `article` or `linkedin` |
| `post_type` | string | No | Variant, such as `host` or `guest` for `webcast_promotion` |

Returns `template` (`prompt_template`, or `system_prompt` and `best_practices` for platform, plus `variables_used`) and `would_fall_back_to`: `null` when the workspace has its own, otherwise `master` (Convia's platform-wide template) or `inline_default` (the built-in default). A `warning` appears if two content templates are marked default.

### upsert_prompt_template

Saves a content template as a non-default alternative. Generation is unchanged until a manager makes it the default in **Brand Brain → AI Prompts**.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `content_type` | string | Yes | For example `article` or `script` |
| `name` | string | Yes | Short name shown in the template list |
| `prompt_template` | string | Yes | Full template text, max 50,000 characters |
| `post_type` | string | No | Variant, such as `host` or `guest` |
| `template_id` | string | No | Update an existing non-default template instead of creating one |
| `surface` | string | No | Only `content` is writable |

Returns `id`, `surface`, `content_type`, `post_type`, `name`, `is_default: false`, `promoted: false`, `variables_used`, `url` and `message`. Editing the live default returns `default_template_immutable`; writing a platform template returns `platform_prompts_immutable` (edit those in **Brand Brain → Social Platform Prompts**).

## Analytics

### get_post_analytics

Returns the latest [analytics](https://docs.conviapro.com/docs/analytics.md) for one post. Requires Advanced Analytics.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `post_id` | string | Yes | Post id |

Returns `post_id`, `platform`, `analytics` (`metrics`: all-time views, impressions, reach, reactions, comments, shares, saves, engagements, `null` if the platform does not report one; `engagement_rate`; `window_28d` for YouTube), `performance` (pace against the account's usual post of that platform and format at the same age: below, within or above; `null` until scored), `reach` (YouTube thumbnail impressions and click-through rate) and raw `snapshot` (prefer `analytics.metrics`). `analytics` is `null` until something is recorded.

### get_web_analytics

Returns sessions and key events that Convia-tagged links sent to the workspace's own site, from its Google Analytics 4 property. Requires Advanced Analytics. See [Website analytics](https://docs.conviapro.com/docs/website-analytics.md).

| Parameter | Type | Required | Description |
|---|---|---|---|
| `start_date`, `end_date` | string | No | `YYYY-MM-DD`, inclusive. Default end today (UTC), start 27 days before end |
| `group_by` | string | No | `platform` (default), `campaign` or `post` |
| `campaign` | string | No | Campaign id or exact name (case-insensitive). Near misses and shared names are refused with candidates |
| `include_untagged` | boolean | No | Add the top 20 untagged traffic sources. Default `false` |

Returns `has_ga4`, `latest_data_date`, `range` (cut off at the last collected day), `requested_range`, `key_events_configured`, `totals` (`sessions`, `engaged_sessions`, `key_events`), `site_total_sessions`, `share_of_site_sessions` (0 to 1), `rows` (at most 100), `untagged` and `note`. A `null` metric means not collected, never zero.

### get_search_queries

Returns the searches that bring people to the workspace's own site, from Google Search Console and Bing. Requires Advanced Analytics.

| Parameter | Type | Required | Description |
|---|---|---|---|
| `start_date`, `end_date` | string | No | `YYYY-MM-DD`. Default end today (UTC), start 27 days before end |
| `branded` | string | No | `all` (default), `only` or `exclude` |
| `position_min`, `position_max` | number | No | Average position bounds. 1 is the top result |
| `provider` | string | No | `all` (default), `google` or `bing` |
| `sort` | string | No | `clicks` (default) or `impressions` |
| `limit` | number | No | 1 to 500, default 50 |

Returns `has_search`, `latest_data_date` (`google`, `bing`), `range`, `filters`, `rows` (`provider`, `query`, `page` (`null` on Bing), `clicks`, `impressions`, `position`, `is_branded`), `returned` and `note`.

## Related

- [Connect an AI assistant (MCP)](https://docs.conviapro.com/docs/mcp-quickstart.md): get your MCP URL and connect.
- [Agent workflows](https://docs.conviapro.com/docs/mcp-workflows.md): these tools as step-by-step recipes.
- [MCP access, permissions & audit](https://docs.conviapro.com/docs/mcp-security.md): connection errors, roles and the audit log.
- [Glossary](https://docs.conviapro.com/docs/glossary.md): Convia terms used in tool results.

---

Source: https://docs.conviapro.com/docs/mcp-tools · Section: AI agents & MCP · Last updated: 2026-10-03
