
🔌 WordPress Supports MCP Now?
WordPress.com officially started supporting MCP (Model Context Protocol). That means you can create posts, manage categories, and tweak site settings directly from Claude Code. Our blog-agent had been handling WordPress through a REST API + Bearer token + Playwright combo, so I wondered what switching to WordPress MCP integration would look like.
The short version: applied in v0.8.0. But I couldn’t replace everything with MCP, so it ended up as a hybrid architecture. Let me walk you through the process.
😤 Problems with the Old Approach
Here’s what the WordPress integration looked like up through blog-agent v0.7.x.
# Previous flow (v0.7.x)
1. Read Bearer token from Confluence
2. URL-decode (token was encoded)
3. Upload media via REST API
4. Create post via REST API
5. Link languages via Playwright
(Polylang)
6. Edit Gutenberg via Playwright
There were a few problems.
- Token expiration — Bearer tokens expire periodically. When a 403 showed up, I had to go to Confluence and refresh it.
- URL decoding nightmare — The token stored in Confluence was HTML-entity-encoded, so decoding logic was necessary.
- Playwright instability — Polylang language linking can’t be done via REST API, so it relied on browser automation — which broke whenever the UI changed.
🔍 Discovering WordPress MCP
I came across the Abilities API and MCP adapter announcement on the WordPress Developer Blog. There are two versions.
wpcom-mcp vs mcp-adapter
| Item | wpcom-mcp | WordPress/mcp-adapter |
|---|---|---|
| Target | WordPress.com | Self-hosted WordPress |
| Transport | Streamable HTTP | stdio |
| Install | Not needed (hosted) | Install on server |
| Auth | OAuth 2.1 (automatic) | Application Password |
| Tool count | 30+ | Plugin-dependent |
Since ai-girls.org is on WordPress.com hosting, I went with wpcom-mcp. The key difference is the transport method.
stdio vs Streamable HTTP
The existing MCP servers I’d been using (nanobanana, terry-xai, mcp-atlassian, etc.) all use the stdio transport — spawning a local process and communicating via stdin/stdout.
WordPress MCP is different. You declare type: "http" and send HTTP requests to an endpoint hosted by WordPress.com. The biggest advantage: no server installation required.

⚙️ Setup and Implementation
.mcp.json Configuration
Just 4 lines added to the existing .mcp.json.
{
"mcpServers": {
"wpcom-mcp": {
"type": "http",
"url": "https://public-api.wordpress.com/wpcom/v2/mcp/v1"
}
}
}
Compare this to stdio servers. stdio requires command, args, and env, but the HTTP method only needs type and url. OAuth authentication is handled automatically by Claude.
config.yaml Changes
# config.yaml (v0.8.0)
wordpress:
site_url: "https://ai-girls.org"
site_id: 252529337
mcp_enabled: true
mcp_site: "ai-girls.org"
# Bearer token — kept for REST fallback
token_confluence_page_id: "108790117"
mcp_enabled: true is the key. This flag lets you switch between MCP-first and REST-fallback strategies at runtime.
MCP-first / REST-fallback Strategy

I refactored publisher.md to define this priority order.
# Publisher Strategy (v0.8.0)
## Post Create/Update
Primary: wpcom-mcp-content-authoring
Fallback: REST API (Bearer token)
## Media Upload
Always: REST API (MCP unsupported)
## Polylang Language Linking
Always: REST + Playwright
(MCP unsupported)
MCP Tool Call Example
Here’s what an actual MCP call looks like when creating a post.
wpcom-mcp-content-authoring:
action: execute
wpcom_site: ai-girls.org
operation: posts.create
params:
title: "Post Title"
content: "<HTML content>"
slug: "post-slug-ko"
categories: [3111150]
featured_media: 12345
status: draft
meta:
rank_math_title: "SEO Title"
rank_math_description: "Desc"
rank_math_focus_keyword: "Keyword"
user_confirmed:
"Pipeline auto-approved"
user_confirmed is mandatory. WordPress MCP has a safety policy that requires user confirmation for write operations. In automated pipelines, you must explicitly include this field for the post to actually be created.
wordpress_tools.py Changes
I added a helper function that builds MCP call parameters.
# wordpress_tools.py (v0.8.0)
def mcp_create_post(
title: str,
content: str,
slug: str,
categories: list[int],
featured_media: int | None = None,
status: str = "draft",
meta: dict | None = None,
) -> dict[str, Any]:
"""
Build MCP tool call params
for posts.create.
"""
params: dict[str, Any] = {
"title": title,
"content": content,
"slug": slug,
"categories": categories,
"status": status,
}
if featured_media:
params["featured_media"] = (
featured_media
)
if meta:
params["meta"] = meta
return params
This function doesn’t call the API directly. It builds the parameter dictionary that Claude Code needs when invoking the MCP tool. The actual communication is handled by Claude Code’s MCP runtime.
🚧 Limitations — Why It Became a Hybrid
I wanted to switch everything to MCP, but two things didn’t work.

1. No Media Upload Support
WordPress MCP supports media metadata editing, but not file uploads. Uploading images still requires the REST API.
# Media upload — still REST API
python tools_runner.py \
wp_upload_media \
--image-path "featured_image.jpg" \
--token "$TOKEN"
MCP’s Streamable HTTP transport isn’t optimized for binary file transfers. It might be supported in the future, but for now REST is the only option.
2. No Polylang Multilingual Support
ai-girls.org runs three languages (Korean, English, Japanese) via Polylang. Since Polylang is a third-party plugin, it falls outside the scope of WordPress MCP’s toolset.
Language linking still relies on the REST API + Playwright combination. This won’t change until Polylang provides its own MCP, or WordPress MCP adds plugin extension support.
✅ Results After Applying
The Power of OAuth 2.1
The most noticeable change is authentication. Let me compare it to the old REST API flow.
| Item | REST API (before) | MCP (v0.8.0) |
|---|---|---|
| Auth | Manual Bearer token mgmt | OAuth 2.1 automatic |
| Token expiry | Periodic 403 errors | Auto-refresh |
| Setup complexity | Confluence token + URL decoding |
4 lines in .mcp.json |
| Post creation | curl + JSON serialization | MCP tool call |
| Error handling | HTTP status code parsing | Delegated to MCP runtime |
The entire routine of reading tokens from Confluence, URL-decoding them, and refreshing on 403 — gone. Add one URL to .mcp.json and you’re done.
30+ MCP Tools
Here’s a category breakdown of the tools WordPress MCP provides.

- Content Authoring — posts, pages, media (metadata only), comments, categories, tags, patterns
- Site Editor Context — theme, blocks
- Site Management — settings, statistics, plugins, users
- User Account — profile, achievements, notifications
- Domain Purchase — domain search and purchase
In practice, blog-agent mostly uses the posts-related tools under Content Authoring. But you could also automate traffic analysis with the statistics tool, or monitor plugin status with the plugins tool.
📐 Before / After Comparison
Post Creation Code Comparison
# Before (REST API)
token = read_confluence_token()
token = urllib.parse.unquote(token)
resp = curl_json(
"POST",
f"{API_BASE}/posts",
token,
data={
"title": title,
"content": html,
"status": "draft",
},
)
post_id = resp["id"]
# After (MCP)
# No token mgmt — OAuth auto-handled
params = mcp_create_post(
title=title,
content=html,
slug=slug,
categories=[3111150],
status="draft",
meta={
"rank_math_title": seo_title,
"rank_math_description": desc,
},
)
# Claude Code MCP runtime executes this
See how all the token-related code is completely gone? No read_confluence_token(), no urllib.parse.unquote().
🔮 Looking Ahead
WordPress 7.0 and the Abilities API
WordPress 7.0, scheduled for April 9, 2026, will merge the Abilities API into core. This means self-hosted WordPress sites will be able to use the MCP adapter without any plugins.
Currently, the self-hosted WordPress/mcp-adapter requires a separate installation, but after 7.0 it becomes a core feature.
The State of the MCP Ecosystem
One thing I noticed while applying WordPress MCP: the MCP ecosystem isn’t at the “everything just works” stage yet. Features like media upload are missing, and third-party plugins (Polylang, etc.) are still outside MCP’s scope.
But MCP-first is the right direction. Three reasons.
- Simplified auth — OAuth 2.1 auto-handling eliminates token management entirely.
- Tool extensibility — 30+ tools already exist and the list keeps growing.
- Standardization — MCP is an open protocol led by Anthropic. Not just WordPress — Slack, GitHub, Jira, and many other services are adopting MCP.
Keep REST only for what doesn’t work yet, and switch to MCP for everything that does. That’s the most practical strategy right now.
💡 Lessons Learned

| Lesson | Detail |
|---|---|
| MCP != silver bullet | Media uploads and third-party plugins still need REST |
| HTTP transport is key | Unlike stdio, no server install needed — 4-line config and done |
| OAuth 2.1 = game changer | Entire token management routine deleted |
| user_confirmed required | Forget it in automation pipelines and write ops will fail |
| Hybrid is realistic | MCP-first + REST-fallback is the best architecture for now |
This post is the first one published by blog-agent v0.8.0 using the MCP-first strategy. If you’re curious about WordPress MCP integration, start by adding 4 lines to your .mcp.json. That’s literally it.