Trango ComputeContextIQ
MCPOAuth 2.0RFC 9728RFC 9207AI agent securityMCP SDKCVE-2026-115563CVE-2026-104850

Pin the Issuer: MCP OAuth Discovery, RFC 9728, RFC 9207, and the Python and TypeScript SDK Advisories

Two MCP SDK advisories showed OAuth clients sending credentials to a server-chosen authorization server. How RFC 9728 discovery works and what clients must pin.

November 10, 2026Trango Compute Inc.

An MCP client connects to a server, gets a 401, and is told which authorization server to use. Where does that "which one" come from? From the MCP server itself.

That is by design. It is also the root of two recent security advisories: the OAuth clients in the official MCP Python and TypeScript SDKs could be steered by a malicious or compromised MCP server into sending credentials to an authorization server the server chose. This post explains the discovery flow, what the advisories say, and the checks a client has to make.

What the advisories say

Both are rated High, CVSS 7.5, and both are classified as insufficient verification of data authenticity and insufficiently protected credentials.

Python SDKTypeScript SDK
AdvisoryGHSA-qx49-fqc8-xw99GHSA-6qxp-vccf-f47h
CVECVE-2026-115563CVE-2026-104850
PublishedSep 28, 2026Sep 30, 2026
Affectedmcp 1.9.1 to before 1.30.0; 2.0.0a1 to before 2.2.0@modelcontextprotocol/sdk 1.12.0 to 1.30.1; @modelcontextprotocol/client 2.0.0 to 2.1.0 under narrower conditions
Fixed in1.30.0, 2.2.01.31.0, 2.2.0

In the Python advisory's words, the authorization server issuer was not validated on every discovery path, and stored or pre-provisioned credentials were not bound to the authorization server they belong to. A malicious server could redirect the client to a token endpoint it controls, exposing material such as the client secret, authorization code, PKCE code verifier or a signed client assertion. The TypeScript advisory describes the same class of problem: a stored refresh_token and client_secret could go to the server-chosen authorization server.

Not affected, per the advisories: MCP servers built with the SDKs, stdio clients, and clients that attach their own tokens or headers.

How MCP OAuth discovery works

The current draft of the MCP authorization specification builds on OAuth 2.1, RFC 9728 (protected resource metadata), RFC 8414 and OpenID Connect Discovery (authorization server metadata), RFC 8707 (resource indicators) and RFC 9207 (issuer identification). The flow:

  1. The client sends an MCP request without a token.
  2. The server answers 401 with a WWW-Authenticate header carrying a resource_metadata URL.
  3. The client fetches that Protected Resource Metadata document. It lists the authorization_servers for this resource.
  4. The client picks one and fetches its authorization server metadata.
  5. The client registers or uses an existing client ID, runs the authorization request with PKCE and a resource parameter, and exchanges the code for a token.

Per the draft, MCP servers MUST implement RFC 9728, and clients MUST use it for authorization server discovery. Clients MUST support both RFC 8414 and OpenID Connect discovery.

Step 3 is the part to notice. The resource server tells the client who the authorization server is. A client that trusts that answer without further checks lets any server redirect its credentials.

What the specification asks a client to pin

The draft spells out several requirements that close this gap:

  • Record the issuer first. Before redirecting the user, the client MUST record the issuer from the selected authorization server's validated metadata, and tie it to the same per-request record as the PKCE verifier. The spec notes the protection fails if the expected issuer came from an unvalidated source.
  • Validate iss on the way back. Before sending the authorization code to any token endpoint, the client MUST apply the RFC 9207 check and compare a present iss to the recorded issuer by simple string comparison, with no case folding or normalization. This applies to error responses too.
  • Send the resource parameter. Clients MUST include resource (RFC 8707) in authorization and token requests, identifying the MCP server the token is for.
  • Never forward foreign tokens. Clients MUST NOT send tokens to the MCP server other than ones issued by that server's authorization server, and servers MUST validate that a token was issued for them as audience.

The advisories read as the same lesson from the implementation side: credentials have to be bound to the issuer they were issued by, not to whichever server happens to ask.

What to do

For client operators:

  1. Upgrade to a fixed SDK version from the table above.
  2. Set the expected issuer. In Python, pass issuer= to ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider; upgrading alone does not fix those providers, and omitting it only raises a deprecation warning that Python hides by default. In TypeScript, pass expectedIssuer to the bundled providers.
  3. Clear unbound stored credentials. Registrations and tokens saved without an issuer stay unbound after the upgrade. Clear them once so the client re-registers.
  4. Rotate if exposed. If a client may have connected to an untrusted MCP server, rotate its client secret or signing key and revoke its tokens at the authorization server.
  5. Know what the fix doesn't cover. The TypeScript advisory notes that new interactive sign-ins still go to the authorization server the MCP server names, so complete them only with servers you trust.

For server operators, publish metadata that makes the client's job easy: a correct resource and authorization_servers in your protected resource metadata, a scope in the WWW-Authenticate challenge, and an authorization server that includes iss in authorization responses and advertises authorization_response_iss_parameter_supported. The draft says it expects to upgrade iss inclusion from SHOULD to MUST in a future revision.

Checking the server side

You cannot test your client SDK from the outside, but you can check what your server tells clients. The Agent Protocol Inspector runs a live MCP handshake against a URL, detects OAuth-protected servers via RFC 9728, and reports them as protected rather than missing, so you can confirm your endpoint is discoverable and refuses anonymous access. It does not exercise a client's credential handling, so treat it as a check on the server's published metadata.

Where ContextIQ fits

Which MCP servers an agent may talk to, and which authorization servers may receive its credentials, are policy decisions as much as code ones. ContextIQ Agent Data Policy is an Enterprise Preview that treats the approved model and tool endpoints as part of a data-handling decision, alongside isolation, read-only input and persistence. It is not generally available; we are working with design partners. To see whether it fits your workload, request an Enterprise Preview demo.

Try ContextIQ free

Free tools for AI engineers.

Follow Trango Compute on LinkedIn

We post updates on new tools, context engineering patterns, and LLM cost research.

Follow on LinkedIn