Skip to content

Session errors

The WordPress MCP Adapter uses MCP’s session-based HTTP transport. Every request after initialize must include the Mcp-Session-Id header from the initialize response. Most MCP clients handle this; some don’t.

Symptom: every request after the first fails

Section titled “Symptom: every request after the first fails”

Likely cause: client isn’t preserving the session ID. Test with curl:

Terminal window
# 1. Initialize, capture the response with -i (show headers)
curl -i -X POST https://your-site.test/wp-json/mcp/emcp-tools-server \
-H "Content-Type: application/json" \
-u "admin:xxxx xxxx xxxx xxxx xxxx xxxx" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'

Look for the Mcp-Session-Id header in the response. Copy that value.

Terminal window
# 2. List tools, include the session header
curl -X POST https://your-site.test/wp-json/mcp/emcp-tools-server \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: <paste-the-id-here>" \
-u "admin:xxxx xxxx xxxx xxxx xxxx xxxx" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

If step 2 returns a tools list, the server is fine. Your client is the problem.

The plugin ships a Node.js stdio↔HTTP proxy that handles session lifecycle, auth, and JSON-RPC framing for clients that only speak stdio. The proxy runs as a local subprocess on the machine running your MCP client. For a remote WordPress site it does not, and cannot, run from the copy inside wp-content/plugins/... on the server. The simplest way to run it is the zero-install npx runner:

{
"mcpServers": {
"emcp-tools": {
"command": "npx",
"args": ["-y", "@msrbuilds/emcp-proxy@latest"],
"env": {
"WP_URL": "https://your-site.com",
"WP_USERNAME": "admin",
"WP_APP_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx",
"MCP_PROTOCOL_VERSION": "2024-11-05"
}
}
}
}

Prefer a local file copy instead of npx? Extract bin/mcp-proxy.mjs from the plugin ZIP, save it locally, and set "command": "node", "args": ["C:\\local\\path\\to\\mcp-proxy.mjs"]. See the Claude Desktop guide for both options and the MCP_PROTOCOL_VERSION note. Node 18+ required.

Symptom: WP-CLI bridge says “Command ‘mcp-adapter’ not found”

Section titled “Symptom: WP-CLI bridge says “Command ‘mcp-adapter’ not found””

The wp mcp-adapter subcommand is registered by the WordPress MCP Adapter plugin’s WP-CLI integration. It only exists when:

  • The MCP Adapter plugin is active
  • WP-CLI’s plugin discovery has loaded that plugin

Test:

Terminal window
wp plugin list --path=/path/to/wordpress | grep mcp

If the MCP Adapter doesn’t show as active, activate it. If it does but wp mcp-adapter list still fails, check that the CLI command file is being loaded. Sometimes a hook ordering issue stops it from registering. Force-load test:

Terminal window
wp eval 'do_action( "cli_init" );' --path=/path/to/wordpress
wp mcp-adapter list --path=/path/to/wordpress

The wp mcp-adapter serve process should print JSON-RPC responses to stdout and stay running, waiting for more input on stdin. If it exits immediately, check for stderr output:

Terminal window
wp mcp-adapter serve --server=emcp-tools-server --user=admin --path=/path/to/wordpress 2>&1

Common errors that look like a hang but are actually instant crashes:

  • Server 'emcp-tools-server' not found: the MCP server registration failed (plugin issue, see No tools appearing)
  • User 'admin' not found: pass a valid WP username with --user
  • --path is invalid: must be the absolute path to the WordPress directory containing wp-config.php

PHP error during a tool call. Check wp-content/debug.log after enabling WP_DEBUG and WP_DEBUG_LOG:

wp-config.php
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );

The log will show the stack trace. Most common culprits:

  • A widget type that doesn’t exist (add-free-widget with a typo in widget_type)
  • Invalid settings shape: get-widget-schema first to see the expected structure
  • Elementor isn’t loaded (rare; means a plugin conflict broke its bootstrap)

Open a GitHub issue with the full stack trace if it’s not obvious.