MCP Site Manager

MCP Site Manager

Enables AI agents to manage WordPress sites via ~74 capabilities including content, media, plugins, themes, and more.

Category
Visit Server

README

MCP Site Manager

Manage WordPress from Claude, ChatGPT, Cursor and any other MCP client.

License: GPL v2+ PHP 8.0+ WordPress 6.8+

MCP Site Manager exposes ~74 WordPress capabilities — content, taxonomies, media, comments, users, plugins, themes, options, navigation menus, diagnostics, cache and cron — as Model Context Protocol tools. It plugs into the WP MCP Adapter library (already bundled with WooCommerce 10.3+) and any MCP-compatible AI agent — Claude Desktop, Claude Code, Cursor, VS Code, ChatGPT — can drive your WordPress site.

šŸ“– New to the WordPress MCP Adapter? Read the official primer on the WordPress Developer Blog: From Abilities to AI Agents: Introducing the WordPress MCP Adapter. It explains the Abilities API, the adapter's transports, and how clients connect.

Quick start

  1. Install and activate MCP Site Manager.
  2. If the MCP Adapter library is missing, an admin notice appears with a one-click Install MCP Adapter button that downloads the latest release from WordPress/mcp-adapter Releases. Skipped on sites that already ship the library (e.g. WooCommerce).
  3. Visit Settings → MCP Site Manager for your live connection URL and ready-to-paste client snippets.
  4. Generate an Application Password from your user profile (HTTP transport) — or skip this step entirely if you'll use the STDIO transport for local dev.
  5. Paste the snippet into your MCP client (examples below).

Pin a specific MCP Adapter release tag by filtering mcpsm_adapter_download_url to a stable Releases URL.

Transports

The MCP Adapter ships two transports. Pick by where the AI client and the WordPress install live relative to each other.

HTTP — for remote / production sites

Best when WordPress is publicly reachable. The AI client speaks JSON-RPC over HTTPS through the @automattic/mcp-wordpress-remote proxy.

  • Auth: WordPress Application Password (basic auth). The article also mentions custom OAuth / JWT for advanced setups; this plugin works with whatever the adapter accepts.
  • Production tip: create a dedicated WP user with the minimum capabilities required for the abilities you expose. The AI's blast radius equals that user's caps.

STDIO — for local development

Best when WordPress runs on the same machine as the AI client. The client spawns wp mcp-adapter serve directly via WP-CLI — no Application Password, no HTTPS, nothing to expose.

wp mcp-adapter serve --server=mcp-adapter-default-server --user=admin

The client invokes this command on its own; you don't run it manually.

Connecting your AI client

šŸ”Œ See also: Connecting AI applications on the WordPress Developer Blog — the upstream walkthrough for Claude Desktop, Claude Code, Cursor and VS Code, plus STDIO vs HTTP transport guidance. The snippets below are pre-adapted for this plugin's default server endpoint.

Replace https://your-site.com and your-username / your-password (Application Password) with your own values. For STDIO, replace /path/to/wordpress with your wp-cli --path.

Claude Desktop

Config at ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows). Open via Settings → Developer → Edit config.

<details> <summary><strong>HTTP</strong> (remote site)</summary>

{
  "mcpServers": {
    "mcp-site-manager": {
      "command": "npx",
      "args": ["-y", "@automattic/mcp-wordpress-remote@latest"],
      "env": {
        "WP_API_URL": "https://your-site.com/wp-json/mcp/mcp-adapter-default-server",
        "WP_API_USERNAME": "your-username",
        "WP_API_PASSWORD": "your application password"
      }
    }
  }
}

</details>

<details> <summary><strong>STDIO</strong> (local dev)</summary>

{
  "mcpServers": {
    "mcp-site-manager": {
      "command": "wp",
      "args": [
        "--path=/path/to/wordpress",
        "mcp-adapter",
        "serve",
        "--server=mcp-adapter-default-server",
        "--user=admin"
      ]
    }
  }
}

</details>

Quit and relaunch Claude Desktop. Try: "List my latest 5 posts".

Claude Code

Config at ~/.claude.json (global) or .mcp.json (project). Same shape as Claude Desktop — use mcpServers. The HTTP and STDIO snippets above work verbatim.

Cursor

Config at ~/.cursor/mcp.json or via Settings → Tools and MCP → Add Custom MCP. Same mcpServers shape as Claude Desktop.

VS Code

Config at .vscode/mcp.json in your project. Key is servers, not mcpServers — this is the only client that differs.

<details> <summary><strong>HTTP</strong></summary>

{
  "servers": {
    "mcp-site-manager": {
      "command": "npx",
      "args": ["-y", "@automattic/mcp-wordpress-remote@latest"],
      "env": {
        "WP_API_URL": "https://your-site.com/wp-json/mcp/mcp-adapter-default-server",
        "WP_API_USERNAME": "your-username",
        "WP_API_PASSWORD": "your application password"
      }
    }
  }
}

</details>

<details> <summary><strong>STDIO</strong></summary>

{
  "servers": {
    "mcp-site-manager": {
      "command": "wp",
      "args": [
        "--path=/path/to/wordpress",
        "mcp-adapter",
        "serve",
        "--server=mcp-adapter-default-server",
        "--user=admin"
      ]
    }
  }
}

</details>

ChatGPT and other clients

Any client that speaks MCP over HTTP or STDIO works. Use the HTTP block above; check your client's docs for the equivalent of mcpServers/servers.

Architecture

mcp-site-manager/
ā”œā”€ā”€ mcp-site-manager.php          # Plugin bootstrap: header, constants, hooks
ā”œā”€ā”€ composer.json                 # PSR-4 → Mrabbani\McpSiteManager\
ā”œā”€ā”€ readme.txt                    # wp.org listing
ā”œā”€ā”€ includes/
│   ā”œā”€ā”€ Plugin.php                # Singleton, dependency check, hook wiring
│   ā”œā”€ā”€ Admin/
│   │   ā”œā”€ā”€ SettingsPage.php      # Settings → MCP Site Manager UI
│   │   └── AbilityLog.php        # Custom DB table + recent invocations
│   ā”œā”€ā”€ Abilities/
│   │   ā”œā”€ā”€ AbilityBundle.php     # Abstract base — declarative ability map
│   │   ā”œā”€ā”€ Content/              # Posts, pages, custom post types
│   │   ā”œā”€ā”€ Taxonomy/
│   │   ā”œā”€ā”€ Media/
│   │   ā”œā”€ā”€ Comments/
│   │   ā”œā”€ā”€ Users/
│   │   ā”œā”€ā”€ Plugins/              # install/activate/update/delete
│   │   ā”œā”€ā”€ Themes/               # list/active/switch/install/update/delete
│   │   ā”œā”€ā”€ Options/              # allowlisted only
│   │   ā”œā”€ā”€ Menus/
│   │   ā”œā”€ā”€ Diagnostics/          # health overview, debug log tail
│   │   └── Maintenance/          # cache flush, cron list/run/unschedule
│   └── Support/
│       ā”œā”€ā”€ RestInvoker.php       # internal WP_REST_Request dispatcher
│       ā”œā”€ā”€ SchemaBuilder.php     # JSON Schema helpers for ability inputs
│       ā”œā”€ā”€ ErrorMapper.php       # WP_Error/Throwable → MCP envelope
│       ā”œā”€ā”€ AbilityRunner.php     # try/catch + log + error mapping
│       └── OptionsAllowlist.php
└── tests/
    ā”œā”€ā”€ Support/                  # PHPUnit unit tests
    └── Integration/              # wp-env + curl JSON-RPC smoke tests

How it works

  1. Bootstrap. On plugins_loaded priority 5, Plugin::boot() checks for the MCP Adapter dependency and wires hooks.
  2. Category registration. On wp_abilities_api_categories_init, registers the mcpsm category.
  3. Ability registration. On wp_abilities_api_init, each AbilityBundle registers its abilities via wp_register_ability('mcpsm/<verb>', […]). MCP Adapter's default server discovers registered abilities on its own — no filter wiring required. Clients see them as mcpsm-<verb> (slashes are mcp-adapter-rewritten to hyphens).
  4. Execution. When a client calls tools/call, AbilityBundle::register() wraps the execute callback in AbilityRunner::run(), which centralizes try/catch, logging to the activity log table, and mapping WP_Error/Throwable to JSON-RPC error envelopes.

Two ability patterns

  • REST-wrapping (most abilities). The execute_callback builds a WP_REST_Request and dispatches via rest_do_request(). Reuses every existing REST permission check, sanitizer and schema validator. No reimplementation.
  • Direct PHP (plugin/theme install/activate/delete, options, cache, cron, diagnostics). Where WP has no REST endpoint, the callback calls core APIs directly (Plugin_Upgrader, switch_theme, wp_cache_flush, etc.) with explicit current_user_can() checks.

Permissions

Every ability runs with the calling user's WordPress capabilities. A subscriber can only do what a subscriber can do. Authentication uses WP core's Application Passwords — no custom auth code. Direct-PHP abilities use granular WP caps:

Domain Required cap
Plugins (all verbs) activate_plugins; install/update/delete also need install_plugins/update_plugins/delete_plugins
Themes (all verbs) switch_themes; install/update/delete also need install_themes/update_themes/delete_themes
Options manage_options
Diagnostics manage_options
Maintenance (cache, cron) manage_options
Comments moderation moderate_comments

REST-wrapping abilities defer to the wrapped endpoint's own permission callback (e.g. edit_posts, upload_files).

Options allowlist

To prevent accidental destruction of plugin-internal options or auth data, the Options bundle only reads/writes a hard-coded allowlist:

blogname, blogdescription, permalink_structure, default_category,
posts_per_page, timezone_string, date_format, time_format,
start_of_week, WPLANG, default_comment_status, default_ping_status,
comment_registration, show_on_front, page_on_front, page_for_posts

Anything outside the list is rejected with a 403 and an allowed_keys payload telling the client what's available.

Ability inventory (~74)

Domain Abilities
Posts posts-list, posts-get, posts-create, posts-update, posts-delete
Pages pages-list, pages-get, pages-create, pages-update, pages-delete
CPT cpt-list-types, cpt-list, cpt-get, cpt-create, cpt-update, cpt-delete
Taxonomy taxonomies-list, terms-list, terms-get, terms-create, terms-update, terms-delete
Media media-list, media-get, media-upload, media-update, media-delete
Comments comments-list, comments-get, comments-create, comments-update, comments-delete, comments-moderate
Users users-list, users-get, users-me, users-create, users-update, users-delete
Plugins plugins-list, plugins-activate, plugins-deactivate, plugins-install, plugins-update, plugins-delete, plugins-search
Themes themes-list, themes-active, themes-switch, themes-install, themes-update, themes-delete
Options options-list, options-get, options-update
Menus menus-list, menus-get, menus-create, menus-update, menus-delete, menu-items-{list,get,create,update,delete}, menu-locations-list
Diagnostics health-overview, health-debug-log-tail, health-rest-status
Maintenance cache-flush-rewrite, cache-flush-object, cron-list, cron-run, cron-unschedule

Tool names as seen by MCP clients are hyphen-prefixed: mcpsm-posts-list, mcpsm-themes-active, etc.

Local development

Prerequisites

  • PHP ≄ 8.0
  • Composer
  • Node.js 18+ (for @wordpress/env)
  • Docker Desktop (for wp-env)

Setup

git clone https://github.com/mrabbani/mcp-site-manager.git
cd mcp-site-manager
composer install
npm install

# Place mcp-adapter alongside this repo (sibling directory) so .wp-env.json finds it:
git clone https://github.com/WordPress/mcp-adapter.git ../mcp-adapter
( cd ../mcp-adapter && composer install )

npx wp-env start
npx wp-env run cli wp rewrite structure '/%postname%/' --hard
npx wp-env run cli wp rewrite flush --hard

WordPress is now live at http://localhost:8890 (admin / password).

Tests

# Unit tests (no WordPress)
./vendor/bin/phpunit --testsuite=unit

# Integration tests (against running wp-env)
APP_PW=$(npx wp-env run cli wp user application-password create admin "tests" --porcelain | grep -E '^[a-zA-Z0-9]{20,}' | head -1)

MCPSM_APP_PW="$APP_PW" \
MCPSM_URL="http://localhost:8890/wp-json/mcp/mcp-adapter-default-server" \
MCPSM_USER="admin" \
  ./vendor/bin/phpunit --testsuite=integration

Expected: OK (9 tests, 70 assertions) for integration; OK (9 tests, 17 assertions) for unit.

Manual probe

APP_PW="<paste from above>"

# 1. Initialize the MCP session, capture session id
SID=$(curl -sS -i -u admin:$APP_PW \
  -X POST -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
  http://localhost:8890/wp-json/mcp/mcp-adapter-default-server \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' \
  2>&1 | grep -i "Mcp-Session-Id:" | awk '{print $2}' | tr -d '\r')

# 2. Send the "initialized" notification (required by MCP)
curl -sS -u admin:$APP_PW \
  -X POST -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
  -H "Mcp-Session-Id: $SID" \
  http://localhost:8890/wp-json/mcp/mcp-adapter-default-server \
  -d '{"jsonrpc":"2.0","method":"notifications/initialized"}' > /dev/null

# 3. List tools
curl -sS -u admin:$APP_PW \
  -X POST -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
  -H "Mcp-Session-Id: $SID" \
  http://localhost:8890/wp-json/mcp/mcp-adapter-default-server \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
  | python3 -m json.tool | head -50

# 4. Call a tool
curl -sS -u admin:$APP_PW \
  -X POST -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
  -H "Mcp-Session-Id: $SID" \
  http://localhost:8890/wp-json/mcp/mcp-adapter-default-server \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"mcpsm-themes-active","arguments":{}}}' \
  | python3 -m json.tool

Adding a new ability

Each ability is a single entry in a bundle's abilities() map. Example: a hypothetical posts-trash-empty:

// In includes/Abilities/Content/PostsBundle.php

public function abilities(): array
{
    return [
        // ... existing abilities ...

        'posts-trash-empty' => [
            'label'               => __('Empty trash', 'mcp-site-manager'),
            'description'         => __('Permanently delete every trashed post.', 'mcp-site-manager'),
            'input_schema'        => S::object([]),
            'permission_callback' => self::require_cap('delete_posts'),
            'execute' => function () {
                $trashed = get_posts(['post_status' => 'trash', 'numberposts' => -1, 'fields' => 'ids']);
                $count = 0;
                foreach ($trashed as $id) {
                    if (wp_delete_post($id, true)) $count++;
                }
                return ['deleted' => $count];
            },
        ],
    ];
}

That's it. The bundle base wraps your execute in AbilityRunner (logging + error handling), registers it via wp_register_ability() with meta.mcp.public = true, and MCP Adapter's default server picks it up automatically as mcpsm-posts-trash-empty — no filter wiring required.

Contributing

Issues and PRs welcome at https://github.com/mrabbani/mcp-site-manager/issues.

Local checks before submitting:

# Lint
find includes tests -type f -name "*.php" -print0 | xargs -0 -I{} php -l {} | grep -v "No syntax errors" || echo "ALL CLEAN"

# Tests
./vendor/bin/phpunit --testsuite=unit
# ...integration as above

License

GPL-2.0-or-later. See LICENSE (or the GPL-2.0 text at https://www.gnu.org/licenses/gpl-2.0.html).

Credits

Built by mrabbani on top of WordPress's MCP Adapter and the WordPress Abilities API shipping in WordPress 6.9.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured