# ABCDEF Studio MCP server: agent guide

ABCDEF Studio manages blog content for agencies and brands: topics in a Content Queue, AI-written outlines and drafts, Article Health checks against each site's rules, approval, and publishing to WordPress, Shopify and custom sites. This guide is for AI agents connecting to its MCP server. It is generated from the server's own code, so it matches what the server does.

## Connecting

- Endpoint: `https://abcdef.studio/mcp` (Streamable HTTP, JSON responses, no server-sent events).
- Sign-in: OAuth 2.1 with PKCE (S256) and Dynamic Client Registration. An unauthenticated call gets a 401 whose `WWW-Authenticate` header points at the protected resource metadata (`https://abcdef.studio/oauth-metadata?doc=resource`). The authorization server metadata is at `https://abcdef.studio/.well-known/openid-configuration`.
- On the consent screen, the person chooses which accounts to connect (all, or one) and which permissions to grant.
- Personal access keys (Your Settings, AI Connections) also work, sent as `Authorization: Bearer <key>` or `X-API-Key: <key>`. Keys are read-only.
- Rate limit: 60 requests a minute per person. Over that, the server answers 429 with `Retry-After: 60`. Wait, then retry.

## Permissions (OAuth scopes)

- `mcp:read` (Read): See your articles, drafts, outlines, Content Queue, categories and tags, images, and performance. Never changes anything. Always granted.
- `content:write` (Write): Create and edit drafts, add topics to the Content Queue, and set categories and tags. Edits never reach your site on their own.
- `media:write` (Add images): Add images to your image library and set an article's featured image.
- `publishing:write` (Publish): Approve, publish, schedule and unpublish posts on your sites, within your role and each property's approval rules. Off unless the person checks it.
- `content:delete` (Delete): Remove articles and images. Rarely needed. Off unless the person checks it.

A permission only lets you attempt a kind of action. The person's role in each account (viewer, editor, publisher, admin, owner) and each property's approval rules still apply, exactly as in the app. Every change you make is recorded as made by the person, through your app.

## Tools

### Read (always available)

- `get_overview`: What needs attention across the properties you can see: drafts and outlines waiting for review, failed sends, live posts with unpublished changes, upcoming scheduled posts, and AI drafts left this month.
  - `property` (string): Optional: one property, by its id (prp_…) or part of its name or web address. Leave out for all.
- `list_review_queue`: Drafts and outlines waiting for review, oldest first, with each one's Article Health problems. Use for "what posts are pending my review" or "what outlines are waiting".
  - `property` (string): Optional: one property, by its id (prp_…) or part of its name or web address. Leave out for all.
  - `kind` ("all" | "drafts" | "outlines"): Drafts, outlines, or both (default).
- `list_articles`: Articles by status. Status: all, outline, writing, draft, review, approved, scheduled (not yet sent), live, unpublished_changes, failed. Sorted newest first by publish date for live articles, and by last update otherwise; set sort to choose. Failed articles include the last send's error.
  - `property` (string): Optional: one property, by its id (prp_…) or part of its name or web address. Leave out for all.
  - `status` (string)
  - `search` (string): Words in the title.
  - `sort` ("published" | "updated"): published: newest publish date first (articles not yet published last). updated: most recently changed first. Default: published for live, updated otherwise.
  - `limit` (integer)
- `get_article`: One article: status, brief, outline, Article Health, approval, scheduled date and links. Set include_body for its text.
  - `id` (string, required): The article id (cnt_…).
  - `include_body` (boolean)
- `get_recent_performance`: The most recently published live posts and how they're doing: visitors, views, reading time and key events (Google Analytics), and search clicks, impressions and position (Search Console), for the last 30 days.
  - `property` (string): Optional: one property, by its id (prp_…) or part of its name or web address. Leave out for all.
  - `limit` (integer)
- `get_article_performance`: One live article's figures for 7, 30 and 90 days, where its visitors came from, its top searches, and whether Google has indexed it.
  - `id` (string, required): The article id (cnt_…).
- `list_content_queue`: Topics in the queue, in order: each one's status (such as "Outline ready: needs review"), its article id and title once one exists, its planned date when a schedule is on, and what happens at that time (unapproved articles are held, never published).
  - `property` (string): Optional: one property, by its id (prp_…) or part of its name or web address. Leave out for all.
  - `limit` (integer)
- `get_insights`: The top recommendations for getting more from Google Search, such as titles that could earn more clicks, with the estimated extra clicks each.
  - `property` (string): Optional: one property, by its id (prp_…) or part of its name or web address. Leave out for all.
  - `limit` (integer)
- `list_properties`: The properties (websites) you can see, with their account, platform, connection status and your role.
- `get_writing_guide`: A property's writing settings: audience, voice, length, default categories and tags, call to action, words to avoid, approval rules, and AI drafts left this month. Read this before create_draft, so you only ask the person about what the property doesn't already settle.
  - `property` (string, required): The property (website): its id (prp_...) or part of its name or web address.
- `list_categories`: The categories and tags a property's site has, and the property's defaults. Use the site's own names exactly.
  - `property` (string, required): The property (website): its id (prp_...) or part of its name or web address.
- `list_images`: Images in a property's library, newest first: id (ast_...), title, alt text, tags, size and address. Search matches title, alt text and tags.
  - `property` (string, required): The property (website): its id (prp_...) or part of its name or web address.
  - `search` (string)
  - `limit` (integer)

### Write (needs `content:write`)

- `create_draft`: Start a new article. Two ways: writer "ai" has ABCDEF Studio write it in the property's voice (outline first, if the property reviews outlines), which uses one AI draft from the monthly allowance; writer "provided" saves a title and body you supply. Before calling, read get_writing_guide, then ask the person, in ONE message, for everything below that they haven't told you: the topic, the key points or facts to cover, the audience, what readers should do afterward, the main search keyword, the length, pages it must link to, other pages it may link to, categories, tags, and who writes it. Offer the property's defaults where it has them. Use "default" to take a property default and "none" where the answer is none. Never invent facts. If anything is missing, this returns needs_input with the questions to ask instead of creating anything. Nothing reaches the site.
  - `property` (string, required): The property (website): its id (prp_...) or part of its name or web address.
  - `topic` (string): What the article is about, or its working title.
  - `key_points` (string): The points, facts, figures or angle it must cover, from the person. "none" lets the writer decide.
  - `audience` (string): Who it's for, or "default".
  - `purpose` (string): What readers should do or understand afterward (the call to action), or "default".
  - `primary_keyword` (string): The main search phrase, or "none".
  - `target_words` (integer or string): Length in words, or "default".
  - `required_links` (string): Pages the article must link to (addresses, one per line), or "none". Each one goes in the article; Article Health flags any that are missing.
  - `links` (string): Other pages it may link to where they fit (addresses, one per line), or "none".
  - `categories` (list or string): Category names from list_categories, or "default".
  - `tags` (list or string): Tags, or "default", or "none".
  - `writer` ("ai" | "provided"): "ai": ABCDEF Studio writes it. "provided": you supply title and body_html.
  - `title` (string): For writer "provided": the title.
  - `body_html` (string): For writer "provided": the article body as HTML (h2, h3, p, ul, ol, li, a, strong, em, blockquote). No h1: the title is separate. No images: an article has one featured image (set_featured_image).
  - `excerpt` (string): Optional for "provided": a one- or two-sentence summary.
  - `meta_description` (string): Optional for "provided": about 150 characters for search results.
  - `notes` (string): Optional: anything else the writer should know.
- `update_draft`: Change an article in ABCDEF Studio: title, body, excerpt, meta description, SEO title, slug, categories or tags. Fields you leave out stay as they are. Or set ai_instructions to have ABCDEF Studio rewrite it (uses one AI draft). Each edit is a new revision; an approved article needs approving again. Edits to a live article stay in ABCDEF Studio until someone publishes them (publish_post); changing a live article's slug changes its address, so it needs confirm_slug_change.
  - `id` (string, required): The article id (cnt_...).
  - `title` (string)
  - `body_html` (string): The article body as HTML. No images in the text: use set_featured_image.
  - `excerpt` (string)
  - `meta_description` (string)
  - `seo_title` (string)
  - `slug` (string)
  - `categories` (list or string): Category names.
  - `tags` (list or string): Tags.
  - `note` (string): What changed, for the revision history.
  - `ai_instructions` (string): Have ABCDEF Studio rewrite the draft following these instructions, instead of applying field edits.
  - `confirm_slug_change` (boolean)
- `write_draft_from_outline`: For an article whose outline is waiting for review: approve the outline and have ABCDEF Studio write the draft from it (uses one AI draft). Optional instructions guide the writing.
  - `id` (string, required): The article id (cnt_...).
  - `instructions` (string)
- `add_topic`: Add a topic to a property's Content Queue. If the property has a schedule, ABCDEF Studio writes it when its turn comes. Ask the person for a summary of what it should cover if they haven't given one.
  - `property` (string, required): The property (website): its id (prp_...) or part of its name or web address.
  - `title` (string, required)
  - `summary` (string): What it should cover.
  - `required_links` (string): Pages its article must link to (addresses, one per line). They carry into the brief when it's written, and Article Health flags any that are missing.
  - `links` (string): Other pages its article may link to where they fit (addresses, one per line).
  - `where` ("bottom" | "top"): End of the queue (default) or next up.
- `update_topic`: Change a Content Queue topic: its title, summary, or the pages its article must or may link to. Fields you leave out stay as they are; "none" clears a list. The topic id (tpc_...) comes from list_content_queue, which also shows what is saved. If its article has already been started, the links are added to that article's brief too.
  - `id` (string, required): The topic id (tpc_...).
  - `title` (string)
  - `summary` (string)
  - `required_links` (string): Pages its article must link to (addresses, one per line), or "none".
  - `links` (string): Other pages its article may link to (addresses, one per line), or "none".
- `set_categories`: Replace an article's categories and/or tags (a new revision). Use names from list_categories.
  - `id` (string, required): The article id (cnt_...).
  - `categories` (list or string): Category names. Leave out to keep them.
  - `tags` (list or string): Tags. Leave out to keep them.

### Add images (needs `media:write`)

- `upload_image`: Add an image (JPEG, PNG, WebP or GIF, up to 20 MB) to a property's image library, for use as a featured image (an article has one; images aren't placed in article text), from a public https address or as base64. By default it's cropped to the 1200x630 featured image size: look at the image and set focus to keep its subject in the frame (top for a portrait photo of a face, say). Use shape "fit" to keep the whole image on white bars, or "keep" for its own proportions. Optionally make it an article's featured image. Ask the person for alt text describing the image if you can't see it.
  - `property` (string, required): The property (website): its id (prp_...) or part of its name or web address.
  - `image_url` (string)
  - `image_base64` (string)
  - `filename` (string)
  - `title` (string)
  - `alt` (string): Describes the image for people who can't see it.
  - `tags` (list or string): Subject words, so ABCDEF Studio can match it to articles.
  - `featured_for` (string): An article id (cnt_...) to make this its featured image.
  - `shape` ("crop" | "fit" | "keep"): "crop" (default): crop to 1200x630. "fit": the whole image inside 1200x630 on white bars. "keep": its own proportions (long edge up to 2400px).
  - `focus` ("center" | "top" | "bottom" | "left" | "right"): For "crop": which part to keep. Top or bottom for a tall image, left or right for a wide one. Default center.
- `set_featured_image`: Make an image from the property's library (list_images) an article's featured image, or clear it with image "none". A new revision.
  - `id` (string, required): The article id (cnt_...).
  - `image` (string, required): The image id (ast_...), or "none".
  - `alt` (string)

### Publish (needs `publishing:write`)

- `publish_post`: Publish an article live on its site now (or, with as "site_draft", send it to the site as an unpublished draft). Also publishes pending edits to a live article. First call returns a preview: what will be sent where, Article Health, and whether it needs approving (if so, confirming approves the current revision as the person). Show the preview and ask; call again with confirm true only after they agree.
  - `id` (string, required): The article id (cnt_...).
  - `as` ("live" | "site_draft")
  - `confirm` (boolean): Leave out (or false) to get a preview of exactly what will happen. Show it to the person; call again with true only after they agree.
- `schedule_post`: Publish an article live at a set time, or cancel its scheduled time (cancel true). Times are in the property's time zone unless you include an offset, such as "2026-10-13 09:00" or "2026-10-13T09:00:00-07:00". Ask the person for the date and time if they haven't given both, and confirm the time zone. First call returns a preview (including approval, which confirming grants as the person); call again with confirm true after they agree. At that time it is checked again, and held, not published, if something changed.
  - `id` (string, required): The article id (cnt_...).
  - `at` (string)
  - `cancel` (boolean)
  - `confirm` (boolean): Leave out (or false) to get a preview of exactly what will happen. Show it to the person; call again with true only after they agree.
- `unpublish_post`: Take a live article off its site, keeping it there as a draft (and in ABCDEF Studio). Not every site connection can; the preview says. First call previews; confirm true acts.
  - `id` (string, required): The article id (cnt_...).
  - `confirm` (boolean): Leave out (or false) to get a preview of exactly what will happen. Show it to the person; call again with true only after they agree.

### Delete (needs `content:delete`)

- `delete_article`: Remove an article from ABCDEF Studio. A live article stays on its site unless remove_from_site is true (which also needs the Publish permission; on Shopify that deletes it for good). First call previews; confirm true acts.
  - `id` (string, required): The article id (cnt_...).
  - `remove_from_site` (boolean)
  - `confirm` (boolean): Leave out (or false) to get a preview of exactly what will happen. Show it to the person; call again with true only after they agree.
- `delete_image`: Remove an image from a property's library. An image an article has used is archived rather than deleted, so its history stays. First call previews; confirm true acts.
  - `property` (string, required): The property (website): its id (prp_...) or part of its name or web address.
  - `image` (string, required): The image id (ast_...).
  - `confirm` (boolean): Leave out (or false) to get a preview of exactly what will happen. Show it to the person; call again with true only after they agree.

## Working rules

- Ids: properties are `prp_...`, articles are `cnt_...`, images are `ast_...`. Tools that take an article's id call the parameter `id` (`article_id`, as results name it, also works). Properties can also be named by part of their name or web address.
- Times are in each property's own time zone unless a result says otherwise.
- Before creating a draft, gather everything the draft needs and ask the person for whatever is missing, all in one message, rather than guessing. If a write tool answers with `needs_input`, ask the person those questions, then call it again.
- Before publishing, scheduling, unpublishing or deleting, show the person exactly what will happen and get their confirmation. These tools first return a preview; only a second call with `confirm: true` acts.
- Images: each article has one featured image. Add it with upload_image (with alt text describing it), set it with set_featured_image or upload_image's featured_for, and ABCDEF Studio uploads it to the site when the article is published. Don't put images in article text.
- Never invent facts, statistics, quotes or links for an article. Use what the person gives you and what the property's own settings say.
- Each result includes a link into ABCDEF Studio. Share it when the person may want to look or finish something by hand.
