Skip to content

Commit cbfe8c7

Browse files
committed
Don't hard code tenant and client IDs
- General cleanup
1 parent c2a77b0 commit cbfe8c7

File tree

13 files changed

+130
-127
lines changed

13 files changed

+130
-127
lines changed

.gitignore

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,4 @@ docs/api
8080

8181
# Rider
8282
.idea/
83-
.idea_modules/
84-
85-
# Misc project metadata
86-
.specs/
83+
.idea_modules/

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
<!-- Product dependencies .NET 9 -->
2929
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
30-
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.4" />
30+
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="$(System9Version)" />
3131
<PackageVersion Include="Microsoft.IdentityModel.Tokens" Version="8.9.0" />
3232
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="$(System9Version)" />
3333
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="$(System9Version)" />

samples/ProtectedMCPClient/Program.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using ModelContextProtocol.Authentication;
22
using ModelContextProtocol.Client;
3+
using ModelContextProtocol.Protocol;
34
using System.Diagnostics;
45
using System.Net;
56
using System.Text;
@@ -15,6 +16,7 @@ static async Task Main(string[] args)
1516
Console.WriteLine();
1617

1718
var serverUrl = "http://localhost:7071/sse";
19+
var clientId = Environment.GetEnvironmentVariable("CLIENT_ID") ?? throw new Exception("The CLIENT_ID environment variable is not set.");
1820

1921
// We can customize a shared HttpClient with a custom handler if desired
2022
var sharedHandler = new SocketsHttpHandler
@@ -29,10 +31,10 @@ static async Task Main(string[] args)
2931
new Uri(serverUrl),
3032
httpClient,
3133
null, // AuthorizationHelpers will be created automatically
32-
clientId: "6ad97b5f-7a7b-413f-8603-7a3517d4adb8",
34+
clientId: clientId,
3335
clientSecret: "", // No secret needed for this client
3436
redirectUri: new Uri("http://localhost:1179/callback"),
35-
scopes: ["api://167b4284-3f92-4436-92ed-38b38f83ae08/weather.read"],
37+
scopes: [$"api://{clientId}/weather.read"],
3638
logger: null,
3739
authorizationUrlHandler: HandleAuthorizationUrlAsync
3840
);
@@ -75,7 +77,7 @@ static async Task Main(string[] args)
7577
new Dictionary<string, object?> { { "state", "WA" } }
7678
);
7779

78-
Console.WriteLine("Result: " + result.Content[0].Text);
80+
Console.WriteLine("Result: " + ((TextContentBlock)result.Content[0]).Text);
7981
Console.WriteLine();
8082
}
8183
}
@@ -102,7 +104,7 @@ static async Task Main(string[] args)
102104
/// <param name="authorizationUrl">The authorization URL to open in the browser.</param>
103105
/// <param name="redirectUri">The redirect URI where the authorization code will be sent.</param>
104106
/// <param name="cancellationToken">The cancellation token.</param>
105-
/// <returns>The authorization code extracted from the callback, or null if the operation failed.</returns>
107+
/// <returns>The authorization code extracted from the callback, or null if the operation failed.</returns>
106108
private static async Task<string?> HandleAuthorizationUrlAsync(Uri authorizationUrl, Uri redirectUri, CancellationToken cancellationToken)
107109
{
108110
Console.WriteLine("Starting OAuth authorization flow...");

samples/ProtectedMCPClient/ProtectedMCPClient.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<ProjectReference Include="..\..\src\ModelContextProtocol\ModelContextProtocol.csproj" />
11+
<ProjectReference Include="..\..\src\ModelContextProtocol.Core\ModelContextProtocol.Core.csproj" />
1212
</ItemGroup>
1313

1414
</Project>

samples/ProtectedMCPServer/Program.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
var builder = WebApplication.CreateBuilder(args);
1010

1111
var serverUrl = "http://localhost:7071/";
12-
var tenantId = "a2213e1c-e51e-4304-9a0d-effe57f31655";
12+
var tenantId = builder.Configuration["TenantId"];
13+
var clientId = builder.Configuration["ClientId"];
1314
var instance = "https://login.microsoftonline.com/";
1415

1516
builder.Services.AddAuthentication(options =>
@@ -26,7 +27,7 @@
2627
ValidateAudience = true,
2728
ValidateLifetime = true,
2829
ValidateIssuerSigningKey = true,
29-
ValidAudience = "167b4284-3f92-4436-92ed-38b38f83ae08",
30+
ValidAudience = clientId,
3031
ValidIssuer = $"{instance}{tenantId}/v2.0",
3132
NameClaimType = "name",
3233
RoleClaimType = "roles"
@@ -57,7 +58,7 @@
5758
})
5859
.AddMcp(options =>
5960
{
60-
options.ProtectedResourceMetadataProvider = context =>
61+
options.ProtectedResourceMetadataProvider = context =>
6162
{
6263
var metadata = new ProtectedResourceMetadata
6364
{
@@ -68,9 +69,9 @@
6869
};
6970

7071
metadata.ScopesSupported.AddRange([
71-
"api://167b4284-3f92-4436-92ed-38b38f83ae08/weather.read"
72+
$"api://{clientId}/weather.read"
7273
]);
73-
74+
7475
return metadata;
7576
};
7677
});
@@ -79,8 +80,8 @@
7980

8081
builder.Services.AddHttpContextAccessor();
8182
builder.Services.AddMcpServer()
82-
.WithTools<WeatherTools>()
83-
.WithHttpTransport();
83+
.WithTools<WeatherTools>()
84+
.WithHttpTransport();
8485

8586
// Configure HttpClientFactory for weather.gov API
8687
builder.Services.AddHttpClient("WeatherApi", client =>

samples/ProtectedMCPServer/ProtectedMCPServer.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
<Project Sdk="Microsoft.NET.Sdk.Web">
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
22

33
<PropertyGroup>
44
<TargetFramework>net9.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
7+
<UserSecretsId>783daef3-9c45-408d-a1d3-7caf44724f39</UserSecretsId>
78
</PropertyGroup>
89

910
<ItemGroup>
Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
namespace ModelContextProtocol.AspNetCore.Authentication
1+
namespace ModelContextProtocol.AspNetCore.Authentication;
2+
3+
/// <summary>
4+
/// Represents the authentication events for Model Context Protocol.
5+
/// </summary>
6+
public class McpAuthenticationEvents
27
{
3-
/// <summary>
4-
/// Represents the authentication events for Model Context Protocol.
5-
/// </summary>
6-
public class McpAuthenticationEvents
7-
{
8-
}
98
}

src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenticationExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ public static AuthenticationBuilder AddMcp(
1919
Action<McpAuthenticationOptions>? configureOptions = null)
2020
{
2121
return AddMcp(
22-
builder,
23-
McpAuthenticationDefaults.AuthenticationScheme,
24-
McpAuthenticationDefaults.DisplayName,
22+
builder,
23+
McpAuthenticationDefaults.AuthenticationScheme,
24+
McpAuthenticationDefaults.DisplayName,
2525
configureOptions);
2626
}
2727

src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenticationHandler.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public async Task<bool> HandleRequestAsync()
3333
{
3434
// Check if the request is for the resource metadata endpoint
3535
string requestPath = Request.Path.Value ?? string.Empty;
36-
36+
3737
string expectedMetadataPath = this.Options.ResourceMetadataUri?.ToString() ?? string.Empty;
3838
if (this.Options.ResourceMetadataUri != null && !this.Options.ResourceMetadataUri.IsAbsoluteUri)
3939
{
@@ -64,14 +64,14 @@ private string GetAbsoluteResourceMetadataUri()
6464
{
6565
var options = this.Options;
6666
var resourceMetadataUri = options.ResourceMetadataUri;
67-
67+
6868
string currentPath = resourceMetadataUri?.ToString() ?? string.Empty;
69-
69+
7070
if (resourceMetadataUri != null && resourceMetadataUri.IsAbsoluteUri)
7171
{
7272
return currentPath;
7373
}
74-
74+
7575
// For relative URIs, combine with the base URL
7676
string baseUrl = GetBaseUrl();
7777
string relativePath = resourceMetadataUri?.OriginalString.TrimStart('/') ?? string.Empty;
@@ -80,7 +80,7 @@ private string GetAbsoluteResourceMetadataUri()
8080
{
8181
throw new InvalidOperationException($"Could not create absolute URI for resource metadata. Base URL: {baseUrl}, Relative Path: {relativePath}");
8282
}
83-
83+
8484
return absoluteUri.ToString();
8585
}
8686

@@ -92,7 +92,7 @@ private Task HandleResourceMetadataRequestAsync(CancellationToken cancellationTo
9292
{
9393
var options = this.Options;
9494
var resourceMetadata = options.GetResourceMetadata(Request.HttpContext);
95-
95+
9696
// Create a copy to avoid modifying the original
9797
var metadata = new ProtectedResourceMetadata
9898
{
@@ -102,22 +102,22 @@ private Task HandleResourceMetadataRequestAsync(CancellationToken cancellationTo
102102
ScopesSupported = [.. resourceMetadata.ScopesSupported],
103103
ResourceDocumentation = resourceMetadata.ResourceDocumentation
104104
};
105-
105+
106106
Response.StatusCode = StatusCodes.Status200OK;
107107
Response.ContentType = "application/json";
108-
108+
109109
var json = JsonSerializer.Serialize(
110-
metadata,
110+
metadata,
111111
McpJsonUtilities.DefaultOptions.GetTypeInfo(typeof(ProtectedResourceMetadata)));
112-
112+
113113
return Response.WriteAsync(json, cancellationToken);
114114
}
115115

116116
/// <inheritdoc />
117117
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
118118
{
119119
// If ForwardAuthenticate is set, forward the authentication to the specified scheme
120-
if (!string.IsNullOrEmpty(Options.ForwardAuthenticate) &&
120+
if (!string.IsNullOrEmpty(Options.ForwardAuthenticate) &&
121121
Options.ForwardAuthenticate != Scheme.Name)
122122
{
123123
// Simply forward the authentication request to the specified scheme and return its result
@@ -136,14 +136,14 @@ protected override Task HandleChallengeAsync(AuthenticationProperties properties
136136
string rawPrmDocumentUri = GetAbsoluteResourceMetadataUri();
137137

138138
properties ??= new AuthenticationProperties();
139-
139+
140140
// Store the resource_metadata in properties in case other handlers need it
141141
properties.Items["resource_metadata"] = rawPrmDocumentUri;
142-
142+
143143
// Add the WWW-Authenticate header with Bearer scheme and resource metadata
144144
string headerValue = $"Bearer realm=\"{Scheme.Name}\", resource_metadata=\"{rawPrmDocumentUri}\"";
145145
Response.Headers.Append("WWW-Authenticate", headerValue);
146-
146+
147147
return base.HandleChallengeAsync(properties);
148148
}
149149
}

src/ModelContextProtocol.AspNetCore/Authentication/McpAuthenticationOptions.cs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@ namespace ModelContextProtocol.AspNetCore.Authentication;
99
/// </summary>
1010
public class McpAuthenticationOptions : AuthenticationSchemeOptions
1111
{
12-
private static readonly Uri DefaultResourceMetadataUri = new("/.well-known/oauth-protected-resource", UriKind.Relative);
13-
12+
private static readonly Uri DefaultResourceMetadataUri = new("/.well-known/oauth-protected-resource", UriKind.Relative);
13+
1414
private Func<HttpContext, ProtectedResourceMetadata>? _resourceMetadataProvider;
1515

16-
private ProtectedResourceMetadata? _resourceMetadata;
17-
16+
private ProtectedResourceMetadata? _resourceMetadata;
17+
1818
/// <summary>
1919
/// Initializes a new instance of the <see cref="McpAuthenticationOptions"/> class.
2020
/// </summary>
2121
public McpAuthenticationOptions()
2222
{
23-
base.ForwardAuthenticate = "Bearer";
23+
// "Bearer" is JwtBearerDefaults.AuthenticationScheme, but we don't have a reference to the JwtBearer package here.
24+
ForwardAuthenticate = "Bearer";
2425
ResourceMetadataUri = DefaultResourceMetadataUri;
2526
Events = new McpAuthenticationEvents();
2627
}
@@ -40,15 +41,15 @@ public McpAuthenticationOptions()
4041
/// <remarks>
4142
/// This URI will be included in the WWW-Authenticate header when a 401 response is returned.
4243
/// </remarks>
43-
public Uri ResourceMetadataUri { get; set; }
44-
44+
public Uri ResourceMetadataUri { get; set; }
45+
4546
/// <summary>
4647
/// Gets or sets the static protected resource metadata.
4748
/// </summary>
4849
/// <remarks>
4950
/// This contains the OAuth metadata for the protected resource, including authorization servers,
5051
/// supported scopes, and other information needed for clients to authenticate.
51-
/// Setting this property will automatically update the <see cref="ProtectedResourceMetadataProvider"/>
52+
/// Setting this property will automatically update the <see cref="ProtectedResourceMetadataProvider"/>
5253
/// to return this static instance.
5354
/// </remarks>
5455
/// <exception cref="ArgumentNullException">Thrown when trying to set a null value.</exception>
@@ -64,13 +65,13 @@ public ProtectedResourceMetadata ResourceMetadata
6465
{
6566
throw new ArgumentException("The Resource property of the metadata cannot be null. A valid resource URI is required.", nameof(value));
6667
}
67-
68+
6869
_resourceMetadata = value;
6970
// When static metadata is set, update the provider to use it
7071
_resourceMetadataProvider = _ => _resourceMetadata;
7172
}
72-
}
73-
73+
}
74+
7475
/// <summary>
7576
/// Gets or sets a delegate that dynamically provides resource metadata based on the HTTP context.
7677
/// </summary>
@@ -84,7 +85,7 @@ public Func<HttpContext, ProtectedResourceMetadata>? ProtectedResourceMetadataPr
8485
get => _resourceMetadataProvider;
8586
set => _resourceMetadataProvider = value;
8687
}
87-
88+
8889
/// <summary>
8990
/// Gets the resource metadata for the current request.
9091
/// </summary>
@@ -94,7 +95,7 @@ public Func<HttpContext, ProtectedResourceMetadata>? ProtectedResourceMetadataPr
9495
internal ProtectedResourceMetadata GetResourceMetadata(HttpContext context)
9596
{
9697
var provider = _resourceMetadataProvider;
97-
98+
9899
return provider != null
99100
? provider(context)
100101
: _resourceMetadata ?? throw new InvalidOperationException(

0 commit comments

Comments
 (0)