Discourse MCP
OFFICIAL SERVERRead, search and, when allowed, post to and administer a Discourse forum over MCP
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
Opens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.
It needs WORDPRESS_SITE_URL, WORDPRESS_USERNAME, WORDPRESS_APP_PASSWORD. Replace each <NAME> with your value.
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{
"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>"
}
}
}
}{
"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>"
}
}
}
}{
"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>"
}
}
}
}[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 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-wordpressOpens the app, which asks before it adds the server. Then replace each <NAME> in its settings with your value.
It needs WORDPRESS_SITE_URL, WORDPRESS_USERNAME, WORDPRESS_APP_PASSWORD. Replace each <NAME> with your value.
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{
"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>"
}
}
}
}{
"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>"
}
}
}
}{
"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>"
}
}
}
}[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 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| 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. |
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. |
ALLOW_INSECURE_HTTP |
Optional: Set to true to allow an http site URL. |
ALLOW_PRIVATE_URLS |
Optional: Set to true to allow localhost or private-network site URLs. |
| 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.
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.
| Runtime | Node.js 22.14+Docker |
|---|---|
| Runs on | macOS, Windows, Linux |
| WordPress | Your 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 |
|
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.
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.
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.
32 only read, 20 change things, 8 can delete or overwrite. A ? marks an optional parameter.
wp_list_postsper_page?: numberpost_type?: stringpage?: numbersearch?: stringstatus?: enumcategories?: arraytags?: arraywp_get_postid: numberpost_type?: stringinclude_content?: booleanwp_create_post changestitle: stringpost_type?: stringcontent?: stringstatus?: enumexcerpt?: stringcategories?: arraytags?: arrayfeatured_media?: numberdate?: stringwp_update_post changesid: numberpost_type?: stringtitle?: stringcontent?: stringstatus?: enumexcerpt?: stringcategories?: arraytags?: arrayfeatured_media?: numberdate?: stringwp_delete_post deletesid: numberpost_type?: stringforce?: booleanwp_get_post_revisionsid: numberwp_list_pagesper_page?: numbersearch?: stringstatus?: enumwp_get_pageid: numberinclude_content?: booleanwp_create_page changestitle: stringcontent?: stringstatus?: enumwp_update_page changesid: numbertitle?: stringcontent?: stringstatus?: enumwp_delete_page deletesid: numberforce?: booleanwp_list_mediaper_page?: numbersearch?: stringmedia_type?: enumwp_upload_media changesfile_path: stringtitle?: stringalt_text?: stringcaption?: stringdescription?: stringpost?: numberwp_update_media changesid: numbertitle?: stringalt_text?: stringcaption?: stringdescription?: stringwp_delete_media deletesid: numberforce?: booleanwp_list_userssearch?: stringroles?: arraywp_get_current_userwp_create_user changesusername: stringemail: stringpassword: stringroles?: arraywp_update_user changesid: numberemail?: stringname?: stringwp_delete_user deletesid: numberreassign?: numberwp_list_commentspost?: numberstatus?: enumper_page?: numberpage?: numberwp_create_comment changespost: numbercontent: stringauthor_name?: stringauthor_email?: stringwp_update_comment changesid: numbercontent?: stringstatus?: enumwp_delete_comment deletesid: numberforce?: booleanwp_approve_comment changesid: numberwp_spam_comment changesid: numberwp_list_categoriessearch?: stringhide_empty?: booleanper_page?: numberpage?: numberwp_create_category changesname: stringdescription?: stringwp_update_category changesid: numbername?: stringwp_delete_category deletesid: numberwp_list_tagssearch?: stringper_page?: numberpage?: numberwp_create_tag changesname: stringwp_update_tag changesid: numbername?: stringwp_delete_tag deletesid: numberwp_get_site_settingswp_update_site_settings changestitle?: stringdescription?: stringtimezone?: stringwp_search_siteterm: stringtype?: enumwp_get_application_passwordsuser_id: numberwp_create_application_password changesuser_id: numberapp_name: stringwp_delete_application_password deletesuser_id: numberuuid: stringwp_test_authwp_switch_auth_methodmethod: enumusername?: stringpassword?: stringjwt_secret?: stringapi_key?: stringwp_cache_statswp_cache_clear changespattern?: stringwp_performance_statssite?: stringcategory?: stringformat?: stringwp_performance_optimizesite?: stringfocus?: stringpriority?: stringincludeROI?: booleanincludePredictions?: booleanwp_check_versioncurrent_version?: stringwp_list_pluginswp_list_themeswp_seo_analyze_contentpostId: numberanalysisType?: enumfocusKeywords?: arraysite?: stringwp_seo_generate_metadatapostId: numbertitle?: stringdescription?: stringfocusKeyword?: stringsite?: stringwp_seo_bulk_update_metadata changespostIds: arrayupdates: objectdryRun?: booleansite?: stringwp_seo_generate_schemapostId: numberschemaType: enumcustomData?: objectsite?: stringwp_seo_validate_schemaschema: objectschemaType?: stringuseGoogleValidator?: booleansite?: stringwp_seo_suggest_internal_linkspostId: numbermaxSuggestions?: numberminimumRelevance?: numbersite?: stringwp_seo_site_auditauditType?: enummaxPages?: numberforce?: booleansite?: stringwp_seo_track_serpkeywords: arrayurl?: stringsearchEngine?: enumlocation?: stringsite?: stringwp_seo_keyword_researchseedKeyword: stringincludeVariations?: booleanincludeQuestions?: booleanmaxResults?: numbersite?: stringwp_seo_test_integrationcheckPlugins?: booleantestMetadataAccess?: booleansite?: stringwp_seo_get_live_datapostId: numberincludeAnalysis?: booleanincludeRecommendations?: booleansite?: string