AIARTICLE

MCP servers in production need to migrate to OAuth Resource Servers under the June 2025 spec

Anyone still using a static API key risks becoming incompatible with MCP clients that already follow the 2025-06-18 revision of the specification.

MCP servers in production need to migrate to OAuth Resource Servers under the June 2025 spec
Image: Alan Andrade

The 2025-06-18 revision of the Model Context Protocol turned every MCP server into an OAuth Resource Server. Anyone still using a static API key risks becoming incompatible with MCP clients that already follow this revision of the specification.

If your company's MCP server (Model Context Protocol) still authenticates clients with a fixed key in a custom header, it is running against a version of the specification that was superseded more than a year ago. The protocol's official changelog, published for the 2025-06-18 revision, formalized an authorization model that classifies MCP servers as OAuth Resource Servers and changes how MCP clients and specification-compliant agents negotiate access to an MCP server.

Anyone who deployed an MCP server in 2024 or early 2025, before this revision, likely implemented authentication on their own: a static token, an API key in the Authorization header, or not even that. The June 2025 revision formalized a specific authorization model, and that has concrete implications for anyone who already has a service running.

What the Changelog Actually Changed

The source document lists this change as the third item under "major changes": classifying MCP servers as OAuth Resource Servers, with protected resource metadata to point to the corresponding Authorization Server.

The 'Major changes' section of the MCP changelog lists the changes in the version, including the classification of MCP servers as OAuth Resource Servers
The 'Major changes' section of the MCP changelog lists the changes in the version, including the classification of MCP servers as OAuth Resource Servers. Reprodução: modelcontextprotocol.io.

Classify MCP servers as OAuth Resource Servers, adding protected resource metadata to discover the corresponding Authorization server.

Model Context Protocol, 2025-06-18 specification

In practice, this means the MCP server is no longer responsible for validating credentials on its own. It delegates that function to an external Authorization Server (which could be Auth0, Okta, Keycloak, or a custom provider) and only needs to announce where that server is.

The changelog also brings two changes that catch out anyone who only skimmed the migration headline:

  • Mandatory Resource Indicators (RFC 8707): MCP clients now need to declare which server the token was requested for, preventing a token issued for one service from being reused on another (the classic "confused deputy" attack).
  • Mandatory MCP-Protocol-Version header: every HTTP request after the initial handshake must declare the negotiated protocol version, not just the first one.

Why the Old Auth Model Becomes a Risk

An MCP server with a fixed API key works fine as long as only one trusted client accesses it. The problem appears when the same token circulates among multiple agents, third-party integrations, or automated pipelines: there is no way to revoke a specific client's access without breaking all the others, and there is no validation that the token was issued for that server.

With Resource Indicators, the flow requires the token to carry an audience claim (aud) matching the requested resource. A server that doesn't validate this claim remains vulnerable even after "migrating" by simply switching the transport to HTTPS with a Bearer token: the point of the change is validation, not just the header format.

Step-by-Step to Migrate an Existing MCP Server

Editor's note: the code in this section was not run in a real environment. Validate it before using it in production.

1. Map the Current Auth Flow

Before touching any code, identify where identity verification happens today: middleware that reads a custom header, an API key check against a database, or no real verification at all. This inventory determines how much of the flow can be preserved and how much needs to be replaced by a dedicated Authorization Server.

2. Expose the Protected Resource Metadata

The server needs to respond on a well-known endpoint with the data of the Authorization Server that protects the resource. A minimal example response:

json
{
  "resource": "https://mcp.suaempresa.com",
  "authorization_servers": [
    "https://auth.suaempresa.com"
  ],
  "bearer_methods_supported": ["header"]
}

This is the document an MCP client consults before starting the OAuth flow, instead of assuming the MCP server itself validates the password.

3. Validate the Resource Indicator in the Received Token

The point most people skip: receiving a valid Bearer token isn't enough, you need to confirm it was issued for this resource. An example check in Node.js, assuming a JWT with an aud claim:

javascript
function validarToken(payload, resourceEsperado) {
  const audiences = Array.isArray(payload.aud) ? payload.aud : [payload.aud];
  if (!audiences.includes(resourceEsperado)) {
    throw new Error('Token não emitido para este recurso');
  }
  return true;
}

Without this check, the server accepts a stolen or leaked token from another integration, even if the JWT's signature is valid.

4. Add the Version Header to Every Request

The spec no longer accepts MCP-Protocol-Version only in the initial handshake. Every subsequent request over HTTP needs to declare the negotiated version. A simple middleware handles this:

javascript
app.use((req, res, next) => {
  const versao = req.headers['mcp-protocol-version'];
  if (versao !== '2025-06-18') {
    return res.status(400).json({ error: 'protocol_version_mismatch' });
  }
  next();
});

5. Test Locally Before Releasing to Production

To validate the flow without depending on real infrastructure, spin up the MCP server on localhost and a test Authorization Server (Keycloak in a container, for example). Point a test MCP client at the local metadata endpoint and confirm three things: the client can discover the Authorization Server via the metadata, the authorization flow returns a token with the correct aud, and the server rejects tokens with a different audience.

What Breaks If the Server Doesn't Migrate

MCP clients that already follow the 2025-06-18 revision expect to find the Protected Resource Metadata endpoint before negotiating access. A server that doesn't expose it may simply fail the handshake silently, depending on how the client handles the absence of that metadata. More seriously: a server that accepts any Bearer token without validating the Resource Indicator is exposed to the reuse of tokens issued for other services, exactly the scenario RFC 8707 was designed to close.

The change from SHOULD to MUST in the Lifecycle Operation section reinforces this point: what used to be a best-practice recommendation became a compliance requirement. Servers that ignore this part of the spec aren't simply "outdated," they are outside the specification that modern clients assume as the standard.

When It's Not Worth Migrating Right Now

If the MCP server runs only internally, behind a VPN, with a single trusted client and no external exposure, the cost of implementing a full Authorization Server may not pay off in the short term. In that scenario, it's worth keeping an eye on the official changelog and planning the migration as part of a security hardening cycle, not as an emergency fix. The real risk appears when the server serves multiple clients or is accessed by third-party agents, in which case audience validation stops being optional.

Source 1: Model Context Protocol, Specification Changelog (2025-06-18) (https://modelcontextprotocol.io/specification/2025-06-18/changelog)

Key Changes - Model Context Protocol

Documentation Index Fetch the complete documentation index at: /llms.txt Use this file to discover all available pages before exploring further. Skip to main content This document lists changes made to the Model Context Protocol (MCP) specification since the previous revision, 2025-03-26 .

​ Major changes

Remove support for JSON-RPC batching (PR #416 )

Add support for structured tool output (PR #371 )

Classify MCP servers as OAuth Resource Servers , adding protected resource metadata to discover the corresponding Authorization server. (PR #338 )

Require MCP clients to implement Resource Indicators as described in RFC 8707 to prevent malicious servers from obtaining access tokens. (PR #734 )

Clarify security considerations and best practices in the authorization spec and in a new security best practices page .

Add support for elicitation , enabling servers to request additional information from users during interactions. (PR #382 )

Add support for resource links in tool call results. (PR #603 )

Require negotiated protocol version to be specified via MCP-Protocol-Version header in subsequent requests when using HTTP (PR #548 ).

Change SHOULD to MUST in Lifecycle Operation

​ Other schema changes

Add _meta field to additional interface types (PR #710 ), and specify proper usage .

Add context field to CompletionRequest , providing for completion requests to include previously-resolved variables (PR #598 ).

Add title field for human-friendly display names, so that name can be used as a programmatic identifier (PR #663 )

​ Full changelog For a complete list of all changes that have been made since the last protocol revision, see GitHub . Was this page helpful? Yes No Assistant Responses are generated using AI and may contain mistakes.

Translated from the Brazilian Portuguese original · Read the original

View profile →