Skip to main content
Glama
MCP WordPress CrunchTools

MCP WordPress CrunchTools

by crunchtools

MCP WordPress CrunchTools

A secure MCP (Model Context Protocol) server for WordPress content management. Designed for developers publishing about their work.

Overview

This MCP server is designed to be:

  • Secure by default - Input validation, credential protection, and SSRF prevention

  • No third-party services - Runs locally via stdio, your credentials never leave your machine

  • Cross-platform - Works on Linux, macOS, and Windows

  • Automatically updated - GitHub Actions monitor for CVEs and update dependencies

  • Containerized - Available at quay.io/crunchtools/mcp-wordpress

Related MCP server: TypeScript WordPress MCP Server

Naming Convention

Component

Name

GitHub repo

crunchtools/mcp-wordpress

Container

quay.io/crunchtools/mcp-wordpress

Python package (PyPI)

mcp-wordpress-crunchtools

CLI command

mcp-wordpress-crunchtools

Module import

mcp_wordpress_crunchtools

Features

  • 33 Tools for posts, pages, media, and comments

  • Security-focused: Credentials protected, input validation, SSRF prevention

  • Developer workflow: Scheduled publishing, revisions, search

  • Easy integration: Works with Claude Code and other MCP clients

Installation

uvx mcp-wordpress-crunchtools

With pip

pip install mcp-wordpress-crunchtools
mcp-wordpress-crunchtools

With Container

# Create a shared upload directory (required before first run)
mkdir -p ~/.local/share/mcp-uploads-downloads

podman run -v ~/.local/share/mcp-uploads-downloads:/tmp/mcp-uploads:z \
  -e WORDPRESS_URL=https://example.com \
  -e WORDPRESS_USERNAME=admin \
  -e WORDPRESS_APP_PASSWORD='xxxx xxxx xxxx xxxx' \
  quay.io/crunchtools/mcp-wordpress

SELinux note: Use :z (lowercase, shared) instead of :Z (uppercase, private). MCP servers run as long-lived stdio processes. With :Z, files copied into the directory after container start won't have the container's private MCS label and will be invisible inside the container. The :z flag sets a shared container_file_t context that all containers and the host can read/write.

Tip: Use the same shared directory (~/.local/share/mcp-uploads-downloads/) across multiple MCP container servers (e.g., mcp-wordpress and mcp-gemini) so generated files are immediately available for upload without copying.

From source

git clone https://github.com/crunchtools/mcp-wordpress.git
cd mcp-wordpress
uv sync --all-extras
uv run mcp-wordpress-crunchtools

Configuration

Set these environment variables:

Variable

Description

Example

WORDPRESS_URL

WordPress site URL

https://example.com

WORDPRESS_USERNAME

WordPress username

admin

WORDPRESS_APP_PASSWORD

Application password

xxxx xxxx xxxx xxxx

MCP_UPLOAD_DIR

Upload directory inside container (optional)

/tmp/mcp-uploads (default)

Creating an Application Password

  1. Log in to WordPress admin

  2. Go to Users → Profile

  3. Scroll to Application Passwords

  4. Enter a name (e.g., "MCP Server") and click Add New

  5. Copy the generated password (shown once)

Usage with Claude Code

claude mcp add mcp-wordpress-crunchtools \
    --env WORDPRESS_URL=https://example.com \
    --env WORDPRESS_USERNAME=admin \
    --env WORDPRESS_APP_PASSWORD="xxxx xxxx xxxx xxxx" \
    -- uvx mcp-wordpress-crunchtools

Using pip

pip install mcp-wordpress-crunchtools

claude mcp add mcp-wordpress-crunchtools \
    --env WORDPRESS_URL=https://example.com \
    --env WORDPRESS_USERNAME=admin \
    --env WORDPRESS_APP_PASSWORD="xxxx xxxx xxxx xxxx" \
    -- mcp-wordpress-crunchtools

Using Container

# Create a shared upload directory (required before first run)
mkdir -p ~/.local/share/mcp-uploads-downloads

claude mcp add mcp-wordpress-crunchtools \
    --env WORDPRESS_URL=https://example.com \
    --env WORDPRESS_USERNAME=admin \
    --env WORDPRESS_APP_PASSWORD="xxxx xxxx xxxx xxxx" \
    -- podman run -i --rm \
        -v ~/.local/share/mcp-uploads-downloads:/tmp/mcp-uploads:z \
        -e WORDPRESS_URL \
        -e WORDPRESS_USERNAME \
        -e WORDPRESS_APP_PASSWORD \
        quay.io/crunchtools/mcp-wordpress

Available Tools

Site Tools

Tool

Description

wordpress_get_site_info

Get site title, description, URL, timezone

wordpress_test_connection

Verify API credentials work

Editing Model

Reads return the source the editor saved (context=edit), never the rendered page, so what an agent reads is safe to write back. Changes go through the edit_* tools: the agent sends the exact text to replace and its replacement, the server applies it to the current source, and the post never round-trips through the agent. The post and page update and edit tools take an optional expected_version (the version get_post or get_page returned); when it is given, the write is refused if the item changed since. update_* refuses content that is rendered output. edit_draft edits only draft or pending posts, so a gateway can grant revision rights without the power to change published posts.

Post Tools

Tool

Description

wordpress_list_posts

List posts with filtering (status, category, search)

wordpress_get_post

Get single post by ID with its saved source (block markup included) and version

wordpress_search_posts

Search posts by keyword

wordpress_create_post

Create new post (supports scheduling)

wordpress_update_post

Update existing post; refuses rendered HTML, and a stale expected_version when given

wordpress_edit_post

Replace text in a post's source without resending the post

wordpress_edit_draft

Same as edit_post, for draft or pending posts only; refuses any other status

wordpress_delete_post

Delete/trash a post

wordpress_list_revisions

List revisions for a post

wordpress_get_revision

Get specific revision content

wordpress_list_categories

List available categories

wordpress_list_tags

List available tags

Page Tools

Tool

Description

wordpress_list_pages

List pages with filtering

wordpress_get_page

Get single page by ID with its saved source and version

wordpress_create_page

Create new page

wordpress_update_page

Update existing page; refuses rendered HTML, and a stale expected_version when given

wordpress_edit_page

Replace text in a page's source without resending the page

wordpress_delete_page

Delete/trash a page

wordpress_list_page_revisions

List page revisions

Media Tools

Tool

Description

wordpress_list_media

List media items

wordpress_get_media

Get media item details

wordpress_upload_media

Upload file from local path

wordpress_update_media

Update media metadata

wordpress_delete_media

Delete media item

wordpress_get_media_url

Get public URL for media

Comment Tools

Tool

Description

wordpress_list_comments

List comments with filtering

wordpress_get_comment

Get single comment

wordpress_create_comment

Add a comment to a post

wordpress_update_comment

Update comment content/status

wordpress_delete_comment

Delete a comment

wordpress_moderate_comment

Approve, hold, spam, or trash

Examples

Create a Draft Post

Create a new WordPress post titled "My Technical Article" with the content below. Keep it as a draft.

Schedule a Post

Update post ID 123 to publish on December 25, 2024 at 10:00 AM.

Upload an Image

Upload this image to WordPress and set the alt text to "Architecture diagram".

Find and Moderate Comments

List all comments in "hold" status and approve the legitimate ones.

Security

  • Credential Protection: All credentials stored as SecretStr, never logged

  • SSRF Prevention: REST API path hardcoded, cannot be overridden

  • Input Validation: All inputs validated via Pydantic models

  • Rate Limiting: Handles WordPress rate limits gracefully

  • TLS Enforcement: All requests use HTTPS with certificate validation

  • Size Limits: Response size limited to 10MB to prevent memory issues

  • Timeout: All requests timeout after 30 seconds

Development

# Install dev dependencies
uv sync --all-extras

# Run tests
uv run pytest

# Run linting
uv run ruff check src tests

# Run type checking
uv run mypy src

# Format code
uv run ruff format src tests

License

AGPL-3.0-or-later

Credits

Built by crunchtools.com

Available Tools

33 tools
wordpress_create_commentWordpress Create CommentC

Create a new comment on a WordPress post.

Inputs: post (required), content (required), parent, author_name, +1 more. Returns: object

wordpress_create_pageWordpress Create PageC

Create a new WordPress page.

Inputs: title (required), content (required), date, slug, +6 more. Returns: object

wordpress_create_postWordpress Create PostC

Create a new WordPress post.

Inputs: title (required), content (required), date, slug, +6 more. Returns: object

wordpress_delete_commentWordpress Delete CommentB

Delete or trash a WordPress comment.

Inputs: comment_id (required), force. Returns: object

wordpress_delete_mediaWordpress Delete MediaC

Delete a WordPress media item.

Inputs: media_id (required), force. Returns: object

wordpress_delete_pageWordpress Delete PageC

Delete or trash a WordPress page.

Inputs: page_id (required), force. Returns: object

wordpress_delete_postWordpress Delete PostC

Delete or trash a WordPress post.

Inputs: post_id (required), force. Returns: object

wordpress_edit_draftWordpress Edit DraftA

Replace text in a draft or pending WordPress post's source. Refuses any other status.

Inputs: post_id (required), new_text (required), old_text (required), replace_all, +1 more. Returns: object

wordpress_edit_pageWordpress Edit PageA

Replace text in a WordPress page's source, without resending the page.

Inputs: page_id (required), new_text (required), old_text (required), replace_all, +1 more. Returns: object

wordpress_edit_postWordpress Edit PostA

Replace text in a WordPress post's source, without resending the post.

Inputs: post_id (required), new_text (required), old_text (required), replace_all, +1 more. Returns: object

wordpress_get_commentWordpress Get CommentB
Read-only

Get a single WordPress comment by ID.

Inputs: comment_id (required). Returns: object

wordpress_get_mediaWordpress Get MediaB
Read-only

Get a single WordPress media item by ID.

Inputs: media_id (required). Returns: object

wordpress_get_media_urlWordpress Get Media UrlB
Read-only

Get the public URL for a WordPress media item.

Inputs: media_id (required), size. Returns: object

wordpress_get_pageWordpress Get PageB
Read-only

Get a single WordPress page by ID with its saved source.

Inputs: page_id (required). Returns: object

wordpress_get_postWordpress Get PostA
Read-only

Get a single WordPress post by ID with its saved source.

Inputs: post_id (required). Returns: object

wordpress_get_revisionWordpress Get RevisionC
Read-only

Get a specific revision of a WordPress post.

Inputs: post_id (required), revision_id (required). Returns: object

wordpress_get_site_infoWordpress Get Site InfoA
Read-only

Get WordPress site information.

Returns site title, description, URL, timezone, and other settings.

Inputs: no named parameters. Returns: object

wordpress_list_categoriesWordpress List CategoriesC
Read-only

List available WordPress categories.

Inputs: page, search, per_page. Returns: object

wordpress_list_commentsWordpress List CommentsC
Read-only

List WordPress comments with filtering.

Inputs: page, post, order, search, +3 more. Returns: object

wordpress_list_mediaWordpress List MediaC
Read-only

List WordPress media items with filtering.

Inputs: page, order, search, orderby, +3 more. Returns: object

wordpress_list_page_revisionsWordpress List Page RevisionsB
Read-only

List revisions for a WordPress page.

Inputs: page_id (required). Returns: object

wordpress_list_pagesWordpress List PagesC
Read-only

List WordPress pages with filtering and pagination.

Inputs: page, order, parent, search, +3 more. Returns: object

wordpress_list_postsWordpress List PostsC
Read-only

List WordPress posts with filtering and pagination.

Inputs: page, tags, order, search, +4 more. Returns: object

wordpress_list_revisionsWordpress List RevisionsB
Read-only

List revisions for a WordPress post.

Inputs: post_id (required). Returns: object

wordpress_list_tagsWordpress List TagsC
Read-only

List available WordPress tags.

Inputs: page, search, per_page. Returns: object

wordpress_moderate_commentWordpress Moderate CommentC

Moderate a WordPress comment by changing its status.

Inputs: action (required), comment_id (required). Returns: object

wordpress_search_postsWordpress Search PostsA
Read-only

Search WordPress posts by keyword in title and content.

Inputs: keyword (required), page, per_page. Returns: object

wordpress_test_connectionWordpress Test ConnectionA
Read-only

Test connection to WordPress REST API.

Verifies API credentials and returns connection status.

Inputs: no named parameters. Returns: object

wordpress_update_commentWordpress Update CommentC

Update an existing WordPress comment.

Inputs: comment_id (required), status, content. Returns: object

wordpress_update_mediaWordpress Update MediaC

Update WordPress media item metadata.

Inputs: media_id (required), title, caption, alt_text, +1 more. Returns: object

wordpress_update_pageWordpress Update PageA

Update an existing WordPress page. To change part of the content, use edit_page.

Inputs: page_id (required), date, slug, title, +8 more. Returns: object

wordpress_update_postWordpress Update PostB

Update an existing WordPress post. To change part of the content, use edit_post.

Inputs: post_id (required), date, slug, tags, +8 more. Returns: object

wordpress_upload_mediaWordpress Upload MediaA

Upload a media file to WordPress from a local file path.

The file is read directly from disk, avoiding large base64 payloads over the MCP protocol. Provide an absolute path to the file.

CONTAINER NOTE: When running as a container, the file path refers to the container filesystem, not the host. Files must be placed in ~/.local/share/mcp-wordpress/uploads/ on the host (mounted to /tmp/mcp-uploads/ inside the container) to be accessible.

Inputs: file_path (required), title, caption, alt_text, +1 more. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

    TDQS

    B3.2/5.0

    Scored across 33 tools

    Disambiguation4/5

    Most tools map cleanly to a distinct resource and action, especially across posts, pages, media, and comments. The main ambiguity is among update_post/edit_post/edit_draft and update_page/edit_page, which all modify content, though the descriptions distinguish full updates from source-text replacement.

    Naming Consistency5/5

    All tools consistently use the wordpress_ prefix followed by snake_case verb_noun naming, such as list_posts, create_page, delete_comment, and moderate_comment. Names are predictable and readable throughout the set.

    Tool Count2/5

    At 33 tools, the surface is heavy for a single MCP server and exceeds the rubric's 25+ threshold for too many tools. The broad WordPress content domain justifies many operations, but the set could likely consolidate overlapping post/page edit variants and media helpers.

    Completeness4/5

    Core content lifecycle coverage is strong for posts, pages, media, and comments, including revisions and comment moderation. Remaining gaps include no get-page-revision operation, read-only categories/tags, and no broader WordPress admin tools such as users or settings.

    Maintenance

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers