From ed408c2ffb2b0ff8623113dc136364949ce243d6 Mon Sep 17 00:00:00 2001 From: Benjamin Bartels Date: Tue, 27 Jan 2026 21:24:39 +0000 Subject: [PATCH 1/4] Support https+http scheme for .NET Aspire service discovery --- .../Client/HttpClientTransportOptions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs b/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs index 73eaae700..999493052 100644 --- a/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs +++ b/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs @@ -25,7 +25,9 @@ public required Uri Endpoint { throw new ArgumentException("Endpoint must be an absolute URI.", nameof(value)); } - if (value.Scheme != Uri.UriSchemeHttp && value.Scheme != Uri.UriSchemeHttps) + if (value.Scheme != Uri.UriSchemeHttp && + value.Scheme != Uri.UriSchemeHttps && + value.Scheme != $"{Uri.UriSchemeHttps}+{Uri.UriSchemeHttp}") { throw new ArgumentException("Endpoint must use HTTP or HTTPS scheme.", nameof(value)); } From e8ae0ac401a30dabe6a3e6dedd142bb1be53bdd2 Mon Sep 17 00:00:00 2001 From: Benjamin Bartels Date: Tue, 27 Jan 2026 21:30:41 +0000 Subject: [PATCH 2/4] Update HttpClientTransportOptions.cs --- .../Client/HttpClientTransportOptions.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs b/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs index 999493052..7b5cf42c5 100644 --- a/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs +++ b/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs @@ -25,9 +25,7 @@ public required Uri Endpoint { throw new ArgumentException("Endpoint must be an absolute URI.", nameof(value)); } - if (value.Scheme != Uri.UriSchemeHttp && - value.Scheme != Uri.UriSchemeHttps && - value.Scheme != $"{Uri.UriSchemeHttps}+{Uri.UriSchemeHttp}") + if (value.Scheme is not (Uri.UriSchemeHttp or Uri.UriSchemeHttps or $"{Uri.UriSchemeHttps}+{Uri.UriSchemeHttp}")) { throw new ArgumentException("Endpoint must use HTTP or HTTPS scheme.", nameof(value)); } From e11e98f5fa84bf500dd4a7dcb371033486cc25d6 Mon Sep 17 00:00:00 2001 From: Benjamin Bartels Date: Tue, 27 Jan 2026 21:34:41 +0000 Subject: [PATCH 3/4] Refactor authorization endpoint scheme check --- .../Authentication/ClientOAuthProvider.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs b/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs index 75126556b..4a23d46cb 100644 --- a/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs +++ b/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs @@ -342,8 +342,7 @@ private async Task GetAuthServerMetadataAsync(Uri a ThrowFailedToHandleUnauthorizedResponse($"No authorization_endpoint was provided via '{wellKnownEndpoint}'."); } - 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}")) { ThrowFailedToHandleUnauthorizedResponse($"AuthorizationEndpoint must use HTTP or HTTPS. '{metadata.AuthorizationEndpoint}' does not meet this requirement."); } From 66798162346a45a8da7525656484e17d6468cf4a Mon Sep 17 00:00:00 2001 From: bbartels Date: Wed, 28 Jan 2026 00:08:13 +0000 Subject: [PATCH 4/4] Addresses PR feedback --- .../Authentication/ClientOAuthProvider.cs | 9 +++++++-- .../Client/HttpClientTransportOptions.cs | 10 ++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs b/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs index 4a23d46cb..312814784 100644 --- a/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs +++ b/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs @@ -24,6 +24,7 @@ internal sealed partial class ClientOAuthProvider : McpHttpClient /// private const string BearerScheme = "Bearer"; private const string ProtectedResourceMetadataWellKnownPath = "/.well-known/oauth-protected-resource"; + private static readonly string HttpsPlusHttpScheme = $"{Uri.UriSchemeHttps}+{Uri.UriSchemeHttp}"; private readonly Uri _serverUrl; private readonly Uri _redirectUri; @@ -342,9 +343,13 @@ private async Task GetAuthServerMetadataAsync(Uri a ThrowFailedToHandleUnauthorizedResponse($"No authorization_endpoint was provided via '{wellKnownEndpoint}'."); } - if (metadata.AuthorizationEndpoint.Scheme is not (Uri.UriSchemeHttp or Uri.UriSchemeHttps or $"{Uri.UriSchemeHttps}+{Uri.UriSchemeHttp}")) + string authorizationEndpointScheme = metadata.AuthorizationEndpoint.Scheme; + + if (authorizationEndpointScheme != Uri.UriSchemeHttp && + authorizationEndpointScheme != Uri.UriSchemeHttps && + authorizationEndpointScheme != HttpsPlusHttpScheme) { - ThrowFailedToHandleUnauthorizedResponse($"AuthorizationEndpoint must use HTTP or HTTPS. '{metadata.AuthorizationEndpoint}' does not meet this requirement."); + ThrowFailedToHandleUnauthorizedResponse($"AuthorizationEndpoint must use HTTP, HTTPS, or HTTPS+HTTP. '{metadata.AuthorizationEndpoint}' does not meet this requirement."); } metadata.ResponseTypesSupported ??= ["code"]; diff --git a/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs b/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs index 7b5cf42c5..2168310a5 100644 --- a/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs +++ b/src/ModelContextProtocol.Core/Client/HttpClientTransportOptions.cs @@ -7,6 +7,8 @@ namespace ModelContextProtocol.Client; /// public sealed class HttpClientTransportOptions { + private static readonly string HttpsPlusHttpScheme = $"{Uri.UriSchemeHttps}+{Uri.UriSchemeHttp}"; + /// /// Gets or sets the base address of the server for SSE connections. /// @@ -25,9 +27,13 @@ public required Uri Endpoint { throw new ArgumentException("Endpoint must be an absolute URI.", nameof(value)); } - if (value.Scheme is not (Uri.UriSchemeHttp or Uri.UriSchemeHttps or $"{Uri.UriSchemeHttps}+{Uri.UriSchemeHttp}")) + string scheme = value.Scheme; + + if (scheme != Uri.UriSchemeHttp && + scheme != Uri.UriSchemeHttps && + scheme != HttpsPlusHttpScheme) { - throw new ArgumentException("Endpoint must use HTTP or HTTPS scheme.", nameof(value)); + throw new ArgumentException("Endpoint must use HTTP, HTTPS, or HTTPS+HTTP scheme.", nameof(value)); } field = value;