Remove server back-references from protocol DTO types (#1345)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> Co-authored-by: Stephen Toub <stoub@microsoft.com>
This commit is contained in:
parent
2c9bb5d368
commit
74622d0c9c
1 changed files with 195 additions and 96 deletions
|
|
@ -398,6 +398,105 @@ public class AuthorizeAttributeTests(ITestOutputHelper testOutputHelper) : Kestr
|
|||
log.Exception.Message.Contains("Ensure that AddAuthorizationFilters() is called"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListTools_WithHandlerAndNullCollection_AllToolsVisible()
|
||||
{
|
||||
// When ToolCollection is null (custom handler only), the auth filter can't look up
|
||||
// primitives in the collection and should not filter any tools.
|
||||
await using var app = await StartServerWithAuth(builder =>
|
||||
builder.WithListToolsHandler(static (_, _) => ValueTask.FromResult(new ListToolsResult
|
||||
{
|
||||
Tools = [new Tool { Name = "custom_tool" }]
|
||||
})));
|
||||
|
||||
var client = await ConnectAsync();
|
||||
var tools = await client.ListToolsAsync(cancellationToken: TestContext.Current.CancellationToken);
|
||||
|
||||
// Tool from custom handler (not in ToolCollection) should be visible even to anonymous users
|
||||
Assert.Single(tools);
|
||||
Assert.Equal("custom_tool", tools[0].Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListTools_WithMixedCollectionAndHandler_HandlerToolsNotFiltered()
|
||||
{
|
||||
// Tools in the ToolCollection are filtered based on auth metadata.
|
||||
// Tools returned only from a custom handler (not in ToolCollection) are not filtered.
|
||||
await using var app = await StartServerWithAuth(builder =>
|
||||
{
|
||||
builder.WithTools<AuthorizationTestTools>();
|
||||
builder.WithListToolsHandler(static (_, _) => ValueTask.FromResult(new ListToolsResult
|
||||
{
|
||||
Tools = [new Tool { Name = "handler_tool" }]
|
||||
}));
|
||||
});
|
||||
|
||||
var client = await ConnectAsync();
|
||||
var tools = await client.ListToolsAsync(cancellationToken: TestContext.Current.CancellationToken);
|
||||
|
||||
// Anonymous user: anonymous_tool from collection + handler_tool (not in collection, so not filtered)
|
||||
Assert.Equal(2, tools.Count);
|
||||
var toolNames = tools.Select(t => t.Name).OrderBy(n => n).ToList();
|
||||
Assert.Equal(["anonymous_tool", "handler_tool"], toolNames);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListPrompts_WithHandlerAndNullCollection_AllPromptsVisible()
|
||||
{
|
||||
// When PromptCollection is null (custom handler only), the auth filter can't look up
|
||||
// primitives in the collection and should not filter any prompts.
|
||||
await using var app = await StartServerWithAuth(builder =>
|
||||
builder.WithListPromptsHandler(static (_, _) => ValueTask.FromResult(new ListPromptsResult
|
||||
{
|
||||
Prompts = [new Prompt { Name = "custom_prompt" }]
|
||||
})));
|
||||
|
||||
var client = await ConnectAsync();
|
||||
var prompts = await client.ListPromptsAsync(cancellationToken: TestContext.Current.CancellationToken);
|
||||
|
||||
// Prompt from custom handler (not in PromptCollection) should be visible even to anonymous users
|
||||
Assert.Single(prompts);
|
||||
Assert.Equal("custom_prompt", prompts[0].Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListResources_WithHandlerAndNullCollection_AllResourcesVisible()
|
||||
{
|
||||
// When ResourceCollection is null (custom handler only), the auth filter can't look up
|
||||
// primitives in the collection and should not filter any resources.
|
||||
await using var app = await StartServerWithAuth(builder =>
|
||||
builder.WithListResourcesHandler(static (_, _) => ValueTask.FromResult(new ListResourcesResult
|
||||
{
|
||||
Resources = [new Resource { Name = "custom_resource", Uri = "resource://custom" }]
|
||||
})));
|
||||
|
||||
var client = await ConnectAsync();
|
||||
var resources = await client.ListResourcesAsync(cancellationToken: TestContext.Current.CancellationToken);
|
||||
|
||||
// Resource from custom handler (not in ResourceCollection) should be visible even to anonymous users
|
||||
Assert.Single(resources);
|
||||
Assert.Equal("resource://custom", resources[0].Uri);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ListResourceTemplates_WithHandlerAndNullCollection_AllResourceTemplatesVisible()
|
||||
{
|
||||
// When ResourceCollection is null (custom handler only), the auth filter can't look up
|
||||
// primitives in the collection and should not filter any resource templates.
|
||||
await using var app = await StartServerWithAuth(builder =>
|
||||
builder.WithListResourceTemplatesHandler(static (_, _) => ValueTask.FromResult(new ListResourceTemplatesResult
|
||||
{
|
||||
ResourceTemplates = [new ResourceTemplate { Name = "custom_template", UriTemplate = "resource://custom/{id}" }]
|
||||
})));
|
||||
|
||||
var client = await ConnectAsync();
|
||||
var templates = await client.ListResourceTemplatesAsync(cancellationToken: TestContext.Current.CancellationToken);
|
||||
|
||||
// Template from custom handler (not in ResourceCollection) should be visible even to anonymous users
|
||||
Assert.Single(templates);
|
||||
Assert.Equal("resource://custom/{id}", templates[0].UriTemplate);
|
||||
}
|
||||
|
||||
private async Task<WebApplication> StartServerWithAuth(Action<IMcpServerBuilder> configure, string? userName = null, params string[] roles)
|
||||
{
|
||||
var mcpServerBuilder = Builder.Services.AddMcpServer().WithHttpTransport().AddAuthorizationFilters();
|
||||
|
|
|
|||
Loading…
Reference in a new issue