MCP Site Manager
Enables AI agents to manage WordPress sites via ~74 capabilities including content, media, plugins, themes, and more.
README
MCP Site Manager
Manage WordPress from Claude, ChatGPT, Cursor and any other MCP client.
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
- Install and activate MCP Site Manager.
- 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).
- Visit Settings → MCP Site Manager for your live connection URL and ready-to-paste client snippets.
- 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.
- Paste the snippet into your MCP client (examples below).
Pin a specific MCP Adapter release tag by filtering
mcpsm_adapter_download_urlto 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
- Bootstrap. On
plugins_loadedpriority 5,Plugin::boot()checks for the MCP Adapter dependency and wires hooks. - Category registration. On
wp_abilities_api_categories_init, registers themcpsmcategory. - Ability registration. On
wp_abilities_api_init, eachAbilityBundleregisters its abilities viawp_register_ability('mcpsm/<verb>', […]). MCP Adapter's default server discovers registered abilities on its own — no filter wiring required. Clients see them asmcpsm-<verb>(slashes are mcp-adapter-rewritten to hyphens). - Execution. When a client calls
tools/call,AbilityBundle::register()wraps the execute callback inAbilityRunner::run(), which centralizes try/catch, logging to the activity log table, and mappingWP_Error/Throwableto JSON-RPC error envelopes.
Two ability patterns
- REST-wrapping (most abilities). The
execute_callbackbuilds aWP_REST_Requestand dispatches viarest_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 explicitcurrent_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.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。