SEO Agency Suite
Complete reference for the 11 SEO Agency Suite tools in Royal MCP Pro. Portfolio-scale SEO audit + bulk meta writers for all five supported SEO plugins (Yoast, Rank Math, SEOPress, AIOSEO, SEObolt) + widget bulk ops + Redirection plugin bulk import/export/rule-set apply. All bulk writers use the safer 2-step commit envelope with drift detection and a longer 168-hour undo TTL.
The two-step commit envelope
Every bulk write in this suite uses a two-step commit pattern — different from the direct-write pattern the Divi / Elementor / WC bulk tools use. This is a deliberate safety layer: SEO meta and widget content live in surfaces users often edit outside your MCP session, so racing an editor is a real risk. The two-step envelope catches drift between preview and commit.
Step 1 — Preview (no commit_token)
Call the tool with your update payload but no commit_token. The response is a dry-run preview: what would change per row, plus a fresh commit_token string. Nothing is written.
Step 2 — Commit (echo the commit_token back)
Call the tool a second time with the same update payload PLUS the commit_token from step 1. The token has a 5-minute TTL and is one-shot — consumed on successful commit, or on any conflict / drift. Successful commit issues a 168-hour undo token.
Drift detection
Between step 1 and step 2, the tool re-reads the target rows. If any target's state changed — someone edited Yoast meta in wp-admin, a scheduled cron rewrote a widget, another MCP session touched the row — step 2 rejects with a conflict error + drifted_post_ids array naming the rows that moved. Nothing is written. You call step 1 again with a fresh preview and try again.
SEO meta changes often surface in Search Console rankings on a 3–7 day lag. If a bulk meta rewrite tanks rankings, you may not know until day 5 or 6. The 168-hour window gives you time to notice and roll back before the tokens age out.
SEO tools (1 audit + 5 bulk writers)
wp_audit_seo_bulk ⭐
Bulk SEO audit across a post type. Returns per-page findings (title/description length + issue, noindex, H1 count, word count, image count, images missing alt, featured image, issues list) plus an optional aggregated rollup (issues by type, worst offenders). Auto-detects Yoast SEO, Rank Math, SEOPress, AIOSEO, or SEObolt; falls back to WordPress-native fields (post_title, post_excerpt) when none is active. Read-only.
Arguments
| Name | Type | Description |
|---|---|---|
post_type | string | Post type to audit (must be a registered CPT slug). Default: post. |
paginate | object | {page, per_page}. Defaults: page 1, per_page 100 (max 500). |
rollup | boolean | Include the aggregated rollup summary alongside per-page results. Default true. |
snapshot | boolean | When true and SiteVault is installed, kick off a pre-audit backup. Default false. Snapshot failure never aborts the audit. |
Example
Run wp_audit_seo_bulk on my page post type with rollup=true. Then tell me the top 3 issues by count and the 5 worst-offender post IDs.No undo (read-only). Requires manage_options.
All five bulk-meta writers (yoast_bulk_update_meta, rankmath_bulk_update_meta, seopress_bulk_update_meta, aioseo_bulk_update_meta, seobolt_bulk_update_meta) accept the same input shape:
| Name | Type | Description |
|---|---|---|
updates required | array | Up to 100 per-post update rows. Each row must include post_id and at least one field. |
dry_run | boolean | Force a step-1 preview even if you already have a commit_token. Default false. |
commit_token | string | Required for the actual write (step 2). Get it from the step-1 dry-run response. TTL: 5 minutes. One-shot. |
Per-update-row 3-state field model — OMIT the key to leave the field UNCHANGED; pass "" or null to CLEAR (delete meta / revert to plugin default); pass a value to SET.
| Field | Type | Description |
|---|---|---|
post_id required | integer | Target post ID. |
title | string | SEO title (browser tab / SERP display). |
description | string | Meta description (SERP snippet). |
focus_keyword | string | Primary focus keyword for SEO scoring. |
noindex | boolean | true = force noindex. false = force explicit index (overrides site default) — EXCEPT SEOPress, see per-tool notes. null = revert to site default on all plugins. |
canonical | string | Canonical URL (or clear). |
yoast_bulk_update_meta
Bulk-update Yoast SEO meta across up to 100 posts. Routes to Yoast's meta keys. Two-step commit + drift detection + 168h undo.
Requires Yoast SEO to be the active SEO plugin. Rank Math / SEOPress / AIOSEO / SEObolt have separate bulk-write tools. See shared arguments above.
Undo: 168h token — restores each affected post's Yoast meta exactly.
rankmath_bulk_update_meta
Bulk-update Rank Math SEO meta across up to 100 posts. Routes to Rank Math's meta keys (rank_math_title, rank_math_description, rank_math_focus_keyword, rank_math_robots array, rank_math_canonical_url).
Noindex handling: noindex toggles preserve other robots tokens (nofollow, noimageindex) already on the post. Two-step commit + drift detection + 168h undo. Requires Rank Math active.
Undo: 168h token — restores each affected post's Rank Math meta exactly.
seopress_bulk_update_meta
Bulk-update SEOPress meta across up to 100 posts. Routes to SEOPress's meta keys (_seopress_titles_title, _seopress_titles_desc, _seopress_analysis_target_kw, _seopress_robots_index, _seopress_robots_canonical).
SEOPress has no explicit-index concept — noindex: false and noindex: null both delete the meta row (revert to site default). If you want to force "always index" on Yoast/RankMath/AIOSEO you'd use noindex: false; on SEOPress there's no equivalent action.
Two-step commit + drift detection + 168h undo. Requires SEOPress active.
Undo: 168h token — restores each affected post's SEOPress meta exactly.
aioseo_bulk_update_meta
Bulk-update AIOSEO (All in One SEO) meta across up to 100 posts. Dual-writes to legacy post_meta AND to the wp_aioseo_posts custom table on modern versions so both surfaces stay coherent.
Posts that AIOSEO has never touched (no wp_aioseo_posts row) surface in the response's warnings array. Open the post once in the AIOSEO editor to seed a row, then re-run the bulk update.
Two-step commit + drift detection + 168h undo. Requires AIOSEO active.
Undo: 168h token — restores each affected post's AIOSEO meta exactly.
seobolt_bulk_update_meta
Bulk-update SEObolt meta across up to 100 posts. Routes to SEObolt's _seobolt_meta_* post-meta keys. Two-step commit + drift detection + 168h undo. Requires SEObolt active.
SEObolt is Royal Plugins' own SEO plugin — treated exactly the same way as Yoast, Rank Math, SEOPress, and AIOSEO by the auto-detect layer. If SEObolt is the active SEO plugin on the site, this writer is what runs when you call bulk-meta updates.
Undo: 168h token — restores each affected post's SEObolt meta exactly.
Widget bulk tools (2)
Both widget tools require edit_theme_options capability plus the Royal MCP settings toggle "Allow AI to modify theme appearance" — a deliberate second gate because widget changes affect site-wide chrome and can't be undone visually as easily as post content.
wp_bulk_update_widgets
Bulk-update widget instance settings across up to 100 widgets. Settings are partial-merged: keys you pass overwrite, keys you omit stay unchanged.
Arguments
| Name | Type | Description |
|---|---|---|
updates required | array | Up to 100 {widget_id, settings} rows. widget_id examples: "text-2", "custom_html-5", "block-15". |
dry_run | boolean | Force step-1 preview even with a commit_token present. |
commit_token | string | Required for the actual write (step 2). TTL 5 min. One-shot. |
Widgets not found are surfaced in the response's skipped array, not raised as errors.
Undo: 168h token — restores prior widget instances exactly.
wp_bulk_replace_widget_content
Literal find/replace across every stored instance of a widget type (e.g. update the copyright year on every text widget site-wide, or fix a URL across every custom_html widget). Walks all STRING values in each instance's settings — non-string values (numeric IDs, booleans) are left untouched.
Literal match only. This is deliberate for safety — regex on user-typed widget content is a foot-gun class of bug that has no good fit inside an AI-driven workflow. If you need regex, do the find/replace client-side and use wp_bulk_update_widgets to write the transformed settings back.
Arguments
| Name | Type | Description |
|---|---|---|
widget_type required | string | Widget id_base (the piece before the -N), e.g. text, custom_html, block, nav_menu. |
find required | string | Literal string to find. |
replace required | string | Replacement (may be empty to remove all occurrences). |
case_insensitive | boolean | Default false. When true, uses str_ireplace. |
dry_run | boolean | Force step-1 preview. |
commit_token | string | Required for step 2. TTL 5 min. |
Undo: 168h token — restores prior widget instances exactly.
Redirection plugin bulk tools (3)
All three tools require the Redirection plugin by John Godley active. They wrap the plugin's storage layer with two-step commit + drift detection.
redirection_bulk_import
Bulk-import up to 100 redirects from a CSV. Header row required with at least source and destination columns; optional group, type, match_type.
Arguments
| Name | Type | Description |
|---|---|---|
csv_content required | string | CSV body. First line = header; header must include source + destination. Columns: source, destination, group, type, match_type. |
overwrite | boolean | When true, existing redirects with the same source are updated in-place. Default false (existing sources skipped and surfaced in the skipped list). |
dry_run | boolean | Force step-1 preview. |
commit_token | string | Required for step 2. TTL 5 min. |
Undo: 168h token — deletes only the redirects this batch CREATED and restores the ones it UPDATED. Never touches pre-existing redirects that weren't part of the batch.
redirection_bulk_export
Export existing Redirection entries as CSV. Read-only.
Arguments
| Name | Type | Description |
|---|---|---|
group_id | integer | Filter to redirects in this group only. Use the Free-tier redirection_list_groups to discover IDs. |
limit | integer | Default 500, min 1, max 5000. |
No undo (read-only, no-op token returned for API consistency).
redirection_apply_rule_set
Apply a JSON-defined rule set (up to 100 rules) — same shape + semantics as redirection_bulk_import but takes a rules array directly instead of CSV. Useful for saved templates like "301 old blog URLs to new structure."
Arguments
| Name | Type | Description |
|---|---|---|
rules required | array | Up to 100 rule objects. Each: {source, destination, group?, type?, match_type?}. type is HTTP status (301 / 302 / 307; default 301). |
overwrite | boolean | When true, existing redirects with the same source are updated in-place. |
dry_run | boolean | Force step-1 preview. |
commit_token | string | Required for step 2. TTL 5 min. |
Undo: 168h token — same shape as redirection_bulk_import (deletes newly-created, restores updated, ignores pre-existing).
Still Stuck? Two-Step Support Path
If a SEO Suite tool isn't behaving the way you expected, work through these two steps in order.
Step 1: Start with the Royal MCP Troubleshooting Guide
Royal MCP Troubleshooting — Start Here covers MCP-layer issues.
For Pro-specific patterns:
- Undo token errors — expired, consumed, or handler missing
- Pro tool returned upgrade prompt with valid license
Step 2: Email priority support
If you've worked through Start Here and the relevant Pro-specific doc and the issue still isn't resolved, email priority support from your purchase email address at support@royalplugins.com. Priority email support is included with your license — typical response within 24 hours. Never include your license key in email; we look it up from your purchase address.
- Your hosting provider (SiteGround, Cloudways, Hostinger, Kinsta, WP Engine, Liquid Web, self-hosted VPS, etc.)
- Royal MCP Pro version from WP Admin → Plugins
- Which SEO plugin is active and its version (Yoast SEO / Rank Math / SEOPress / AIOSEO / SEObolt / none) — if using a bulk SEO writer
- Redirection plugin version if using a Redirection tool
- Active caching plugins (LiteSpeed Cache, WP Rocket, W3 Total Cache, SpeedyCache, Hummingbird, none)
- Which MCP client — claude.ai web custom connector, Claude Desktop with
mcp-remote, ChatGPT MCP, Cursor, or another MCP-compatible client - The exact tool name and args you called (redact any customer PII from the
updatesarray if present) - Which step failed — step 1 preview, or step 2 commit? If step 2 rejected with
conflict, include thedrifted_post_idsarray - Screenshot of the most recent
oauth:row in Activity Log AND the most recent Pro tool row in Audit Log with View Details expanded