Skip to content

Commit dc8f3a1

Browse files
committed
Bit more cleanup here.
1 parent f699f77 commit dc8f3a1

File tree

6 files changed

+120
-59
lines changed

6 files changed

+120
-59
lines changed

src/ModelContextProtocol/Protocol/Auth/AuthorizationContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ internal class AuthorizationContext
88
/// <summary>
99
/// Gets or sets the resource metadata.
1010
/// </summary>
11-
public ResourceMetadata? ResourceMetadata { get; set; }
11+
public ProtectedResourceMetadata? ResourceMetadata { get; set; }
1212

1313
/// <summary>
1414
/// Gets or sets the authorization server metadata.

src/ModelContextProtocol/Protocol/Auth/AuthorizationService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class AuthorizationService
2626
/// </summary>
2727
/// <param name="response">The HTTP response that contains the WWW-Authenticate header.</param>
2828
/// <returns>A <see cref="Task"/> that represents the asynchronous operation. The task result contains the resource metadata if available.</returns>
29-
public static async Task<ResourceMetadata?> GetResourceMetadataFromResponseAsync(HttpResponseMessage response)
29+
public static async Task<ProtectedResourceMetadata?> GetResourceMetadataFromResponseAsync(HttpResponseMessage response)
3030
{
3131
if (response.StatusCode != HttpStatusCode.Unauthorized)
3232
{
@@ -71,7 +71,7 @@ public class AuthorizationService
7171
// Read as string first, then deserialize using source-generated serializer
7272
using var reader = new StreamReader(contentStream);
7373
var json = await reader.ReadToEndAsync();
74-
return JsonSerializer.Deserialize(json, McpJsonUtilities.JsonContext.Default.ResourceMetadata);
74+
return JsonSerializer.Deserialize(json, McpJsonUtilities.JsonContext.Default.ProtectedResourceMetadata);
7575
}
7676
catch (Exception)
7777
{

src/ModelContextProtocol/Protocol/Auth/ProtectedResourceMetadata.cs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ public class ProtectedResourceMetadata
1717
/// Gets or sets the resource identifier URI.
1818
/// </summary>
1919
[JsonPropertyName("resource")]
20-
public required string Resource { get; set; }
20+
public required Uri Resource { get; set; }
2121

2222
/// <summary>
2323
/// Gets or sets the authorization servers that can be used for authentication.
2424
/// </summary>
2525
[JsonPropertyName("authorization_servers")]
26-
public required string[] AuthorizationServers { get; set; }
26+
public required Uri[] AuthorizationServers { get; set; }
2727

2828
/// <summary>
2929
/// Gets or sets the bearer token methods supported by the resource.
@@ -41,18 +41,5 @@ public class ProtectedResourceMetadata
4141
/// Gets or sets the URL to the resource documentation.
4242
/// </summary>
4343
[JsonPropertyName("resource_documentation")]
44-
public string? ResourceDocumentation { get; set; }
45-
46-
/// <summary>
47-
/// Converts this <see cref="ProtectedResourceMetadata"/> to the internal <see cref="ResourceMetadata"/> type.
48-
/// </summary>
49-
/// <returns>A <see cref="ResourceMetadata"/> instance with the same values as this instance.</returns>
50-
internal ResourceMetadata ToResourceMetadata() => new()
51-
{
52-
Resource = Resource,
53-
AuthorizationServers = AuthorizationServers,
54-
BearerMethodsSupported = BearerMethodsSupported,
55-
ScopesSupported = ScopesSupported,
56-
ResourceDocumentation = ResourceDocumentation
57-
};
44+
public Uri? ResourceDocumentation { get; set; }
5845
}

src/ModelContextProtocol/Protocol/Auth/ResourceMetadata.cs

Lines changed: 0 additions & 39 deletions
This file was deleted.

src/ModelContextProtocol/Utils/Json/McpJsonUtilities.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ internal static bool IsValidMcpToolSchema(JsonElement element)
124124
[JsonSerializable(typeof(IReadOnlyDictionary<string, object>))]
125125

126126
// Authorization-related types
127-
[JsonSerializable(typeof(Protocol.Auth.ResourceMetadata))]
128127
[JsonSerializable(typeof(Protocol.Auth.ProtectedResourceMetadata))]
129128
[JsonSerializable(typeof(Protocol.Auth.AuthorizationServerMetadata))]
130129
[JsonSerializable(typeof(Protocol.Auth.ClientMetadata))]
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// filepath: c:\Users\ddelimarsky\source\csharp-sdk\tests\ModelContextProtocol.Tests\Protocol\Auth\ProtectedResourceMetadataTests.cs
2+
using ModelContextProtocol.Protocol.Auth;
3+
using System.Text.Json;
4+
5+
namespace ModelContextProtocol.Tests.Protocol.Auth;
6+
7+
public class ProtectedResourceMetadataTests
8+
{
9+
[Fact]
10+
public void ProtectedResourceMetadata_JsonSerialization_Works()
11+
{
12+
// Arrange
13+
var metadata = new ProtectedResourceMetadata
14+
{
15+
Resource = new Uri("http://localhost:7071"),
16+
AuthorizationServers = [new Uri("https://login.microsoftonline.com/tenant/v2.0")],
17+
BearerMethodsSupported = ["header"],
18+
ScopesSupported = ["mcp.tools", "mcp.prompts"],
19+
ResourceDocumentation = new Uri("https://example.com/docs")
20+
};
21+
22+
// Act
23+
var json = JsonSerializer.Serialize(metadata);
24+
var deserialized = JsonSerializer.Deserialize<ProtectedResourceMetadata>(json);
25+
26+
// Assert
27+
Assert.NotNull(deserialized);
28+
Assert.Equal("http://localhost:7071", deserialized.Resource.ToString());
29+
Assert.Equal("https://login.microsoftonline.com/tenant/v2.0", deserialized.AuthorizationServers[0].ToString());
30+
Assert.Equal("header", deserialized.BearerMethodsSupported![0]);
31+
Assert.Equal(2, deserialized.ScopesSupported!.Length);
32+
Assert.Contains("mcp.tools", deserialized.ScopesSupported!);
33+
Assert.Contains("mcp.prompts", deserialized.ScopesSupported!);
34+
Assert.Equal("https://example.com/docs", deserialized.ResourceDocumentation!.ToString());
35+
}
36+
37+
[Fact]
38+
public void ProtectedResourceMetadata_JsonDeserialization_WorksWithStringProperties()
39+
{
40+
// Arrange
41+
var json = @"{
42+
""resource"": ""http://localhost:7071"",
43+
""authorization_servers"": [""https://login.microsoftonline.com/tenant/v2.0""],
44+
""bearer_methods_supported"": [""header""],
45+
""scopes_supported"": [""mcp.tools"", ""mcp.prompts""],
46+
""resource_documentation"": ""https://example.com/docs""
47+
}";
48+
49+
// Act
50+
var deserialized = JsonSerializer.Deserialize<ProtectedResourceMetadata>(json);
51+
52+
// Assert
53+
Assert.NotNull(deserialized);
54+
Assert.Equal("http://localhost:7071", deserialized.Resource.ToString());
55+
Assert.Equal("https://login.microsoftonline.com/tenant/v2.0", deserialized.AuthorizationServers[0].ToString());
56+
Assert.Equal("header", deserialized.BearerMethodsSupported![0]);
57+
Assert.Equal(2, deserialized.ScopesSupported!.Length);
58+
Assert.Contains("mcp.tools", deserialized.ScopesSupported!);
59+
Assert.Contains("mcp.prompts", deserialized.ScopesSupported!);
60+
Assert.Equal("https://example.com/docs", deserialized.ResourceDocumentation!.ToString());
61+
}
62+
63+
[Fact]
64+
public void ResourceMetadata_JsonSerialization_Works()
65+
{
66+
// Arrange
67+
var metadata = new ResourceMetadata
68+
{
69+
Resource = new Uri("http://localhost:7071"),
70+
AuthorizationServers = [new Uri("https://login.microsoftonline.com/tenant/v2.0")],
71+
BearerMethodsSupported = ["header"],
72+
ScopesSupported = ["mcp.tools", "mcp.prompts"],
73+
ResourceDocumentation = new Uri("https://example.com/docs")
74+
};
75+
76+
// Act
77+
var json = JsonSerializer.Serialize(metadata);
78+
var deserialized = JsonSerializer.Deserialize<ResourceMetadata>(json);
79+
80+
// Assert
81+
Assert.NotNull(deserialized);
82+
Assert.Equal("http://localhost:7071", deserialized.Resource.ToString());
83+
Assert.Equal("https://login.microsoftonline.com/tenant/v2.0", deserialized.AuthorizationServers[0].ToString());
84+
Assert.Equal("header", deserialized.BearerMethodsSupported![0]);
85+
Assert.Equal(2, deserialized.ScopesSupported!.Length);
86+
Assert.Contains("mcp.tools", deserialized.ScopesSupported!);
87+
Assert.Contains("mcp.prompts", deserialized.ScopesSupported!);
88+
Assert.Equal("https://example.com/docs", deserialized.ResourceDocumentation!.ToString());
89+
}
90+
91+
[Fact]
92+
public void ToResourceMetadata_ConversionWorks()
93+
{
94+
// Arrange
95+
var prm = new ProtectedResourceMetadata
96+
{
97+
Resource = new Uri("http://localhost:7071"),
98+
AuthorizationServers = [new Uri("https://login.microsoftonline.com/tenant/v2.0")],
99+
BearerMethodsSupported = ["header"],
100+
ScopesSupported = ["mcp.tools", "mcp.prompts"],
101+
ResourceDocumentation = new Uri("https://example.com/docs")
102+
};
103+
104+
// Act
105+
var resourceMetadata = prm.ToResourceMetadata();
106+
107+
// Assert
108+
Assert.Equal(prm.Resource, resourceMetadata.Resource);
109+
Assert.Equal(prm.AuthorizationServers, resourceMetadata.AuthorizationServers);
110+
Assert.Equal(prm.BearerMethodsSupported, resourceMetadata.BearerMethodsSupported);
111+
Assert.Equal(prm.ScopesSupported, resourceMetadata.ScopesSupported);
112+
Assert.Equal(prm.ResourceDocumentation, resourceMetadata.ResourceDocumentation);
113+
}
114+
}

0 commit comments

Comments
 (0)