MCP server
SuperDuperSEO is a remote MCP server (Streamable HTTP): https://app.superduperseo.com/mcp. An agent with it can connect a site, write and publish pages, and see how the site does in search.
Connect
- Claude Code:
claude mcp add --transport http --scope user superduperseo https://app.superduperseo.com/mcp, then/mcp, choose superduperseo, Authenticate. - Claude, ChatGPT, Cursor and other clients: add a custom connector or MCP server with the URL
https://app.superduperseo.com/mcpand sign in when asked. - Agents that run on their own: send an account API key (https://app.superduperseo.com/settings/api) as
Authorization: Bearer sf_....
Sign-in is OAuth 2.1, and your client handles it. A call without credentials answers 401 with WWW-Authenticate: Bearer resource_metadata="https://app.superduperseo.com/.well-known/oauth-protected-resource/mcp". Clients register themselves (RFC 7591), use PKCE (S256), and the user approves once on a consent screen. Connected apps can be removed in Settings, API.
How to use it
- If the user skipped setup in the app,
get_setupsays what's missing (pages a day, author, topics, connection, balance) and which tool fills it. Until it's done, every answer ends with the same note. - Start with
get_site_setupfor a site. Runcheck_siteafter every deploy and fix what it lists. - Errors say what to do next (
Next: ...). - Tools that cost money, or change or remove something, show a preview first and act on
confirm: true. Show the user the preview. - Pages with search traffic cannot be removed (unpublish_post refuses them).
- At most 120 calls a minute per account.
Resources: sds://docs/setup (the setup guide) and sds://{site}/posts/{slug} (each published post as markdown). Prompt: set_up_blog (site, framework).
Tools
Set up a site
list_sites: List sites
The sites in this SuperDuperSEO account: how each is served, whether it shows its pages yet (connection: waiting = the site has not read from us, reading = it has but no page is live, live, verified), its SEO check, page counts and any setup still missing (get_setup).
Read only.
No parameters.
create_site: Add a site
Add a website to the account. SuperDuperSEO researches it in the background (topics, keywords, strategy). It gets 3 pages a day unless pages_per_day says otherwise; daily writing (and spend) starts once the site shows its first page and the account has balance. set_pace changes it later.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
hostname |
string | yes | The site, e.g. example.com |
language |
string | Content language, default en | |
country |
string | Target country, default US | |
pages_per_day |
integer | Pages a day, default 3; 0 for none |
get_site_setup: How to connect a site
Everything needed to make a site read its pages, SEO tags and sitemap from SuperDuperSEO: the content API, the key variable, the starter for the framework, the route map, webhook and the current state. Start here.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
framework |
"nextjs" \ | "cloudflare" \ | "other" |
create_site_key: Create a site key
A secret key the site's server code uses to read its content (shown once; store it as SUPERDUPERSEO_CONTENT_KEY in the server environment, never in code). With rotate, the old key keeps working 7 days.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
rotate |
boolean | Replace the current key (it keeps working 7 days) | |
confirm |
boolean | Required with rotate |
revoke_site_key: Revoke a site key
Stop a site key at once (the site stops getting content with it). Needs confirm:true.
Changes or removes something: shows a preview first, confirm: true does it.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
key_prefix |
string | yes | The key prefix, e.g. sds_live_ab12 |
confirm |
boolean |
add_webhook: Add a webhook
We POST to this URL (signed) when a page is published, updated or removed, so the site can refresh it. Returns the signing secret once: store it as SUPERDUPERSEO_WEBHOOK_SECRET.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
url |
string | yes | https URL on the site, e.g. https://example.com/api/revalidate |
test_webhook: Test a webhook
Send a signed test call to a webhook and report whether the site answered 2xx.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
webhook_id |
string | yes |
check_site: Check the live site
Fetch the live site like a search engine (no JavaScript) and compare it with what SuperDuperSEO published: canonical, title, description, structured data, one h1, server rendering, robots.txt, sitemap, 404s, Search Console. Returns verified or each issue with its fix. Run after every deploy.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
get_site_status: Site status
Whether a site shows its pages yet (connection), the last SEO check result, Search Console state and CMS, without running a new check.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
update_site: Change site settings
The site's organisation details for search engines: its name (WebSite and Organization name, og:site_name, the feed and llms.txt), a short description, its logo, and its profiles elsewhere (X, LinkedIn, Facebook; used as sameAs). Use the name the site calls itself on its homepage. "" clears a field. Pages served by SuperDuperSEO are rebuilt at once; pages on another CMS pick it up on their next update. undo_activity puts the old details back.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
name |
string | The brand name, e.g. Kickmyass (not a page title) | |
description |
string | One or two sentences about the site | |
logo_url |
string | https:// address of a square logo, at least 512px | |
twitter_url |
string | ||
linkedin_url |
string | ||
facebook_url |
string |
set_routes: Change where pages live
Change the paths a site serves its posts, author pages and topic pages at (e.g. /blog/{slug} to /articles/{slug}). Every page that moves keeps a 301 from its old URL. Only for sites served by SuperDuperSEO. The first call shows what moves and the search traffic at stake; confirm:true applies it. Deploy the frontend for the new paths first: the SDK follows site.routes, hand-written routes need a change.
Changes or removes something: shows a preview first, confirm: true does it.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
post_path |
string | e.g. /blog/{slug}, /articles/{slug}, /{slug} | |
author_path |
string | e.g. /blog/author/{slug} | |
topic_path |
string | e.g. /blog/topic/{slug} | |
confirm |
boolean |
connect_search_console: Connect Search Console
Start Search Console verification for a site: returns the DNS TXT record to add at the domain's DNS provider. Then check_search_console.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
reissue |
boolean | Ask Google for a new token |
check_search_console: Check Search Console verification
Ask Google whether the DNS TXT record is in place; on success the site is added to Search Console and its sitemap submitted.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
switch_site_to_cms: Serve the site from SuperDuperSEO
Move a site onto SuperDuperSEO as its CMS (its old CMS is kept, switched off, for rollback). Dry run first by default; the real switch needs confirm:true and a verified check_site.
Changes or removes something: shows a preview first, confirm: true does it.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
dry_run |
boolean | ||
confirm |
boolean |
delete_site: Delete a site
Delete a site and everything it owns: its pages stop being served at once, and its plan, voice, rules, keys, redirects and history are deleted. The balance stays. Cannot be undone. Without confirm it shows what goes; the user must say to delete it, then call with confirm:true and hostname set to the site's address exactly.
Changes or removes something: shows a preview first, confirm: true does it.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
confirm |
boolean | ||
hostname |
string | The site's address, typed as confirmation |
Finish setup
get_setup: What setup is missing
For each site (or one): whether its setup is done, and for anything missing (pages a day, author, topics, connection, balance) the tool that fills it. SuperDuperSEO writes nothing for a site until all five are done. Start here when the user skipped setup in the app.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | The site: its hostname (example.com) or id |
set_author: Set who signs the pages
Make a person the main author of a site: their name signs new pages (byline and Person structured data). Creates the author, or links one the account already has (author_id). Ask the user who it should be; usually them.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
name |
string | Full name, e.g. Simon Sovič. Not needed with author_id | |
bio |
string | One or two sentences: who they are and why they know the topic | |
job_title |
string | ||
url |
string | Their personal site or profile | |
linkedin_url |
string | ||
twitter_url |
string | ||
image_url |
string | ||
author_id |
string | An author the account already has (from another site) |
set_voice: Set how the site sounds
How a site's pages sound, used from the next page written: tone (plain, friendly, expert), depth (short, standard, in depth), who reads it, and the owner's own words about the voice (up to 500 characters, e.g. "Write like a practice manager who has tried every tool. Short sentences, real prices, no hype."). Send only what changes; ask the user first.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
tone |
"plain" \ | "friendly" \ | "expert" |
depth |
"short" \ | "standard" \ | "in depth" |
audience |
string | Who reads it, e.g. "owners and office managers of small dental clinics" | |
words |
string | How it should sound, in the owner's words |
add_topics: Add topics to write about
Add topics (search keywords, e.g. "how to price a saas product") to a site's queue; daily writing picks from it, best first. Topics already queued or written are skipped. suggest_topics gives ideas; agree on them with the user first. Free.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
topics |
string[] | yes | |
first |
boolean | Write these before the rest of the queue |
remove_topic: Remove a queued topic
Take a topic out of a site's queue so it is never written. Pages already written stay (unpublish_post removes those).
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
topic |
string | yes |
pin_topic: Write a topic next
Move a queued topic to the front of a site's queue so daily writing takes it next (pinned:false puts it back in its place). add_topics with first:true adds new topics at the front.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
topic |
string | yes | |
pinned |
boolean | Default true |
How pages are written
get_plan: How a site's pages are written
A site's voice (tone, depth, who reads it, the owner's words), its rules (always / never, with ids for update_rule), the owner's notes the writer works into pages (with ids for update_note), and its competitors. suggest_topics shows the topics queued.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
add_rule: Add a writing rule
Something the writer must always or never do on a site, used for every page written and every refresh: either a rule in plain words (rule: "Never name a competitor in a page title") or a word swap (say: "clinic", instead_of: "practice"). fix_existing_pages:true also changes the swap on the site's pages that already exist, live ones included (undo_activity puts them back). Ask the user first.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
rule |
string | ||
say |
string | The words to use | |
instead_of |
string | The words to replace | |
fix_existing_pages |
boolean |
update_rule: Turn a rule on, off, or remove it
on:false stops the writer following a rule from the next page (on:true brings it back); remove:true deletes it. Pages already written keep their words. Rule ids are in get_plan.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
rule_id |
string | yes | |
on |
boolean | ||
remove |
boolean |
add_note: Add the owner's experience
A story, number or opinion from the owner, in their words (up to 2000 characters, e.g. "Most no-shows were people who booked more than three weeks out."). The writer works it into the site's pages where the topic fits, and never invents details beyond it. draft (default true) also writes a draft page from it, which waits in the site's pages and costs nothing unless published. Only add what the user tells you.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
text |
string | yes | |
draft |
boolean |
update_note: Change or remove a note
Change a note's words (text), give a note without a site to this one (assign:true), or stop using it (remove:true; pages that use it keep their words). Note ids are in get_plan.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
note_id |
string | yes | |
text |
string | ||
assign |
boolean | ||
remove |
boolean |
set_competitors: Set who a site competes with
The sites a site competes with (up to 3 addresses, e.g. ["weave.com"]); replaces the list, [] clears it. We read their sitemap and homepage for what they write about. comparison_topics:true also queues comparison topics against each ("acme vs weave", "acme vs weave pricing"); free until a page goes live. Ask the user first.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
competitors |
string[] | yes | |
comparison_topics |
boolean |
Write and publish
list_posts: List posts
A site's pages: published, drafts (with any scheduled time), failed, or all; newest first.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
status |
"published" \ | "draft" \ | "failed" \ |
limit |
integer | ||
offset |
integer |
get_post: Get a post
One page of a site by slug. With version, an earlier version (see get_post_history). By default the body as stored, ready to edit with update_post (the byline, CTAs and footer are added when it is published); as_published:true returns the page exactly as served, with its SEO fields.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
slug |
string | yes | The post's slug (or its URL) |
format |
"markdown" \ | "html" | |
as_published |
boolean | ||
version |
integer | Read an earlier version (get_post_history lists them) |
create_draft: Create a draft
Add a draft page to a site. Either give the page yourself (title + content, markdown by default; free), or give only a keyword and SuperDuperSEO writes it with its own research, the site's voice and internal links (costs the site's page price from the balance; the first call shows the price, confirm:true writes it). Drafts are never published by this tool.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
title |
string | Title (H1 and SEO title) of a page you wrote | |
content |
string | The body of a page you wrote (no title heading needed) | |
format |
"markdown" \ | "html" | |
keyword |
string | The search query the page targets. Alone: we write the page | |
slug |
string | URL slug (derived from the title when left out) | |
description |
string | Meta description (derived from the body when left out) | |
template |
"ARTICLE" \ | "LISTICLE" \ | "HOWTO" \ |
confirm |
boolean | Confirms the page price when we write the page |
update_post: Edit a post
Change a page's title, meta description, body, slug, author or CTAs. A published page is updated on the live site at once. Changing the URL of a published page needs confirm:true (on SuperDuperSEO the old URL redirects; on another CMS it stops working, so pages with search traffic keep their URL).
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
slug |
string | yes | The post's slug (or its URL) |
title |
string | ||
description |
string | ||
content |
string | The full new body (get_post returns the current one) | |
format |
"markdown" \ | "html" | |
new_slug |
string | ||
author |
string | Author id or name, one of the site's authors | |
suppress_ctas |
boolean | true: no calls to action on this page | |
confirm |
boolean |
publish_post: Publish a post
Publish a draft on its site now (a page that was live before returns to its old URL). Only hard problems block it (thin content, invalid structured data); the quality score comes back as advice.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
slug |
string | yes | The post's slug (or its URL) |
get_post_history: Post history
The versions of a page served by SuperDuperSEO (the last 20): when, by whom (editor, an agent, automation...) and what changed. Read one with get_post {version}; restore one with rollback_post.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
slug |
string | yes | The post's slug (or its URL) |
rollback_post: Restore an earlier version
Make an earlier version of a page current again (its text, title, description, feature image and author). It is published as a new version, the URL never changes, and calls to action follow the current rotation. The first call shows what changes; confirm:true restores.
Changes or removes something: shows a preview first, confirm: true does it.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
slug |
string | yes | The post's slug (or its URL) |
version |
integer | yes | |
confirm |
boolean |
schedule_post: Schedule a post
Publish a draft later: at a given time (15 minutes to 30 days ahead), or without a time in the site's publishing queue, which spaces pages out.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
slug |
string | yes | The post's slug (or its URL) |
at |
string | ISO 8601 time; leave out for the queue |
unpublish_post: Unpublish a post
Take a page off its site (it becomes a draft). Its URL then answers 410, or 301 to redirect_to (merging it into another page). Pages with search traffic stay live. The first call shows what happens; confirm:true does it.
Changes or removes something: shows a preview first, confirm: true does it.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
slug |
string | yes | The post's slug (or its URL) |
redirect_to |
string | Path on the site or https URL the old URL should redirect to | |
confirm |
boolean | ||
confirm_unmeasured |
boolean | The user accepts removing it although its search traffic cannot be measured |
add_redirect: Add a redirect
On a site served by SuperDuperSEO: make a path redirect (301) to another path or https URL, or answer 410 (gone:true). Chains are collapsed. Not over a live post (use unpublish_post with redirect_to).
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
from |
string | yes | Path on the site, e.g. /old-page |
to |
string | Path on the site or https URL | |
gone |
boolean | Answer 410 instead of redirecting |
remove_redirect: Remove a redirect
Remove a redirect added with add_redirect. Redirects made automatically (slug changes, unpublished pages) protect old links and stay.
Changes or removes something: shows a preview first, confirm: true does it.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
from |
string | yes |
Pace, publishing and balance
set_pace: Set pages a day
How many pages a day SuperDuperSEO writes and publishes for a site (0 for none), paid from the prepaid balance at the site's page price. A site writes once it shows its first page and the account has balance. Raising the daily spend shows the new cost first; confirm:true applies it.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
pages_per_day |
integer | yes | |
confirm |
boolean |
pause_site: Pause a site
Stop daily writing for one site. Its published pages stay live; nothing is charged while paused. resume_site starts it again.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
resume_site: Resume a site
Start daily writing again for a site paused with pause_site (or in the app). Says whether it writes today and, if not, what it waits for.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
set_publishing: How a site publishes
How a site's pages go live: review_before_publishing (every page waits for the user), quality_floor (40-90; pages scoring under it are held, default 65), publishing hours (hours_from / hours_to, 0-23 in the account's time zone), gifs (a fitting GIF in pages), auto_refill_topics (add researched topics when the queue runs low). Send only what changes; with none it shows the current settings. Ask the user first. undo_activity reverses a change.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
review_before_publishing |
boolean | ||
quality_floor |
integer | ||
hours_from |
integer | ||
hours_to |
integer | ||
gifs |
boolean | ||
auto_refill_topics |
boolean |
set_adult_mode: Adult content mode
For sites about adult products: pages go through a separate writer and checks at a different price per page, from the next page. Pages a day stay the same. Without confirm it shows both prices; tell the user, then confirm:true switches it. undo_activity switches it back.
Changes something.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
on |
boolean | yes | |
confirm |
boolean |
get_balance: Balance and prices
The account balance, what a page costs on each site, each site's pages a day and spend, whether it writes today (and if not, why), and how long the balance lasts. Prepaid only: every page SuperDuperSEO writes is paid from the balance, charged when it goes live (pages waiting to go live are reserved). Read only: balance is added by the user in the app; set_pace changes a site's pace.
Read only.
No parameters.
Inbox and activity
get_inbox: What needs the user
The user's inbox, the same list as the app's Home: pages waiting for approval, failed publishes, a site not connected, site check issues, missing setup, low balance, few topics left, pages held for quality, and a weekly suggestion. Each item says the tool that fixes it, or that only the user can.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | The site: its hostname (example.com) or id |
get_activity: What happened
What happened on the user's sites, newest first: pages published, held, refreshed, edited, linked, redirects and settings changed, with who did it (SuperDuperSEO, the user, or an agent), why, and what it cost. Events marked undoable can be reversed with undo_activity.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | The site: its hostname (example.com) or id | |
who |
"everyone" \ | "you" \ | "agent" \ |
kind |
"published" \ | "held" \ | "refreshed" \ |
before |
string | An event id from a previous answer: events older than it | |
limit |
integer |
undo_activity: Undo something
Reverse an event from get_activity that is marked undoable: take a published page down, put it back, restore the version before an edit or refresh, set a pace back, pause or resume, move page addresses back, remove a redirect. The first call says what it will do; confirm:true does it. Pages with search traffic stay live.
Changes or removes something: shows a preview first, confirm: true does it.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
event_id |
string | yes | |
confirm |
boolean | ||
remove_unmeasured |
boolean | Take a page down even though its search traffic can't be measured (Search Console not connected) |
Insight
get_seo_report: SEO report
How a site does in search: clicks, impressions, position and top pages from Search Console (last 30 days), pages nearly on page one, pages losing clicks, indexing, content health and the last live-site check.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
suggest_topics: Suggest topics
What to write next for a site: the topics already queued, the topics our research found for it (not queued yet), and with fresh:true new AI suggestions that fill gaps (each flagged when it would compete with an existing page). add_topics queues the ones the user wants. Free.
Read only.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
site |
string | yes | The site: its hostname (example.com) or id |
fresh |
boolean | Also ask for new suggestions (up to 10 times an hour) | |
count |
integer |