# A Small Detail in the MCP OAuth Fix

The Python SDK update caught my attention because finishing the fix takes a little more than changing a version number.

Published: 2026-10-09

I like fixes that end with a dependency update. Change the version, run the tests, deploy, and get back to whatever was interrupted.

The recent MCP Python SDK OAuth advisory takes a little more attention. There is an update, but some applications also need a configuration change and a look at what they saved during earlier sign-ins. That is an easy detail to miss when the ticket arrives looking like routine dependency maintenance.

The part that interested me was who got to choose the destination for the client's credentials. In an agent system with several external tools, that decision deserves a closer look.

## What the advisory says

The issue affects HTTP clients using the SDK's OAuth providers with credentials for a legitimate authorization server when connecting to an untrusted MCP server. Discovery could let that server redirect credential delivery. Depending on the flow, exposed material could include a client secret, authorization code, PKCE verifier, or signed client assertion.

Affected ranges are `>=1.9.1, <1.30.0` and `>=2.0.0a1, <2.2.0`. The fixed releases are 1.30.0 and 2.2.0. This advisory excludes SDK-built MCP servers, stdio clients, and clients supplying their own tokens or headers.

For `ClientCredentialsOAuthProvider` and `PrivateKeyJWTOAuthProvider`, the fix also requires an explicit `issuer=`. Without it, server-selected authorization remains possible. In 1.30.0, omission produces a normally hidden `DeprecationWarning`. The older `RFC7523OAuthClientProvider` needs migration.

Stored registrations without an issuer remain unbound. The advisory calls for clearing old registrations so they can be recreated, or binding manually provisioned records. Possible past exposure calls for secret rotation and token revocation. [Read the SDK advisory](https://github.com/modelcontextprotocol/python-sdk/security/advisories/GHSA-qx49-fqc8-xw99).

## The tool server has its own interests

An MCP server may need to tell a client how to authenticate. That makes discovery useful. It also creates a point where information from the service influences a decision involving credentials the client already holds.

My expectation would be that the client has an independently established answer to “which authorization server owns these credentials?” before it starts discovery. A response from the service can then be checked against that answer.

Without that starting point, a familiar issuer name can feel reassuring while the surrounding metadata directs the client somewhere else. Checking the label and binding the credentials to their intended issuer need to be part of the same flow.

This is a different problem from the tool-call path in [Detecting the Confused Deputy in Azure DevOps MCP](/blog/detecting-the-confused-deputy-in-azure-devops-mcp/). There, I followed content through legitimate operations. Here, I would start earlier, with the authentication decisions made before the agent gets a useful tool response.

## Where I would look in an application

I would begin with the code that constructs the HTTP transport and its authentication provider. A search for the affected class names is a reasonable starting point, although wrappers and shared libraries may hide them.

The useful record is small: the deployed SDK version, provider class, expected issuer, source of client credentials, and location of saved registrations. I would also record which MCP servers the application is allowed to contact. A dependency list by itself cannot answer all of those questions.

The issuer should come from reviewed application configuration. If it is copied from whatever the MCP server just returned, I would want to understand how that establishes an independent expectation.

Saved registrations are the less glamorous part. They may sit in a database, a local file, or a storage implementation shared by several clients. Clearing them can interrupt sign-in, so I would work out the migration before deploying. A deliberate re-registration is easier to manage than finding out afterward that some instances kept old state while others started fresh.

This also gives the update ticket a better definition of completion. A version-based scanner may see the fixed package while application configuration still needs work. I would attach evidence of the issuer setting and registration migration to the same change.

## A test I would be comfortable running

I would use a disposable client, dummy credentials, and two local test services: an expected authorization server and a fixture MCP server. No production secret needs to be involved.

First, I would confirm that the intended discovery and authentication flow succeeds. Then I would have the fixture advertise metadata for a different issuer and check that the client rejects it before sending credential material. The test services should record receipt using harmless markers, so the result does not depend solely on an exception appearing in the client log.

I would also exercise alternate discovery and scope-error paths, and run the migration with a copy of the old registration format containing dummy values. Those are proposed acceptance tests. I have not reproduced this vulnerability here.

The question I want the test to settle is straightforward: does this deployed client keep its credentials with the authorization server we configured, even when the service it contacts supplies misleading discovery information?

## Some evidence would help later, too

For monitoring, I would record the configured issuer, discovered token-endpoint host, MCP server identity, application instance, and whether the client accepted or rejected the metadata. Raw secrets and complete assertions have no place in that record.

An unexpected destination would be worth investigating, but an allowlist needs to account for the actual identity provider setup. DNS changes, proxies, and legitimate service changes can all complicate a hostname comparison. Provider-side grant records may help if the identity platform exposes the needed detail. I would verify that coverage before promising an alert.

If possible exposure is being investigated, the inventory should make it easy to find the credential owner and the applications that share it. That is where this connects with [the evaluation credential review](/blog/your-evaluation-sandbox-holds-production-authority/): knowing where access lives makes revocation much less of a guessing exercise.

I would be happy to close this particular update after seeing three things together: the fixed SDK in the deployed application, the intended issuer in configuration, and the old registration state dealt with. The extra work is modest. It just needs to be visible in the ticket.