MCP server

MCP server

The MetaMonster connector lets Claude work on your site's on-page SEO. Claude can find the pages worth fixing, analyze a page against 40+ factors, write briefs, outlines and drafts, and keep your business facts up to date. It works on the same sites, pages and drafts you see in the app.

The server is a remote MCP server at https://app.metamonster.ai/mcp.

Before you start

You need:

  • A MetaMonster account. Sign up at app.metamonster.ai with Google or with an email and password.
  • An active subscription, for everything but the quick check and the site list. quick_check_page is free with or without one: give Claude a page's URL, or a draft, and every factor that needs no AI is checked. Every other tool but list_sites needs a subscription, the read-only ones included. Without one, connecting still works, the tools are still listed, Claude is told to start with the free check, and list_sites lists your sites and says the other tools need a plan; every other tool call comes back as a payment_required error naming what needs a plan, the cheapest plan that includes it with its price, a checkout link, and that quick_check_page is free. Nothing is read, changed or charged. Once you subscribe, the same connector or key works at once (see Conventions).

Connect from Claude

This works the same in claude.ai on the web, Claude Desktop and the Claude mobile apps.

  1. Open Settings → Connectors (Customize → Connectors in some versions).
  2. Browse the connector directory and find MetaMonster.
  3. Click Connect.
  4. Sign in with your MetaMonster account.
  5. Pick the organization to authorize, if you belong to more than one.
  6. Approve.

There's no API key to copy or paste. The connector gets its own token and refreshes it.

Add it as a custom connector

If you don't see MetaMonster in the directory, add it by URL instead:

  1. Go to Settings → Connectors → Add custom connector.
  2. Enter the server URL: https://app.metamonster.ai/mcp.
  3. Sign in, pick the organization, and Approve, as above.

Revoke or switch organization

Revoke access anytime from Settings → Connected apps in MetaMonster. Revoking cuts off access immediately.

A connector is authorized for one organization. To switch, revoke it in Settings → Connected apps, then reconnect and pick the other organization. There's no in-place switch.

Connect from Claude Code, Cursor or Windsurf

These clients send an API key as a header instead of signing in. Create a key under Settings → API keys in MetaMonster. It's the same mm_ key the REST API uses, sent as a bearer token:

Authorization: Bearer mm_YOUR_API_KEY

There's no separate MCP key or scope model. An MCP call spends the same rate-limit budget and respects the same scopes as the REST call behind it (see Authentication).

Claude Code

claude mcp add --transport http metamonster https://app.metamonster.ai/mcp --header "Authorization: Bearer mm_YOUR_KEY"

Cursor / Windsurf

Add to mcp.json:

{
  "mcpServers": {
    "metamonster": {
      "url": "https://app.metamonster.ai/mcp",
      "headers": { "Authorization": "Bearer mm_YOUR_KEY" }
    }
  }
}

The endpoint is stateless Streamable HTTP. There's no session state, so any request can land on any server instance.

Example prompts

Once connected, ask in plain language. Claude picks the tools.

  • "Which pages on my site should I work on first?"
    Claude calls list_sites to find your site, then get_opportunities and lists the pages with the most to gain.
  • "Analyze https://example.com/pricing and tell me what's failing."
    Claude calls analyze_page, then shows each factor that fails, the measurement behind it, and the fix that would make it pass.
  • "Write a content brief for my page about kitchen remodeling costs."
    Claude calls generate_content_brief for the angle, then generate_content_outline for the sections, and shows you both to edit.
  • "Draft a better title and meta description for https://example.com/services."
    Claude calls generate_field_draft for each field and shows the current and proposed text side by side. For a single failing factor it uses draft_fix instead.
  • "Find keywords for a new page about emergency plumbing in Denver."
    Claude calls keyword_research and returns keyword ideas with search volume and difficulty.
  • "Which queries lost the most clicks this month?"
    Claude calls query_search_console with the query dimension, compare_to: "previous_period" and sort: "clicks_change" ascending, then shows the biggest drops.
  • "Add this testimonial to my site facts: 'They fixed our leak in an hour.' (Jane D.)"
    Claude calls add_site_facts, so every later draft for the site can use it.

Start from a page in the app

Every page in the app's page editor has Work on this with your agent in its header. It copies one prompt for any agent connected to the MCP, the Claude app or a coding agent alike. The prompt names the page and what the agent can do with it through the MCP (read its analysis and fixes, push content and drafts into MetaMonster, write or rework the page, publish), and has the agent tell you where the page stands and ask what you want before it changes anything. If you ask it to publish and it has the site's repo open, it applies only what get_page_drafts returns, commits with a MetaMonster-Page: <page id> trailer, then calls mark_page_published with exactly what it applied.

Nothing is published to your CMS from the connector. Drafts, content versions and alt text are saved in MetaMonster, and you review and publish them yourself.

Data and privacy

What the connector reads and writes. Only your organization's MetaMonster data: sites, pages, analyses, fixes, briefs, drafts, business facts and context documents. Every tool works through the v1 API, with the same access rules as the app.

One organization per connection. An OAuth token is scoped to the one organization you approve. Revoke it anytime in Settings → Connected apps.

What it doesn't see. The connector does not read your Claude chats, memory or files. It only receives the arguments of the tools Claude calls, such as a URL or the text of a testimonial, and returns their results.

Logging. Tool calls are logged for reliability and product analytics, tied to your account and organization: the tool name, whether it succeeded, how long it took, and the call's arguments and result. Anything shaped like an API key or access token is removed before it's stored.

AI providers. Briefs, drafts and other generated content are written by AI providers, as described in the privacy policy.

Support

Email support@metamonster.ai.

Tools

The server wraps a curated set of tools over the v1 API, not a 1:1 endpoint mirror. Each tool is a small workflow step (find pages, stage an edit, resolve a fix, run an analysis, generate a brief or a fix draft) so a chat agent can drive the whole verification loop, and everything the app can generate, without knowing the REST shapes underneath.

Every tool returns a short human-readable summary plus a structured JSON payload mirroring the REST data shape (snake_case field names, with the fix vocabulary below). The MCP speaks of factors and fixes: where the REST API says recommendations, tool inputs and results say fixes (fix_id, fixes_status, fix_count).

Nothing a tool generates is published to your CMS. Drafts, content versions and alt text are saved in MetaMonster for review.

Find and read

Tool What it does REST endpoint(s)
list_sites Lists the sites in your organization. Start here unless you already have a page URL. GET /sites
find_pages Searches and filters a site's pages by URL, priority, share of factors passing (min_factors_passing_pct), opportunity score, or fix presence (has_fixes). Each page carries version_state: live, live_draft (live, with unpublished draft changes), draft (planned, not live yet), published (published by your agent, not seen live yet) or not_live (the live checks stopped without seeing it). GET /sites/{siteId}/pages
get_opportunities Returns the ranked "what should I work on" report for a site: the homepage, ranked opportunity rows, and cross-page fixes. Requires an active subscription. GET /sites/{siteId}/opportunities
get_factors Returns every factor the site's pages are checked against: what it measures, whether it is AI-judged, its threshold, and which page types it applies to. Free. Read it once per site before editing. GET /sites/{siteId}/checks/rubric
quick_check_page A free check against every factor that needs no AI: title and meta length, keyword placement, H1 count, word count, JSON-LD validity, links and more. Free with or without a subscription. Takes one of: page_id (a page MetaMonster has, in its current state, saved drafts included); the content, markdown first (the body as Markdown, with title, meta_description and primary_keyword in frontmatter or as arguments; an argument beats frontmatter) or html (the page's full HTML, head included); or just a url, which MetaMonster fetches with a plain HTTP GET request without running JavaScript (a page that builds its content in the browser comes back thin; send its html instead). URL fetches are limited per organization per day (quick_check_url_limit, resets at midnight UTC); a fetch that is refused or fails answers url_blocked, url_fetch_failed, url_not_html or url_too_large. Optional: h1 (Markdown only: the H1 the layout renders when the Markdown has no # heading; without one, such a body has no H1), secondary_keywords, page_type, url (with content: gives it its domain and path). Content and fetched pages are checked in memory with the default factor settings: nothing is stored or charged. The result names what was checked (page 12, the Markdown or page you sent, or the fetched page's final URL). What it cannot answer is listed as not checked with the reason (keyword checks without primary_keyword, site-wide checks, checks that need the whole page's crawl data, fields not sent); when keyword checks were skipped, the result tells Claude to ask the user for the target keyword and run it again. The AI-judged checks are listed as not run, so a factor can pass here and still fail in analyze_page. Also takes include_passing. GET /pages/{pageId}/checks/preview, POST /checks/quick
get_page_report Returns the page's latest analysis without running one (factors and fixes), with its fields, keywords and outline. Includes the page's version_state (live, live_draft, draft, published or not_live) at the top level of the result. Accepts page_id or url. GET /pages/lookup (if url) → GET /pages/{pageId}/analysis, GET /pages/{pageId}/brief
get_analysis_history Lists a page's past analyses (factors passing). GET /pages/{pageId}/analyses
get_job Returns the status of an async job: job_ck_... (analysis), job_cr_... (crawl), job_ol_... (content brief), job_ac_... (fix draft), job_rw_... (body draft), job_wr_... (page writer draft). Use it when a tool returned status: "processing". GET /jobs/{jobId}
keyword_research Returns search volume, difficulty, CPC and intent for a seed keyword, plus related keyword ideas with the same metrics (DataForSEO). Pass site_id to use the site's search market. Requires an active subscription. Each live lookup counts against the organization's daily limit (500, shared with the app); repeating a keyword within 30 days is served from cache for free. GET /keywords/research
query_search_console Queries the site's Search Console data like the Performance report: clicks, impressions, CTR and average position, grouped by any of query, page, country, device, date and search appearance, with filters, a search type and an optional comparison with the previous period or the previous year (rows that vanished are kept). Rows with the page dimension carry their page_id. Pass page_id for one page. Returns a page of rows at a time (limit up to 200, next_offset) plus exact totals. Live from Google, for sites with Search Console connected. Requires an active subscription. POST /sites/{siteId}/search-analytics

Edit and verify

Tool What it does REST endpoint(s)
update_page Sets a page's keywords, priority flag, or purpose. Stores exactly what you send, with no AI involved. PATCH /pages/{pageId}
set_field_draft Stages a new title, meta description, h1, primary keyword, body, or schema (JSON-LD) for a page. An empty value discards the draft. Alt text is per image: use set_image_alt. PUT/DELETE /pages/{pageId}/drafts/{field}
update_content Replaces the page body with markdown, creating a content version. POST /pages/{pageId}/content
list_content_versions Lists a page's body versions (source, word count, date). GET /pages/{pageId}/content-versions
restore_content_version Restores an older body version by copying it forward as a new version. No version is deleted. POST /pages/{pageId}/content-versions/{versionId}/restore
resolve_fix Tells MetaMonster "I made this change": validates the current content or draft against the fix and marks it applied on a pass. Takes fix_id. POST /recommendations/{id}/resolve
dismiss_fix Tells MetaMonster "not doing this": marks a fix dismissed, with an optional rationale. Takes fix_id. POST /recommendations/{id}/dismiss
recheck_fix Re-verifies an already-applied fix after further edits (clears placeholders, confirms a skipped verdict). Takes fix_id. POST /recommendations/{id}/recheck
recrawl_page Re-fetches the live page after edits made directly on the site rather than through these tools. POST /pages/{pageId}/recrawl
analyze_page Runs an analysis and returns its factors and fixes. Accepts page_id or url, and resolves or creates the page (and, with create_site: true, the site) as needed. The first analysis of a page in a billing period spends one unit of the org's plan allowance; re-analyzing that page in the same period is free. The result carries a usage block: whether this run counted, pages used, limit, remaining and when the period resets. GET /pages/lookup, POST /sites, POST /sites/{siteId}/pages, POST /pages/{pageId}/analyze, GET /pages/{pageId}/analysis, GET /pages/{pageId}/brief
get_usage Pages used this billing period against the plan allowance and when it resets (a page counts once per period, whatever is generated for it), every page that counts with the actions that counted it; with page_id, whether that page already counts (so working on it again is free). GET /usage?include=pages
write_fixes Writes (or rewrites) the fixes for the page's latest analysis from its stored factor results, without re-running the analysis. Free. Returns at once; the writing takes about 20 seconds, then read them with get_page_report. Use it when an analysis reports fixes_status: "not_requested". POST /pages/{pageId}/checks/recommendations
create_page Adds a page for content that isn't published yet, like the app's "Add page". Nothing is crawled. Write it with update_content and set_field_draft, then analyze_page reviews the saved content. On a planned site, the page joins the plan with no URL until go_live_site. POST /sites/{siteId}/pages (crawl: false)
delete_page Deletes a page created by mistake, such as a mistyped URL. A soft delete: the page leaves every listing, and the live website is not touched. DELETE /pages/{pageId}

Plan a new site

For a site that isn't live yet, the same flow as the app's "Plan a site".

Tool What it does REST endpoint(s)
plan_site Creates a planned site from a brief about the business (no domain, no crawl) and proposes the pages it needs, each with a name, slug and purpose. When the brief names its pages, only those are created and the rest come back as suggested pages. Takes 10-40 seconds. suggest_pages: false skips the proposal: the brief is optional and the site starts with the homepage only. POST /sites/plan, POST /sites/{siteId}/plan/generate, GET /sites/{siteId}/plan
get_site_plan Lists the planned pages with their paths, purposes and primary keywords, whether keyword assignment is still running, and any suggested pages (not created until added). GET /sites/{siteId}/plan
edit_site_plan Removes, edits and adds planned pages in one call, adds suggested pages (pass the suggestion's name, slug and purpose to add), or regenerates the whole set from the brief (optionally a revised one). DELETE/PATCH /sites/{siteId}/plan/pages/{pageId}, POST /sites/{siteId}/plan/pages, POST /sites/{siteId}/plan/generate
assign_planned_keywords Assigns a primary keyword to every planned page that has none, then waits up to ~45 seconds for it to finish. Free. POST /sites/{siteId}/plan/keywords, GET /sites/{siteId}/plan
go_live_site Sets the site's real domain and starts a crawl. Crawled URLs are matched to the planned pages by path, so their keywords, briefs and content carry over. POST /sites/{siteId}/go-live

Generate

Tool What it does REST endpoint(s)
get_content_brief Reads the page's latest content brief: its angle and its proposed sections with their status. GET /pages/{pageId}/outline
generate_content_brief Step 1 of a brief: generates the angle (thesis, SERP pattern, differentiators, questions for you) from the page's primary keyword and SERP, then waits for it (about 45 seconds at most). instructions steer it; on a rerun they revise the current brief. Pass outline: true to write the angle and the sections in one run. Counts the page against the plan allowance once per billing period: a page already analyzed or briefed this period is free. POST /pages/{pageId}/outline → GET /jobs/{jobId}
generate_content_outline Step 2 of a brief: builds the section outline from the page's latest brief, including your edits to its angle, then waits for it (about 45 seconds; on a timeout it returns status: "processing" and a job_id). Takes page_id or url, instructions and wait. Not charged. brief_not_ready if there is no finished brief. POST /pages/{pageId}/outline/build → GET /jobs/{jobId}
update_content_brief Edits the brief's angle by hand (brief: any of thesis, serp_pattern, differentiators, pov_prompts), or accepts, rejects, revises or reorders its sections. Accepted headings go into the body as a new content version; write the sections next with update_content, passing the returned content_version_id as base_version_id. PATCH /pages/{pageId}/outline/brief (angle), PATCH /pages/{pageId}/outline/sections (sections)
draft_fix Drafts a fix with AI: a fix draft for one fix (fix_id), or for a title, meta description, h1 or schema with your instructions. Returns the before/after and an action_id. Nothing is applied yet. Capped at 50 generations per page per analysis, revisions included (generation_cap_reached), and 3 revisions per draft (revision_cap_reached). POST /recommendations/{recId}/fix or POST /pages/{pageId}/actions → GET /jobs/{jobId} → GET /actions/{actionId}
review_fix_draft Accepts, rejects or revises a fix draft (by action_id). Accepting saves a metadata fix as the field's draft, or a body fix as a new content version. POST /actions/{actionId}/accept, /reject, /revise
generate_content_draft Rewrites the body with several body fixes at once (pass fix_ids; the app's Review Mode). The result is saved as the latest content version straight away, with no review step. Counts the page once this billing period (free if it already counts). POST /pages/{pageId}/content-rewrites → GET /jobs/{jobId} → GET /pages/{pageId}/content-versions/{versionId}
generate_field_draft Generates a title, meta description or h1 draft, with optional instructions. Counts the page once this billing period (free if it already counts). POST /pages/{pageId}/drafts/{field}/generate
get_page_images Lists the page's images with their alt text state (missing, decorative, draft or crawled). GET /pages/{pageId}/images
set_image_alt Sets one image's alt text, or generates it with generate: true. PUT /pages/{pageId}/images/alt, POST /pages/{pageId}/images/generate-alt
generate_missing_alt Generates alt text for every image still missing it, within a ~45-second budget per call. Call again to continue. Counts the page once this billing period (free if it already counts). GET /pages/{pageId}/images, POST /pages/{pageId}/images/generate-alt
get_page_drafts Read-only. Returns everything the page has waiting to go live, for a coding agent to write into the site's own files: title, meta description, H1 and schema drafts (each with its live value), the body's unpublished edits (full Markdown plus the changed blocks before → after) and image alt drafts. When the site's platform is known (Astro, Hugo, WordPress…), it names it with a hint on where that platform keeps the SEO fields. The app's Work on this with your agent prompt has the agent call it when you ask it to publish from the site's repo. GET /pages/{pageId}/pending-drafts
mark_page_published Call after pushing the commit that applied get_page_drafts's drafts. Marks the drafts published and starts watching the live page (every minute for 15 minutes, then hourly for a week); optional commit_sha and preview_url. With none of fields, body and image_ids, every pending draft is marked; once any of them is passed, only what they name is (a missing fields or image_ids means none, and the body counts only with body: true). Once the live page shows the changes, MetaMonster recrawls and re-analyses it. When nothing credited can be checked on the live page, the publish is logged but not watched. POST /pages/{pageId}/published
check_page_live_again Restarts the live checks on a page whose last publish isn't fully on the live page and whose checks have stopped, on the same schedule as a new publish (every minute for 15 minutes, then hourly for a week). Once the live page shows the changes, MetaMonster recrawls and re-analyses it. Fails when the last publish is already live or still being checked. POST /pages/{pageId}/published/check

Business facts and the Context Library

Tool What it does REST endpoint(s)
get_site_facts Reads the site's verified business facts (company details, contact info, Google listing, testimonials, stats, awards, clients, people) with their citations. Returns 25 facts at a time (up to 50 with limit); next_offset says where the next page starts. Search the full library with search; status: "dismissed" lists removed facts and what removed each. Each fact's merged_from lists the wordings consolidation merged into it. GET /sites/{siteId}/facts
add_site_facts Records facts the user stated in conversation so later generations use them. Deduped by content; never overwrites a fact a person edited. POST /sites/{siteId}/facts
update_site_fact Edits a fact's value, confirms a stale fact is still true, deletes a fact (a fact read from the site is dismissed instead), restores a removed one (undoing the dismissal that removed it, when there was one), or splits a merged wording (split_out with merged_from_id) back out into its own fact. PATCH/DELETE /sites/{siteId}/facts/{factId}, POST /sites/{siteId}/facts/{factId}/restore, POST /sites/{siteId}/facts/{factId}/split
get_site_guidance Reads what every generation is told: brand voice, about the business, audiences per offer, preferences and voice notes, and fact-scan status. GET /sites/{siteId}/guidance
update_site_guidance Edits brand voice and business context, and adds, edits or archives preferences and voice notes. PATCH /sites/{siteId}, POST /sites/{siteId}/guidance, PATCH /sites/{siteId}/guidance/{guidanceId}
manage_audiences Adds, edits or removes who an offer is for, or regenerates the generated rows. POST/PATCH/DELETE /sites/{siteId}/audiences..., POST /sites/{siteId}/audiences/regenerate
scan_site Rescans the site for facts (optionally with new skip patterns or instructions), or refreshes only the Google listing. Runs in the background. POST /sites/{siteId}/facts/extract, GET/PUT /sites/{siteId}/facts/settings, POST /sites/{siteId}/facts/google-listing
list_dismissal_fact_changes Lists the fact changes made from the reasons people gave when dismissing fixes. GET /sites/{siteId}/dismissal-routing/facts
undo_dismissal_fact_change Reverses the Context Library change a dismissal reason made. Takes fix_id. POST /recommendations/{recId}/dismissal-routing/undo
add_context_document Adds a call transcript to the Context Library: stored whole, searchable, and mined in the background for testimonials, stats and customer-voice facts. The same text is never added twice: re-sending text already on the site (under any or no external_id) returns that document unchanged; re-sending the same external_id with different text replaces the text (a first send whose text matched an existing document doesn't store its external_id), and re-sending a failed document retries it. New text counts against the organization's monthly word allowance (context_documents_cap_reached when used up). Processing time depends on length: a short call takes about a minute, a long transcript several minutes. If processing could not start, the document comes back failed; retry it with update_context_document. Requires ends_with (the transcript's last few words): a transcript that arrives cut off is rejected rather than stored. POST /sites/{siteId}/documents
list_context_documents Lists a site's context documents, optionally filtered by category, title search or date range. GET /sites/{siteId}/documents
get_context_document One document: summary, participants, status, cited fact ids, and optionally the transcript, one page at a time (text_offset, text_limit). GET /sites/{siteId}/documents/{documentId}
update_context_document Edits a document's title, category, summary, topics, participants or date, or toggles quotes_usable; retry: true restarts a document whose processing failed (no effect otherwise). Changing quotes_usable, participants or the date re-extracts; changing the title, category or date re-indexes. PATCH /sites/{siteId}/documents/{documentId}
delete_context_document Deletes a document with its stored text and search passages. Facts another source backs lose only this citation; facts a person confirmed, edited or entered are kept, citing the deleted call. orphans decides the facts only this document supports: delete (default) or keep (kept as confirmed, citing the deleted call). The tool tells the agent to ask the user which first. Returns facts_deleted and facts_kept. DELETE /sites/{siteId}/documents/{documentId}
search_context Searches everything said across the site's documents by meaning and exact words. GET /sites/{siteId}/documents/search

Page writer (internal preview)

Only for organizations with the page writer enabled.

Tool What it does REST endpoint(s)
generate_page_draft Writes the whole page from its accepted outline and brief: plans it, writes each section, edits the draft twice against the site's facts and rules, and writes the title and meta description. Needs an accepted outline (accept_outline otherwise). Nothing is published: the body becomes the latest content version and the title and meta description become field drafts; sections the user wrote in are kept. A run takes a few minutes, so it waits up to ~45 seconds and then returns status: "processing" with a job_id and draft_run_id. Poll with get_job, or call again with draft_run_id. The result lists the questions it left for the owner ([[...]]), any blocking checks still failing, and the fields it skipped because they already had an open draft. Counts the page once this billing period (free if it already counts). POST /pages/{pageId}/writer-runs → GET /jobs/{jobId} → GET /pages/{pageId}/content-versions/{versionId}

Items (internal preview)

Only for organizations with items enabled. Items are the work in progress on a site: pages being created or updated. An item exists only once work starts; the Playbook is the queue, so to add work without starting it, add an idea with add_content_idea.

Tool What it does REST endpoint(s)
create_item Starts work from an idea, an analysis or by hand and sends it to the monsters. A page that already has work in progress leaves it waiting (started: false, reason: page_busy); start it with start_item once that work is done. POST /sites/{siteId}/items
list_items The site's items, each as title, create or update, and its next step. Filter with status: active, queued or all. Lines show the change label. GET /sites/{siteId}/items
get_item One item (with its change label) with what is asked of the user, every step and its state, and its history. GET /sites/{siteId}/items/{itemId}

Email reports (internal preview)

Only for organizations with email reports enabled. The monthly email report sends a site's performance summary and what to do next to the addresses listed (for an agency, usually its client).

Tool What it does REST endpoint(s)
get_email_report_settings Whether the site's monthly email report is on, and who it goes to. GET /sites/{siteId}/email-report-settings
update_email_report_settings Turns the report on or off and/or sets its recipients. The list given replaces the current one (up to 10); an invalid address is rejected. The tool asks the agent to confirm with the user first, since the emails go to the user's clients. PUT /sites/{siteId}/email-report-settings

Drift (internal preview)

Only for keys whose user has Drift enabled. Drift finds places where a site contradicts itself or its business facts.

Tool What it does REST endpoint(s)
get_drift_findings The latest Drift scan (status, stage, when) and the finding groups in one view (needs review or dismissed), each with its group key, severity, confidence, type, title and page. GET /sites/{siteId}/drift
get_drift_finding One finding group in full: the passage, what each finding conflicts with (a fact, another page, or every version across the site), the problem, and the proposed rewrite. GET /sites/{siteId}/drift/groups/{groupKey}
run_drift_scan Queues a Drift scan. Runs in the background with no job to poll; re-read get_drift_findings later. POST /sites/{siteId}/drift/scans
accept_drift_finding Accepts a finding group as ideas: one Update idea per page it affects (From Drift), and a strategy holding them when there are two or more pages. The findings become confirmed; nothing is queued. Accepting again adds nothing. Also needs content ideas. POST /sites/{siteId}/drift/groups/{groupKey}/accept

Content ideas

Every account gets these tools.

Tool What it does REST endpoint(s)
get_content_playbook Reads the site's content playbook: the quick wins to make first (the moves field), the strategies with their ideas in priority order (the plays field), the keywords it relies on, and its notes. It is how to read the strategies (the app's Strategies view); one strategy's ideas come from list_content_ideas with its play_id. Says whether it was written from scratch or updated (with what changed), and whether it was written before launch and should be updated now. GET /sites/{siteId}/ideas/playbook
list_content_ideas Lists ideas as a table, filtered by status, strategy, topic, funnel stage, change or a search. Each row says where the idea came from (Suggested, From your plan, From Drift) and marks quick wins. GET /sites/{siteId}/ideas
get_content_idea One idea in full: why, what to watch out for, keywords with their metrics, and the page it changes or the URL proposed for a new one. GET /sites/{siteId}/ideas/{ideaId}
get_authority_map The Authority map as data: the core, topics by distance from it, gaps, drifting pages and pages across two topics. GET /sites/{siteId}/ideas/topics
generate_content_ideas Starts a run (about 10 minutes) and returns at once. A site with a playbook is updated by default; pass mode: "rebuild" to start over with a new playbook. Both modes use the day's run, so the choice cannot be redone until the cooldown passes. Costs money and is capped: once a day per site and a monthly limit per organization. POST /sites/{siteId}/ideas/refresh
get_content_ideas_status The latest run's status, whether it updates the playbook or rebuilds it (mode), its stage and progress, and when the next run may start. GET /sites/{siteId}/ideas/run
accept_content_idea An explicit request to start a Not started idea. Optimize adds its keywords to the page and starts an analysis (spends allowance); create links the page made with create_page. For a status-only move that starts nothing, use set_content_idea_status. POST /sites/{siteId}/ideas/{ideaId}/accept
set_content_idea_status Sets where an idea stands: not_started, in_progress or done, in either direction. in_progress changes the status only and starts nothing paid (an optimize idea gets no keywords added and no analysis; use accept_content_idea or analyze_page for that; a new-page idea gets its planned page, from page_id, the page it already has, or one made from the idea, and no content brief is generated, use generate_content_brief). An idea also moves to In progress by itself when an analysis finishes or a content brief is generated for its page. done is recorded as marked over MCP. A dismissed idea can't change. POST /sites/{siteId}/ideas/{ideaId}/progress
dismiss_content_idea Dismisses an idea with a reason; later runs won't suggest its keywords again. POST /sites/{siteId}/ideas/{ideaId}/dismiss
restore_content_idea Brings a dismissed idea back to Not started (the app's Restore); it returns to the calendar at the end of the queue. POST /sites/{siteId}/ideas/{ideaId}/restore
add_content_idea Adds an idea to the Playbook by hand (the app's Add to Playbook): a new page, or an update to one of the site's pages. Not started; it gets a date on the content calendar. POST /sites/{siteId}/ideas
reopen_content_idea Moves an In progress idea back to Not started (the app's Move back to Not started): its earlier page comes back and its added keywords are cleared. POST /sites/{siteId}/ideas/{ideaId}/reopen
create_map_topic Adds an Authority map topic by hand: name, optional description, distance from the core. Runs keep it. POST /sites/{siteId}/ideas/topics
update_map_topic Renames a map topic or changes its description or distance; runs keep it as edited. Destructive: the old values are replaced. PATCH /sites/{siteId}/ideas/topics/{topicId}
delete_map_topic Deletes a map topic: runs never recreate it, its pins go back to automatic, and its pages and ideas are sorted onto the remaining topics (any not placed in time wait for the next run). Destructive. DELETE /sites/{siteId}/ideas/topics/{topicId}
set_map_page_placement Places a page by hand: pin to a topic, ignore (off the map and out of runs), unignore, or reset to automatic. PUT /sites/{siteId}/ideas/topics/pages/{pageId}
get_content_calendar The content calendar for a date range: the repeat rule and start, and each idea's date, status, whether it is overdue and whether the owner set the date by hand. Done ideas show on the day they were done. Days are UTC; an idea with no date yet shows - (it is placed when the calendar is opened in the app or after the next run). GET /sites/{siteId}/ideas/calendar
update_content_calendar_settings Changes the cadence (an RRULE: weekly on weekdays, or monthly on days of the month or weekday positions) or the start, then lays out again the future ideas whose dates were not set by hand. PATCH /sites/{siteId}/ideas/calendar/settings
schedule_content_idea Sets one idea's date or snoozes it by N weeks (counted from its date, or from today when the date has passed); the date then counts as set by hand. POST /sites/{siteId}/ideas/calendar/schedule
shift_content_calendar Moves every not-done idea after a date by N weeks (either way). POST /sites/{siteId}/ideas/calendar/shift
reorder_content_ideas Sets the queue order; future dates not set by hand follow it. POST /sites/{siteId}/ideas/calendar/reorder
reschedule_content_calendar Reschedule from today: lays every not-done idea not set by hand, future or overdue, back onto the cadence from today, closing gaps. POST /sites/{siteId}/ideas/calendar/reschedule
get_content_calendar_feed The calendar feed link (ICS) to subscribe to from Google Calendar and others, made on first use. POST /sites/{siteId}/ideas/calendar/ics-link
reset_content_calendar_feed Replaces the feed link; the old one stops working at once (destructive). Only when the user asks, such as after the link was shared by mistake. POST /sites/{siteId}/ideas/calendar/ics-link (reset: true)
get_playbook_steering The site's Playbook steering (the Steering section in the Playbook's Settings): goal, kinds of ideas (less, normal or more), focus, avoid, pages the user already wants, and whether the monthly refresh is on. Every idea run follows it. GET /sites/{siteId}/playbook/steering
update_playbook_steering Changes the steering; only the fields passed change. Saving runs nothing; monthly_refresh turns the monthly refresh on or off. PUT /sites/{siteId}/playbook/steering
get_playbook_share_link The site's active playbook share link (a read-only public page of the latest playbook), or none. GET /sites/{siteId}/ideas/playbook-share
create_playbook_share_link Returns the active share link or makes one (the app's Share). POST /sites/{siteId}/ideas/playbook-share
revoke_playbook_share_link Stops sharing: the link stops working (destructive; sharing again makes a new link). DELETE /sites/{siteId}/ideas/playbook-share

Factors and fixes

There is one analysis. Every factor passes or fails, with the measurement and the threshold behind it, grouped by area. Each failing factor comes with fixes: the edits that would make it pass.

  • analyze_page and get_page_report return a factor table: every factor with its verdict, measurement and threshold, plus the fixes once written. Passing factors are summarized; pass include_passing: true to list them. analyze_page re-judges content only when it changed (unchanged content spends no allowance), and force re-runs it anyway.
  • get_page_report returns the page's latest analysis, and a no analysis error when the page has none.
  • find_pages takes min_factors_passing_pct (0-100) and has_fixes. min_score/max_score filter the opportunity (demand) score.
  • get_opportunities rows show factors passing (for example 36/41 factors passing, or not analyzed) and a fix_count. A row's score is the demand rank, not an analysis score.
  • get_factors lists every factor that is checked.
  • An analysis whose fixes_status is not_requested has findings but no fixes yet: call write_fixes.
  • Results use fix vocabulary throughout: fixes, fixes_status, fix_count, fix_id, and error codes such as no_actionable_fixes and fixes_in_progress. The REST API underneath still says recommendations.

Analyze a URL

analyze_page and get_page_report both accept { url } instead of { page_id }, so a client can hand over a bare URL and get a report back without knowing whether MetaMonster has seen the page before. analyze_page resolves it through three cases:

  1. Known page. The URL already resolves to a page. If it has a crawled snapshot, saved body content, or staged field drafts, it's analyzed directly (or its existing report is returned), so a page made with create_page and written with update_content is analyzed without a crawl. A discovered page with none of those is crawled first. A planned or hand-added page with no content returns page_not_live / no_content instead of crawling a URL that may not exist.
  2. Known site, unknown page. The URL's host matches an existing site but the path doesn't. The page is created and crawled first, then analyzed.
  3. Unknown site. Neither the host nor the path is known. The tool returns site_not_found with a next_step hint instead of guessing. Confirm with the user, then call analyze_page again with create_site: true to add the site (this queues a background discovery crawl of the whole site). Only the one page you asked about is analyzed; site creation never spends extra allowance on its own.

A mistyped URL on a known site creates a page, so confirm uncertain paths with the user before calling analyze_page with a URL. If one slips through, remove it with delete_page.

Only analyze_page will create a site or page on your behalf, and only with explicit opt-in (create_site: true). get_page_report only reads what already exists (returning page_not_found/site_not_found otherwise), and recrawl_page only accepts page_id; it doesn't resolve a URL.

Create new content

To take a content idea from nothing to a reviewed draft without publishing anything:

  1. create_page with a working title (the path defaults to its slug, as in the app) and the idea as purpose.
  2. keyword_research on a seed keyword, then update_page to save the primary and secondary keywords.
  3. generate_content_brief writes the angle. Review it and edit it with update_content_brief (brief), then generate_content_outline builds the sections from it, and update_content_brief accepts sections (their headings go into the body).
  4. Write the body with update_content (pass the brief's content_version_id as base_version_id) and the title, meta description and H1 with set_field_draft. With the page writer, generate_page_draft writes the body, title and meta description for you instead.
  5. quick_check_page (free), then analyze_page to review the saved content. No crawl is needed.

Plan a new site

To plan a whole site before it exists:

  1. plan_site with the user's description of the business. Show them the proposed pages.
  2. edit_site_plan to remove, rename, re-slug or add pages, or to regenerate the set from a revised brief.
  3. assign_planned_keywords once the user confirms the set. Check on it with get_site_plan if it is still running.
  4. Build each page as in Create new content (steps 3-5): briefs, body and fields work on planned pages.
  5. When the site is published, go_live_site with its domain. After the crawl, the pages are analyzed like any live page.

Plan content from ideas (preview)

For accounts with the content ideas tools:

  1. get_content_playbook to see what to publish next, and get_authority_map for topical gaps and drifting pages.
  2. get_content_idea for the one the user picks.
  3. For a new page: create_page with the idea's proposed path and keywords, then accept_content_idea with action: "create" and the new page_id, and build it as in Create new content. For a change to an existing page: accept_content_idea with action: "optimize".
  4. Only when the user wants the plan refreshed: generate_content_ideas (it updates the current playbook; mode: "rebuild" starts over; it costs money and is capped), then get_content_ideas_status every few minutes until it has succeeded.

Errors

Tool errors carry the same code/message/details as the REST error envelope: payment_required, analysis_in_progress, crawl_in_progress, site_not_found, page_not_found, already_resolved, and so on. A few additions and behaviors are specific to the MCP layer:

  • result_too_large means the result would be more than Claude can read in one go (about 120,000 characters). Ask for less: a smaller limit, the next page with offset, or a narrower search or filter.
  • payment_required without a plan means the organization has no active subscription. Every tool but quick_check_page and list_sites returns it in that case (list_sites answers, with plan_required: true and a one-line note), with a plain notice in place of the v1 message: what needs a plan for that tool's task, the cheapest plan that includes it with its price and limits (Drift tools: the cheapest plan with Drift), a /pricing?plan=… checkout link, and that quick_check_page is free (offer it on the page the call named, else ask which page). The prices come from the v1 refusal's details.plans. The same facts are in details.paywall (reason: no_plan, task, plan, checkout_url, free_check). Tell the user a plan is needed and share the link, don't retry: calling another paid tool will not help. When the organization has a plan, the same code with details.reason limit_reached (pages or sites used up this period) or not_on_plan (a feature the plan lacks) carries an upgrade link instead.
  • invalid_arguments means the tool call itself was malformed (bad zod input). Fix the arguments and retry.
  • generation_cap_reached means the page has used its 50 AI generations for the current analysis (draft_fix and revisions). Re-run the analysis to get a fresh set.
  • revision_cap_reached means a draft has been revised 3 times. Accept it and edit the text directly (update_content or set_field_draft), or reject it and draft the fix again.
  • generate_content_brief, generate_content_outline, draft_fix and generate_content_draft wait up to ~45 seconds. If the generation is still running, they return status: "processing" with a job_id. Poll it with get_job, then read the result: get_content_brief for a brief or its outline, or call draft_fix / generate_content_draft again with the returned action_id / rewrite_id (this resumes the wait and doesn't start a new generation).
  • page_not_live / no_content mean analyze_page was asked to analyze a planned (no live URL yet) or hand-added page that has no crawled or saved content. Write the body with update_content (or stage fields with set_field_draft) and analyze again, or, if the page is live, call recrawl_page first.
  • analyze_page's crawl and analysis waits share a single ~45-second server-side budget for the whole call (not ~90s per step), so the second wait gets whatever's left after the first. If the budget runs out while a step is still running, the tool returns status: "processing" with a job_id instead of an error. Call get_job to poll it, honoring its retry_after_seconds.

Rate limits are the calling key's normal REST limits (see Conventions). There's no separate MCP-layer limit; each tool call spends the budget of the v1 request(s) it makes underneath.

Local development

Run against a local dev server at http://localhost:3000/mcp with the same bearer auth. The MCP Inspector is the fastest way to poke at it directly:

npx @modelcontextprotocol/inspector

In the Inspector UI, choose transport Streamable HTTP, set the URL to http://localhost:3000/mcp, and add an Authorization: Bearer mm_YOUR_KEY header.