Skip to content

Workarounds Required to Support Microsoft Azure as Auth Server #862

Closed

Description

@2underscores

Support Azure for Enterprise Adoption

  • With MCP SDK, Azure AD cannot be used as the Authorisation Server (AS) as Azure:
    • Does not advertise PKCE in AS metadata
    • Uses scope param instead of RFC 8707's resource param
  • MCP SDK should support Azure as an AS, as Azure is extremely commonly used, particularly in enterprise.

PKCE Not Advertised

scope instead of resource

  • RFC 8707 - Resource Indicators for OAuth 2.0 is an optional extension to OAuth, that MCP has as mandatory.
  • It introduces the resource param that indicates which protected resource the client is requesting access to.
    • This is included in /authorize and /token endpoints, and in the JWT's aud claim.
  • Azure v2 endpoints do not implement RFC 8707. They implement a very similar scope parameter in place of the resource param
    • scope is a superset, and includes both the "resource" access is being requested to, and the actions ("scopes") to perform on it.
  • Azure AS will fail if resource is provided (i.e. It does not ignore/silently drop it)
  • To support Azure, conditional logic is needed to provide scope in place of resource with the required minor change to value.

Other Related Azure Issues

This commit has one implementation of the compatibility changes needed to support Azure as AS.

Activity

  1. added
    enhancementRequest for a new feature that's not currently supported
    on Aug 11, 2025
  2. changed the title [-]Workarounds to Support Microsoft Azure as Auth Server[/-] [+]Workarounds Required to Support Microsoft Azure as Auth Server[/+] on Aug 11, 2025
  3. pcarleton commented on Aug 12, 2025

    @pcarleton
    Member

    One solution in the SDK's is to make auth more pluggable, so it's easy to override the behaviors needed to handle these quirks without the SDK having to consider every single one. there's this PR in progress to work on that: #485

    that means if a developer has a client they want to work with an AS that is doing something unusual, they can easily swap out the auth impl to make it easier.

    the downside of that approach, which becomes clear with inspector, is that if you have a client that's expected to be generic and connect to everything, you need the "every oddball AS special case" implementation.

    I'd prefer we not litter the SDK with a bunch of vendor specific carve-outs, and also don't want to litter Inspector with it. one compromise would be to have an "advanced" flow in inspector where you can more easily directly manipulate all the params/headers.

    on the particular issue regarding resource vs. scope, there's a conversation about scope here: modelcontextprotocol/modelcontextprotocol#835 i think we should probably just solve this one that way.

    going to close this one for now

  4. 2underscores commented on Aug 12, 2025

    @2underscores
    Author

    I'd prefer we not litter the SDK with a bunch of vendor specific carve-outs

    Yeah very understandable, it's pretty icky code. We'll continue maintaining our fork with this for now, but hoping for something in the future to standardise this.

    the downside of that approach, which becomes clear with inspector, is that if you have a client that's expected to be generic and connect to everything, you need the "every oddball AS special case" implementation.

    Generic client fits our use case sadly, and IMO is what a lot of MCP clients will do (like the LSP analogy for editors and languages, MCP enables that interoperability and clients will connect to a variety of MCP servers).

    For future reference on our use case (i think it's representative of a lot of enterprise MCP usage) - some of our MCPs use Azure as both the AS and IdP for authentication, and some use a vendor's AS, with IdP federation to our Azure (where the vendors AS is spec compliant, this SDK works for us).

    IMO Azure (and maybe 0-3 others) are large enough, that where spec break is minor, carve outs for them specifically may improve standardisation by making a single SDK (this one) more broadly adopted rather than forcing forks if the big AS don't change. For reasons here, I don't think Azure is going to change anytime soon on these ones.

    Thanks very much for reviewing and redirecting to the WIP links!

  5. kamranayub commented on Oct 24, 2025

    @kamranayub

    I'm going to chime in with a +1 to @2underscores use case. I'm actually building a course focused on enterprise use cases, and using Entra ID for passwordless identities. It's slick -- except for this wrinkle with Inspector. Throughout the entire course, I can teach people how it all works using the Inspector as a client... except when it comes to this. So I'll probably call out this as an issue and use Jeremy's fork for now. I don't know how the team wants to handle this formally, but I think it makes sense that Inspector should work with a major auth provider like Entra IMHO (or maybe just offer a way to install an auth plugin to make it work, which it sounds like you're thinking about).

    I mentioned this in another comment (modelcontextprotocol/csharp-sdk#730 (comment)), but there does seem to be a workaround that is compatible with MCP Inspector. It requires a lot of heavy lifting in Azure API Management: https://den.dev/blog/remote-mcp-server/#prerequisites

  6. kamranayub commented on Oct 26, 2025

    @kamranayub

    Just a note to add to this: Claude's beta Remote MCP support ALSO has these compatibility issues 😞 Obviously we can't work around it manually or patch it, so I opened a support ticket on it, but I fear this is going to be a wider problem with any MCP client + Entra ID (vanilla). The only workaround I see (but haven't tested) is to basically front it with APIM and custom logic. FWIW, I think the Entra team should be the ones to fix this all on their end, it shouldn't be up to MCP clients/hosts/vendors to workaround but that's probably pie-in-the-sky thinking. VS Code has workarounds for all this and so everything "just works" there.

  7. kamranayub commented on Dec 19, 2025

    @kamranayub

    Revisiting this after a couple months now, and after the latest spec drop.

    AFAIK, the "state of the state" on Azure as an AS is:

    1. PKCE S256 handling should be fixed, at least in the SDK (Azure OIDC discovery metadata missing code_challenge_methods_supported breaks S256 PKCE validation #832)
    2. Auth spec has been updated for scope (SEP-835: Update authorization spec with default scopes definition modelcontextprotocol#835)
    3. Spec has been updated to support OIDC metadata (feat: enhance auth server discovery with OAuth2 and OpenID metadata support modelcontextprotocol#797)

    As far as the SDK goes, that means that static client registration should work without any workarounds.

    As far as the Inspector goes, I haven't tested 0.18.0 yet, but I am not positive the same changes have been reflected there. I still see resource being included and I don't see the same S256 handling as the SDK. I have to do some further testing but if that's the case, IMHO the Inspector should be updated to reflect the spec updates.

  8. kamranayub commented on Dec 19, 2025

    @kamranayub

    Alright, today I took a look more at how this is working with MCP Inspector 0.18.0 and C# SDK.

    SEP-835: Scope in WWW-Authenticate

    First, the C# SDK hasn't yet implemented the scope parameter support for WWW-Authenticate (modelcontextprotocol/csharp-sdk#907).

    However, I have a custom patched McpAuthenticationHandler that adds support for it:

    Image

    Despite this, the MCP inspector still appends resource even though scope is explicitly provided in the WWW-Authenticate.

    Image

    SEP-835

    When implementing authorization flows, MCP clients SHOULD follow the principle of least privilege by requesting only the scopes necessary for their intended operations. During the initial authorization handshake, MCP clients SHOULD follow this priority order for scope selection:

    1. Use scope parameter from the initial WWW-Authenticate header in the 401 response, if provided
    2. If scope is not available, use all scopes defined in scopes_supported from the Protected Resource Metadata document, omitting the scope parameter if scopes_supported is undefined.

    Since resource is required for PRM, the Inspector should likely be updated to not pass resource if scope is provided:

    https://github.com/modelcontextprotocol/inspector/blame/1977e2a597cd95bb8df6efef8bedee60876a289b/client/src/lib/oauth-state-machine.ts#L136C21-L136C56

    PKCE Handling

    This is now handled correctly, I don't receive an error in the flow anymore.

    Client Registration (CIMD)

    As far as DCR is concerned, Entra ID won't/doesn't support that, but it also doesn't seem to support the new CIMD either, so static pre-registration is the only option still there out-of-the-box.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementRequest for a new feature that's not currently supported

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions