Skip to content

Auth errors (401 / 403)

The most common error. WordPress rejected your credentials. Walk through these:

  1. WordPress admin → Users → Profile → scroll to Application Passwords
  2. The password you created must be active (no revoked indicator)
  3. Application Passwords are formatted as xxxx xxxx xxxx xxxx xxxx xxxx, four-character chunks separated by single spaces. Don’t strip the spaces.
  4. The user the password belongs to must have at least edit_posts. Editor / Author / Administrator roles all qualify. Subscriber does not.

The Authorization header value should be Basic <base64-of-username:password>. Generate:

Terminal window
echo -n "admin:xxxx xxxx xxxx xxxx xxxx xxxx" | base64

Common mistakes:

  • Trailing newline. Use echo -n (no newline). On Windows PowerShell: [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("admin:xxxx xxxx ..."))
  • URL-encoding the colon. Don’t. It’s part of the credential string, not a URL part.
  • Wrapping the base64 in quotes inside the JSON. Quotes are JSON syntax; they shouldn’t be inside the header value.

The header should look exactly like:

Authorization: Basic YWRtaW46eHh4eCB4eHh4IHh4eHggeHh4eCB4eHh4IHh4eHg=
Terminal window
curl -i https://your-site.test/wp-json/wp/v2/users/me \
-u "admin:xxxx xxxx xxxx xxxx xxxx xxxx"

If this returns a 401, your credentials are wrong (or WordPress isn’t accepting App Passwords on this install). If it returns a 200 with your user data, credentials work. The MCP endpoint should accept them too.

Some security plugins (Wordfence, iThemes) disable Application Passwords by default. Check Settings → General or your security plugin’s settings.

You can also test programmatically: var_dump( wp_is_application_passwords_available() ) in a snippet. Returns true if available.

The credentials worked but the user doesn’t have permission for the specific tool. EMCP Tools enforces capabilities per tool:

  • Read tools require edit_posts
  • Write tools require edit_posts + ownership check on the target post
  • Global settings require manage_options
  • Delete operations require delete_posts
  • Code-injection tools require unfiltered_html

Use an Administrator account during initial testing. Subscriber / Customer accounts will hit 403 on almost everything.

If you’re using OAuth sign-in (approving a browser prompt instead of an Application Password) and the connection never completes:

No browser prompt / “discovery failed” / 404

Section titled “No browser prompt / “discovery failed” / 404”

The client discovers the server by requesting /.well-known/oauth-protected-resource (RFC 9728). Two common causes:

  • Not HTTPS. OAuth is only offered on https:// sites. On HTTP, use an Application Password.

  • Host blocks /.well-known/. Some managed hosts and nginx/openresty defaults deny every /.well-known/ path except ACME challenges, at the web-server layer, before WordPress runs. Test it:

    Terminal window
    curl -i https://your-site.com/.well-known/oauth-protected-resource/wp-json/mcp/emcp-tools-server

    A 200 with JSON means discovery works. A 403/404 (especially an nginx/hosting page, not WordPress) means the host is blocking it. Ask your host to allow /.well-known/ requests, or use an Application Password instead, it doesn’t rely on discovery.

  • Cloudflare (or another CDN/WAF) is blocking the client, not your browser. If your client reports “Couldn’t register”, or the connection just never completes, the most common cause is a CDN or security layer in front of the site — most often Cloudflare’s bot-fight mode — blocking the client’s server-side calls to the discovery and dynamic-registration endpoints. Your own browser reaches the site fine (it isn’t flagged as a bot), which is why this one is confusing: everything looks fine when you check it yourself.

    Fix it by allow-listing these exact paths in the CDN/WAF:

    /.well-known/oauth-authorization-server
    /.well-known/oauth-protected-resource
    /wp-json/emcp-tools/oauth/*
    /wp-json/mcp/emcp-tools-server

    If you can’t change the CDN/WAF config, fall back to an Application Password instead — pick it under “Choose your authentication method” on EMCP Tools → Connection.

”Invalid client or redirect URI” / the sign-in prompt keeps reopening

Section titled “”Invalid client or redirect URI” / the sign-in prompt keeps reopening”

If a connected client (Claude Desktop, ChatGPT, or another MCP client) periodically pops open a sign-in page on its own that fails with “Invalid client or redirect URI for this connection request”, and it never reconnects no matter how many times you approve it — this was a real bug, fixed in v3.12.3. A cleanup routine deleted any client registration older than a day with no active tokens, intending to prune abandoned sign-in attempts, but a client whose tokens had simply lapsed (a 30-day-idle refresh token, or anything else that cleared them) also has no tokens — so its registration was deleted while the app still had it saved, and every reconnect attempt failed against a registration the site had already thrown away.

Fix: update to v3.12.3 or later. A client that has completed sign-in at least once is now kept permanently; only registrations that never completed sign-in are cleaned up, and this applies automatically to connections that already existed before you update. If you still hit this after updating, remove the connector from your AI client and add it again to start a fresh registration — the error page itself now says the same thing.

Section titled “”Only administrators can approve” / consent denied”

The consent screen refuses non-admin users. Sign in to WordPress as an administrator in the same browser before approving.

If EMCP Tools → Connection doesn’t offer OAuth at all, the site isn’t on HTTPS (the only requirement to enable it). Application Passwords remain available regardless.

WordPress’s MCP Adapter requires the Mcp-Session-Id header on every request after the initial initialize call. The session ID is in the response headers of initialize. Subsequent requests must include it.

If you’re testing manually with curl:

  1. Call initialize. Read the Mcp-Session-Id response header
  2. Include that exact header value on every subsequent request (tools/list, tools/call, etc.)

Most MCP clients handle this automatically. For clients that don’t, the Node.js proxy handles it. Run it with npx -y @msrbuilds/emcp-proxy@latest (no local file to maintain).

The REST endpoint isn’t designed to be called from browser JavaScript directly. It requires either the application password (server-side) or a logged-in nonce (browser-side via wp_localize_script). If you’re getting CORS errors, you’re probably calling it from the wrong context.

For programmatic browser access, the WordPress REST API’s nonce auth is the right path, but no MCP client does this. They all run server-side or as native apps with proper credential handling.