Skip to content

Conversation

@bbartels
Copy link

Summary

Add support for https+http URI scheme to enable .NET Aspire service discovery

Motivation and Context

When using .NET Aspire service discovery, endpoints are configured with composite schemes like https+http://servicename. The current validation rejects these URLs because it only allows exact http or https schemes. This change allows the service discovery scheme pattern so the MCP client can work seamlessly with Aspire-based applications.

How Has This Been Tested?

Tested locally with a .NET Aspire application using service discovery to connect to an MCP gateway. Verified that:

  • Standard http:// and https:// URLs continue to work
  • https+http://servicename URLs are now accepted
  • Invalid schemes are still rejected

Breaking Changes

None. This is an additive change that allows an additional valid scheme pattern.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

.NET Aspire uses composite URI schemes for service discovery:

  • https+http://service means "resolve via service discovery, connect using HTTPS"
  • The +http suffix indicates looking up HTTP endpoints in the configuration

Reference: https://learn.microsoft.com/en-us/dotnet/aspire/service-discovery/overview


if (metadata.AuthorizationEndpoint.Scheme != Uri.UriSchemeHttp &&
metadata.AuthorizationEndpoint.Scheme != Uri.UriSchemeHttps)
if (metadata.AuthorizationEndpoint.Scheme is not (Uri.UriSchemeHttp or Uri.UriSchemeHttps or $"{Uri.UriSchemeHttps}+{Uri.UriSchemeHttp}"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@halter73, is this something we want to do?

If we do decide to take this, @bbartels each of these string interpolations is allocating a new string; it should not do that.

Also, @halter73, these checks are being done case-sensitive; shouldn't schema comparisons be case-insensitive?

Copy link
Author

@bbartels bbartels Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought given its interpolating constants its done at compile time, but happy to change it

EDIT: Looks like they are static readonly fields afterall, wouldn't have worked in pattern matching anyways. I'll change it!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 6679816

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't schema comparisons be case-insensitive?

Yes. That's what we do just above in IsValidClientMetadataDocumentUri, but we missed it here. We could also fix this in the HttpClientTransportOptions.Endpoint setter and in the ProtectedMcpClient sample's OpenBrowser method.

is this something we want to do?

I don't think so, but I need to understand the scenario better. This reminds me of #562 which made HttpClientTransportOptions.Endpoint optional to help with Aspire scenarios. @bbartels do you know why you ran into this issue with ClientOAuthProvider before the HttpClientTransportOptions issue? Did you just pick a specific scheme for the MCP server?

Also, are you seeing .well-known/oauth-authorization-server or .well-known/openid-configuration returning "authorization_endpoint": "http+https://... in the AuthorizationServerMetadata JSON response from the authorization server?

If so, what OAuth server are you using? Keycloak? I suspect most other OAuth clients will also fail unless the OAuth server responds with a real URL, so it might make more sense to have the OAuth server pick a specific scheme to respond with. According to the spec, it must be HTTPS anyway.

Communication Security

Implementations MUST follow OAuth 2.1 Section 1.5 "Communication Security".

Specifically:

  1. All authorization server endpoints MUST be served over HTTPS.
  2. All redirect URIs MUST be either localhost or use HTTPS.

https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization#communication-security

That said, it appears to me neither they TypeScript nor Python MCP SDKs enforce this. The TS SDK just disallows "javascript:", "vbscript:" and "data:" schemes (modelcontextprotocol/typescript-sdk#877). I suppose the argument is that it's on the AS to enforce communication security, and the SDKs are just trying to avoid a not-fully-trusted OAuth server from doing XSS-style attacks, since this URL is intended to be open in a browser. It's a little unusual because MCP client SDKs are designed to work with untrusted OAuth servers whereas most OAuth client SDKs are designed to work with a single OAuth server you trust.

If we do start stricter enforcement on the client and only allow HTTPS despite other SDK being more lax, we'd probably want some sort of explicit opt-out similar to ASP.NET Core's OpenIdConnectOptions.RequireHttpsMetadata and IdentityModel's HttpDocumentRetriever.RequireHttps which is a bigger change that doesn't need to be part of the PR.

Copy link
Author

@bbartels bbartels Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, apologies, i should have clarified I am mainly interested in the change to HttpClientTransportOptions i just added the check in ClientOAuthProvider for parity.
Happy to revert the ClientOAuthProvider change, our use-case is for an aggregation proxy for multiple MCPs, some of which support TLS termination, some don't. So our aspire apphost has a mixed set of http/https configurations for local development. We currently configure everything to be http as we cannot set https+http in the SDK.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants