MCP WordPress

Manage posts, pages, media, users, comments and SEO on self-run WordPress sites over the REST API

By Thomas Juul Dyhr (individual) TypeScript Local · stdio Productivity

54 popularity score ★ 114 ↓ 1.7k/wk

Connect your client

Local (npm)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

It needs WORDPRESS_SITE_URL, WORDPRESS_USERNAME, WORDPRESS_APP_PASSWORD. Replace each <NAME> with your value.

Claude CodeTerminal
claude mcp add wordpress -e WORDPRESS_SITE_URL=<WORDPRESS_SITE_URL> -e WORDPRESS_USERNAME=<WORDPRESS_USERNAME> -e WORDPRESS_APP_PASSWORD=<WORDPRESS_APP_PASSWORD> -- npx -y mcp-wordpress
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "wordpress": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-wordpress"
      ],
      "env": {
        "WORDPRESS_SITE_URL": "<WORDPRESS_SITE_URL>",
        "WORDPRESS_USERNAME": "<WORDPRESS_USERNAME>",
        "WORDPRESS_APP_PASSWORD": "<WORDPRESS_APP_PASSWORD>"
      }
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "wordpress": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-wordpress"
      ],
      "env": {
        "WORDPRESS_SITE_URL": "<WORDPRESS_SITE_URL>",
        "WORDPRESS_USERNAME": "<WORDPRESS_USERNAME>",
        "WORDPRESS_APP_PASSWORD": "<WORDPRESS_APP_PASSWORD>"
      }
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "wordpress": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "mcp-wordpress"
      ],
      "env": {
        "WORDPRESS_SITE_URL": "<WORDPRESS_SITE_URL>",
        "WORDPRESS_USERNAME": "<WORDPRESS_USERNAME>",
        "WORDPRESS_APP_PASSWORD": "<WORDPRESS_APP_PASSWORD>"
      }
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.wordpress]
command = "npx"
args = ["-y", "mcp-wordpress"]

[mcp_servers.wordpress.env]
WORDPRESS_SITE_URL = "<WORDPRESS_SITE_URL>"
WORDPRESS_USERNAME = "<WORDPRESS_USERNAME>"
WORDPRESS_APP_PASSWORD = "<WORDPRESS_APP_PASSWORD>"
Gemini CLITerminal
gemini mcp add --scope user -e WORDPRESS_SITE_URL=<WORDPRESS_SITE_URL> -e WORDPRESS_USERNAME=<WORDPRESS_USERNAME> -e WORDPRESS_APP_PASSWORD=<WORDPRESS_APP_PASSWORD> wordpress npx -- -y mcp-wordpress
Local (container)

Add in one click

Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.

Or add it by command or config

It needs WORDPRESS_SITE_URL, WORDPRESS_USERNAME, WORDPRESS_APP_PASSWORD. Replace each <NAME> with your value.

Claude CodeTerminal
claude mcp add wordpress -e WORDPRESS_SITE_URL=<WORDPRESS_SITE_URL> -e WORDPRESS_USERNAME=<WORDPRESS_USERNAME> -e WORDPRESS_APP_PASSWORD=<WORDPRESS_APP_PASSWORD> -- docker run -i --rm -e WORDPRESS_SITE_URL -e WORDPRESS_USERNAME -e WORDPRESS_APP_PASSWORD docdyhr/mcp-wordpress:latest
Claude Desktopclaude_desktop_config.json
{
  "mcpServers": {
    "wordpress": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "WORDPRESS_SITE_URL",
        "-e",
        "WORDPRESS_USERNAME",
        "-e",
        "WORDPRESS_APP_PASSWORD",
        "docdyhr/mcp-wordpress:latest"
      ],
      "env": {
        "WORDPRESS_SITE_URL": "<WORDPRESS_SITE_URL>",
        "WORDPRESS_USERNAME": "<WORDPRESS_USERNAME>",
        "WORDPRESS_APP_PASSWORD": "<WORDPRESS_APP_PASSWORD>"
      }
    }
  }
}
Cursor~/.cursor/mcp.json
{
  "mcpServers": {
    "wordpress": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "WORDPRESS_SITE_URL",
        "-e",
        "WORDPRESS_USERNAME",
        "-e",
        "WORDPRESS_APP_PASSWORD",
        "docdyhr/mcp-wordpress:latest"
      ],
      "env": {
        "WORDPRESS_SITE_URL": "<WORDPRESS_SITE_URL>",
        "WORDPRESS_USERNAME": "<WORDPRESS_USERNAME>",
        "WORDPRESS_APP_PASSWORD": "<WORDPRESS_APP_PASSWORD>"
      }
    }
  }
}
VS Code.vscode/mcp.json
{
  "servers": {
    "wordpress": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "WORDPRESS_SITE_URL",
        "-e",
        "WORDPRESS_USERNAME",
        "-e",
        "WORDPRESS_APP_PASSWORD",
        "docdyhr/mcp-wordpress:latest"
      ],
      "env": {
        "WORDPRESS_SITE_URL": "<WORDPRESS_SITE_URL>",
        "WORDPRESS_USERNAME": "<WORDPRESS_USERNAME>",
        "WORDPRESS_APP_PASSWORD": "<WORDPRESS_APP_PASSWORD>"
      }
    }
  }
}
Codex~/.codex/config.toml
[mcp_servers.wordpress]
command = "docker"
args = ["run", "-i", "--rm", "-e", "WORDPRESS_SITE_URL", "-e", "WORDPRESS_USERNAME", "-e", "WORDPRESS_APP_PASSWORD", "docdyhr/mcp-wordpress:latest"]

[mcp_servers.wordpress.env]
WORDPRESS_SITE_URL = "<WORDPRESS_SITE_URL>"
WORDPRESS_USERNAME = "<WORDPRESS_USERNAME>"
WORDPRESS_APP_PASSWORD = "<WORDPRESS_APP_PASSWORD>"
Gemini CLITerminal
gemini mcp add --scope user -e WORDPRESS_SITE_URL=<WORDPRESS_SITE_URL> -e WORDPRESS_USERNAME=<WORDPRESS_USERNAME> -e WORDPRESS_APP_PASSWORD=<WORDPRESS_APP_PASSWORD> wordpress docker -- run -i --rm -e WORDPRESS_SITE_URL -e WORDPRESS_USERNAME -e WORDPRESS_APP_PASSWORD docdyhr/mcp-wordpress:latest

Settings 12

Set together: single site
WORDPRESS_SITE_URL Required: Full https address of the WordPress site.
WORDPRESS_USERNAME Required: WordPress user to sign in as (not used with api-key sign-in).
WORDPRESS_APP_PASSWORD secret Required: Application password for that user; used by the default app-password method.
WORDPRESS_AUTH_METHOD Optional: app-password, jwt, basic or api-key. Default app-password.
WORDPRESS_PASSWORD secret Optional: Account password, for basic or jwt sign-in instead of an application password.
WORDPRESS_JWT_SECRET secret Optional: Secret of the JWT Authentication plugin, for jwt sign-in.
WORDPRESS_API_KEY secret Optional: Key from an API-key plugin, for api-key sign-in.
MCP_UPLOAD_BASE_DIR Optional: Folder wp_upload_media may read files from; uploads are off when unset. For wp_upload_media.
ALLOW_INSECURE_HTTP Optional: Set to true to allow an http site URL. Default false.
ALLOW_PRIVATE_URLS Optional: Set to true to allow localhost or private-network site URLs. Default false.
Set together: multi-site
MCP_WORDPRESS_ALLOW_MULTI_SITE Optional: Set to true to load a multi-site JSON file; without it the server stops when one is found.
MCP_WORDPRESS_CONFIG Optional: Path to the multi-site JSON file.

In a container, a setting goes in with -e NAME=value after docker run.

What it does

MCP WordPress is a local Node.js server, by an independent developer rather than Automattic or the WordPress project, that talks to one or more WordPress sites through the standard REST API (wp-json). It runs on your machine over stdio and signs in to each site with credentials you give it, by default a WordPress application password.

Version 4.2.3 registers 73 tools. They cover posts and custom post types, pages, media, users, comments, categories and tags, site settings and application passwords. There are also sign-in checks, a response cache, session performance statistics and eleven SEO tools that score content, draft meta tags and JSON-LD, audit a site and read what an installed SEO plugin stores. The system group now has three tools: an update check plus wp_list_plugins and wp_list_themes, which only read what is installed and cannot activate or change anything (src/tools/system.ts). Most other groups both read and change the site, so an assistant connected to it can publish, edit and delete content, manage users and change general settings, within what the signed-in WordPress role allows. List tools hand back 10 items a page unless per_page asks for more, up to 100, and add a note when a page comes back full (src/tools/params.ts).

One site is set with environment variables. Several sites (up to 50 per its configuration guide) go in a JSON file, and the server refuses to start when it finds such a file unless MCP_WORDPRESS_ALLOW_MULTI_SITE=true is set, a guard against loading another project's production credentials by accident (src/config/ServerConfiguration.ts). It looks for the file at MCP_WORDPRESS_CONFIG, then ~/.config/mcp-wordpress/config.json, then ~/mcp-wordpress.config.json, then a legacy copy in its install folder. Besides npx it ships as a Claude Desktop extension (.dxt) on its GitHub releases and as the Docker image docdyhr/mcp-wordpress.

What it needs

RuntimeNode.js 22.14+Docker
Runs onmacOS, Windows, Linux
WordPressYour own instanceA site on WordPress 5.6 or later with the REST API reachable over https, and a user whose role covers the work
Also
  • JWT or API-key sign-in needs the matching plugin on the site

Node.js 22.14 or later for the npx way (package.json engines), or Docker for the image. Editor or above covers most content work. Site settings need an Administrator, as do wp_list_plugins (activate_plugins capability) and wp_list_themes (switch_themes) on a default role setup. Create the application password under Users > Profile in wp-admin.

Limits

  • Not covered Site URLs must be public https: http is refused unless ALLOW_INSECURE_HTTP=true, and localhost or private addresses unless ALLOW_PRIVATE_URLS=true
  • Limit The configuration guide shows http://localhost site URLs without naming the two override settings they need
  • Not covered wp_upload_media is off until MCP_UPLOAD_BASE_DIR names an existing folder, and then reads only files inside it
  • Limit Deleted categories and tags are gone for good, as WordPress terms have no trash
  • Size cap List tools return 10 items a page by default, up to 100 with per_page
  • Read only Plugins and themes can be listed but not installed, activated or updated
  • Not covered Performance totals cover the current session across all configured sites
  • Limit The docs' Docker example starts the container with -d, which a client cannot talk to. Use -i --rm instead

Site URLs must be https on a public host: http, localhost and private addresses are refused unless ALLOW_INSECURE_HTTP=true and ALLOW_PRIVATE_URLS=true are set (src/utils/validation/network.ts), though the configuration guide shows http://localhost examples without them. wp_upload_media is off until MCP_UPLOAD_BASE_DIR names an existing folder, and then reads only files inside it (src/tools/media.ts). Deleted categories and tags are gone for good, as WordPress terms have no trash. Performance figures cover the current session across all sites. The docs' Docker example uses -d, which a client cannot talk to; use -i --rm.

Who it suits

Suits someone who runs or manages self-hosted WordPress sites, or several client sites, and wants an assistant to write, edit and tidy content, moderate comments and check SEO without opening wp-admin. Because it writes as the user it signs in as, give it an application password for a role no higher than needed. Pick something else if you want an option maintained by the WordPress project: the Automattic repository this README names as the official alternative is archived and now points to WordPress/mcp-adapter, which we also list and which runs as a plugin inside the site rather than as a separate Node process.

Tools 60 of 73

32 only read, 20 change things, 8 can delete or overwrite. A ? marks an optional parameter.

wp_list_posts
List posts or a custom post type, filtered by search, status, category or tag; 10 per page by defaultper_page?: numberpost_type?: stringpage?: numbersearch?: stringstatus?: enumcategories?: arraytags?: array
wp_get_post
Fetch one post with its metadata and, by default, its raw block markupid: numberpost_type?: stringinclude_content?: boolean
wp_create_post changes
Create a post or custom post type entrytitle: stringpost_type?: stringcontent?: stringstatus?: enumexcerpt?: stringcategories?: arraytags?: arrayfeatured_media?: numberdate?: string
wp_update_post changes
Change the fields given on an existing postid: numberpost_type?: stringtitle?: stringcontent?: stringstatus?: enumexcerpt?: stringcategories?: arraytags?: arrayfeatured_media?: numberdate?: string
wp_delete_post deletes
Move a post to trash, or delete it for good with forceid: numberpost_type?: stringforce?: boolean
wp_get_post_revisions
List a post's revision historyid: number
wp_list_pages
List pages with search and status filtersper_page?: numbersearch?: stringstatus?: enum
wp_get_page
Fetch one page, optionally with full contentid: numberinclude_content?: boolean
wp_create_page changes
Create a pagetitle: stringcontent?: stringstatus?: enum
wp_update_page changes
Edit an existing pageid: numbertitle?: stringcontent?: stringstatus?: enum
wp_delete_page deletes
Trash a page, or delete it for good with forceid: numberforce?: boolean
wp_list_media
List media library items by search or media typeper_page?: numbersearch?: stringmedia_type?: enum
wp_upload_media changes
Upload a local file to the media library (needs MCP_UPLOAD_BASE_DIR)file_path: stringtitle?: stringalt_text?: stringcaption?: stringdescription?: stringpost?: number
wp_update_media changes
Edit a media item's title, alt text, caption or descriptionid: numbertitle?: stringalt_text?: stringcaption?: stringdescription?: string
wp_delete_media deletes
Delete a media itemid: numberforce?: boolean
wp_list_users
List users with their rolessearch?: stringroles?: array
wp_get_current_user
Show the signed-in user's profile, roles and capabilities
wp_create_user changes
Create a user with a password and rolesusername: stringemail: stringpassword: stringroles?: array
wp_update_user changes
Change a user's email or display nameid: numberemail?: stringname?: string
wp_delete_user deletes
Delete a user, optionally handing their posts to another userid: numberreassign?: number
wp_list_comments
List comments by post or statuspost?: numberstatus?: enumper_page?: numberpage?: number
wp_create_comment changes
Add a comment to a postpost: numbercontent: stringauthor_name?: stringauthor_email?: string
wp_update_comment changes
Edit a comment's text or statusid: numbercontent?: stringstatus?: enum
wp_delete_comment deletes
Trash a comment, or delete it for good with forceid: numberforce?: boolean
wp_approve_comment changes
Approve a pending commentid: number
wp_spam_comment changes
Mark a comment as spamid: number
wp_list_categories
List categoriessearch?: stringhide_empty?: booleanper_page?: numberpage?: number
wp_create_category changes
Create a categoryname: stringdescription?: string
wp_update_category changes
Rename a categoryid: numbername?: string
wp_delete_category deletes
Delete a category for good, as terms have no trashid: number
wp_list_tags
List tagssearch?: stringper_page?: numberpage?: number
wp_create_tag changes
Create a tagname: string
wp_update_tag changes
Rename a tagid: numbername?: string
wp_delete_tag deletes
Delete a tag for good, as terms have no trashid: number
wp_get_site_settings
Read general site settings (administrator only)
wp_update_site_settings changes
Change the site title, tagline or timezone (administrator only)title?: stringdescription?: stringtimezone?: string
wp_search_site
Search posts, pages and media on the siteterm: stringtype?: enum
wp_get_application_passwords
List a user's application passwordsuser_id: number
wp_create_application_password changes
Create an application password for a useruser_id: numberapp_name: string
wp_delete_application_password deletes
Revoke an application passworduser_id: numberuuid: string
wp_test_auth
Check sign-in and connection to a configured site
wp_switch_auth_method
Try another sign-in method in memory without switching the live onemethod: enumusername?: stringpassword?: stringjwt_secret?: stringapi_key?: string
wp_cache_stats
Show cache hit and size figures for one site
wp_cache_clear changes
Empty the server's own cache for a site, or the entries matching a patternpattern?: string
wp_performance_stats
Show request counts, response times and errors for this session, plus recent tool callssite?: stringcategory?: stringformat?: string
wp_performance_optimize
Suggest performance improvementssite?: stringfocus?: stringpriority?: stringincludeROI?: booleanincludePredictions?: boolean
wp_check_version
Check whether a newer mcp-wordpress release existscurrent_version?: string
wp_list_plugins
List installed plugins with status, version and author (needs the activate_plugins capability)
wp_list_themes
List installed themes, the active one first, with parent theme and features (needs switch_themes)
wp_seo_analyze_content
Score a post's readability, keyword use and structurepostId: numberanalysisType?: enumfocusKeywords?: arraysite?: string
wp_seo_generate_metadata
Draft title, meta description and social tags for a postpostId: numbertitle?: stringdescription?: stringfocusKeyword?: stringsite?: string
wp_seo_bulk_update_metadata changes
Write SEO metadata to many posts in one run, with a dry-run optionpostIds: arrayupdates: objectdryRun?: booleansite?: string
wp_seo_generate_schema
Build JSON-LD structured data for a postpostId: numberschemaType: enumcustomData?: objectsite?: string
wp_seo_validate_schema
Check JSON-LD markup for errorsschema: objectschemaType?: stringuseGoogleValidator?: booleansite?: string
wp_seo_suggest_internal_links
Suggest links to other posts on the sitepostId: numbermaxSuggestions?: numberminimumRelevance?: numbersite?: string
wp_seo_site_audit
Audit the site's technical and content SEOauditType?: enummaxPages?: numberforce?: booleansite?: string
wp_seo_track_serp
Track search result positions for keywordskeywords: arrayurl?: stringsearchEngine?: enumlocation?: stringsite?: string
wp_seo_keyword_research
Suggest keywords for a seed termseedKeyword: stringincludeVariations?: booleanincludeQuestions?: booleanmaxResults?: numbersite?: string
wp_seo_test_integration
Detect which SEO plugins the site hascheckPlugins?: booleantestMetadataAccess?: booleansite?: string
wp_seo_get_live_data
Read the metadata the site's SEO plugin stores for a postpostId: numberincludeAnalysis?: booleanincludeRecommendations?: booleansite?: string

Similar servers