How to connects ChatGPT to your WordPress site

A client of mine basically lives in ChatGPT. It’s their first tab in the morning, their last tab at night. They use it to draft emails, brainstorm content ideas, summarize reports — you name it. So it was only a matter of time before they came to me with a request that went something like: “Can I just do everything from ChatGPT? Like, pull my site analytics, see what posts are performing, maybe even draft and publish directly to WordPress — all without leaving the chat?”

Honestly, my first reaction was “yeah, probably.” MCP makes that kind of thing possible — it’s the protocol that lets AI clients talk to external tools and data sources. There’s even a WordPress MCP Adapter that handles the server side. So I started wiring it up, feeling pretty good about myself. Then I pointed ChatGPT at the endpoint and watched it immediately fall over. Turns out ChatGPT’s plugin and agent integrations require strict OAuth 2.1 — a proper authorization flow with a consent screen, a token endpoint, the whole thing. The WordPress MCP Adapter doesn’t have any of that built in. There was no authorization server. No consent flow. No token endpoint. Just… nothing.

I went looking for something ready-made that could fill the gap. Spent a couple of days on it. Not much was out there. So I built it myself.


The Problem in Plain English

The Model Context Protocol (MCP) is how AI systems talk to tools and data sources. Think of it as the glue between an AI client — say, Claude Desktop or some other agent — and a server that can actually do something useful, like reading your WordPress content or querying your database.

WordPress MCP Adapter handles the server side of that equation pretty well. You install it, configure your tools, and your WordPress site starts speaking MCP. Great.

The issue is that a lot of modern AI clients don’t just connect over a plain HTTP endpoint and call it a day. They expect OAuth 2.1. Specifically, they want to go through a proper authorization code flow — redirect to an authorization server, get the user’s consent, exchange for a token, then use that token on every subsequent request.

WordPress MCP Adapter doesn’t have that built in. So those clients just fail. Sometimes silently. Sometimes with a cryptic 401 that takes a while to trace back to the missing OAuth layer.

The gap wasn’t in WordPress. It wasn’t in the MCP Adapter. The gap was the missing authorization server sitting between them.


Why Not Just Use an External Auth Server?

That was my first instinct, honestly. Stick Keycloak or Auth0 in front of it and call it done. But that introduces a whole chain of dependencies for what should be a relatively contained setup. You’d need a separate service running, something to bridge the user identities between that service and WordPress, and then you’d still need to wire the token validation back into the MCP layer.

More importantly — WordPress already has users. It already has sessions. It already has a login page. The information an OAuth consent screen needs is already sitting right there inside `wp-login.php` and the user database. It felt wrong to route around all of that just to spin up another service.

So the idea became: turn WordPress itself into the OAuth authorization server. Let it issue tokens. Let it handle the consent screen. Keep everything self-contained.


What I Actually Built

The plugin — Simple WP MCP Adapter OAuth — wires an OAuth 2.1 authorization server directly into WordPress as a companion to the MCP Adapter plugin. Here’s what it handles:

  • Authorization endpoint with a real consent flow — when a client requests access, it goes through WordPress login (the existing wp-login.php) and then hits a consent page hosted inside WordPress admin. No external redirects.
  • Token endpoint — issues JWT access tokens after a successful authorization code exchange.
  • PKCE support (S256) — the Authorization Code flow supports PKCE, which is required for public clients under OAuth 2.1.
  • Dynamic client registration — clients can register themselves at runtime without you having to pre-configure anything. There are full CRUD endpoints for managing registrations.
  • OAuth discovery endpoint — the standard /.well-known/oauth-authorization-server metadata document, so clients can find everything they need automatically.
  • JWKS endpoint — exposes the JSON Web Key Set so clients can verify token signatures without needing out-of-band key distribution.

All of this hangs off your existing WordPress REST API under /wp-json. Once you activate the plugin, your MCP server endpoint becomes OAuth-protected, and the discovery documents point to everything a compliant client needs to negotiate access.

// The plugin hooks in automatically via mcp_adapter_default_server_config.
// But if you want to register a server explicitly with OAuthTransport:

add_action(
    'mcp_adapter_init',
    function ( $adapter ) {
        $adapter->create_server(
            'my-server',
            'my-namespace',
            'mcp',
            'My MCP Server',
            'Description',
            '1.0.0',
            array( \SimpleWpMcpAdapterOAuth\OAuthTransport::class ),
            null,
            null,
            array( 'my-namespace/some-tool' ),
            array(),
            array()
        );
    }
);

The Endpoints, Laid Out

After activation, your site exposes a handful of new REST routes under your configured namespace and server route. Here’s the shape of it:

EndpointWhat It Does
GET /wp-json/{ns}/{route}The MCP server endpoint (now OAuth-protected)
GET .../.well-known/oauth-protected-resourceProtected resource metadata
GET .../.well-known/oauth-authorization-serverAuthorization server discovery
GET .../.well-known/jwks.jsonPublic keys for token verification
POST .../tokenToken issuance
POST /registerDynamic client registration
GET|POST /wp-admin/admin-post.php?action=simple_mcp_oauth_authorizeAuthorization + consent screen

The Parts That Took Longer Than Expected

Getting the basic flow working wasn’t the hard part. The tricky bits were mostly around the spec details that easy-to-miss on a first read of RFC 6749 and the OAuth 2.1 draft.

PKCE, for example — the spec is clear enough, but implementing the S256 challenge verification in a way that’s both correct and doesn’t leak timing information requires a bit of care. PHP’s hash_equals() is your friend there, but you have to actually remember to use it.

Dynamic client registration was another one. RFC 7591 is fairly straightforward, but deciding what to store, how to rotate client secrets, and how to handle the registration access tokens that protect the management endpoints added up to more surface area than I initially planned for.

The consent screen also needed more thought than a simple “yes/no” prompt. It needs to clearly communicate what the client is asking for, who it is, and what the user is actually authorizing. Getting that right inside the constraints of wp-admin styling took a few iterations.


How to Get Started

Requirements are pretty minimal — WordPress 6.8+, PHP 7.4+, the OpenSSL extension (which most hosts have on by default), and the WordPress MCP Adapter plugin already installed and active.

To get up and running in development:

  1. Clone the repo into your wp-content/plugins/ directory.
  2. Run composer install from the plugin directory.
  3. Activate the plugin from WordPress Admin → Plugins.

That’s it. Once active, the plugin automatically registers OAuthTransport as the MCP transport by filtering mcp_adapter_default_server_config, so your existing MCP server setup gets OAuth layered on top of it without any additional configuration.

View on GitHub →


What’s Next

This is v1.1.0 at this point — stable enough for real use, but there’s more I want to do. Token refresh handling could use some polish. I want to look at scopes more carefully and see whether finer-grained permission control makes sense at the MCP tool level. There’s also the question of token introspection, which some clients expect.

If you run into issues or have ideas for what would make this more useful for your setup, the GitHub issues tab is the best place to start that conversation. Pull requests are welcome too — the plugin uses PHPCS with WordPress coding standards, so just keep an eye on that if you’re contributing code.

Mostly I hope this saves someone else the same afternoon of digging through OAuth specs that I spent. The gap was real and it was annoying — now there’s something sitting in it.

Leave a Reply

Your email address will not be published. Required fields are marked *