Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 96 additions & 64 deletions src/ModelContextProtocol.AspNetCore/AuthorizationFilterSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,31 +43,39 @@ public void PostConfigure(string? name, McpServerOptions options)

private void ConfigureListToolsFilter(McpServerOptions options)
{
options.Filters.Request.ListToolsFilters.Add(next => async (context, cancellationToken) =>
options.Filters.Request.ListToolsFilters.Add(next =>
{
context.Items[AuthorizationFilterInvokedKey] = true;

var result = await next(context, cancellationToken);
await FilterAuthorizedItemsAsync(
result.Tools, static tool => tool.McpServerTool,
context.User, context.Services, context);
return result;
var toolCollection = options.ToolCollection;
return async (context, cancellationToken) =>
{
context.Items[AuthorizationFilterInvokedKey] = true;

var result = await next(context, cancellationToken);
await FilterAuthorizedItemsAsync(
result.Tools, tool => toolCollection is not null && toolCollection.TryGetPrimitive(tool.Name, out var serverTool) ? serverTool : null,
context.User, context.Services, context);
return result;
};
});
}

private static void CheckListToolsFilter(McpServerOptions options)
{
options.Filters.Request.ListToolsFilters.Add(next => async (context, cancellationToken) =>
options.Filters.Request.ListToolsFilters.Add(next =>
{
var result = await next(context, cancellationToken);

if (HasAuthorizationMetadata(result.Tools.Select(static tool => tool.McpServerTool))
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
var toolCollection = options.ToolCollection;
return async (context, cancellationToken) =>
{
throw new InvalidOperationException("Authorization filter was not invoked for tools/list operation, but authorization metadata was found on the tools. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
}
var result = await next(context, cancellationToken);

if (HasAuthorizationMetadata(result.Tools.Select(tool => toolCollection is not null && toolCollection.TryGetPrimitive(tool.Name, out var serverTool) ? serverTool : null))
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
{
throw new InvalidOperationException("Authorization filter was not invoked for tools/list operation, but authorization metadata was found on the tools. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
}

return result;
return result;
};
});
}

Expand Down Expand Up @@ -103,61 +111,77 @@ private static void CheckCallToolFilter(McpServerOptions options)

private void ConfigureListResourcesFilter(McpServerOptions options)
{
options.Filters.Request.ListResourcesFilters.Add(next => async (context, cancellationToken) =>
options.Filters.Request.ListResourcesFilters.Add(next =>
{
context.Items[AuthorizationFilterInvokedKey] = true;

var result = await next(context, cancellationToken);
await FilterAuthorizedItemsAsync(
result.Resources, static resource => resource.McpServerResource,
context.User, context.Services, context);
return result;
var resourceCollection = options.ResourceCollection;
return async (context, cancellationToken) =>
{
context.Items[AuthorizationFilterInvokedKey] = true;

var result = await next(context, cancellationToken);
await FilterAuthorizedItemsAsync(
result.Resources, resource => resourceCollection is not null && resourceCollection.TryGetPrimitive(resource.Uri, out var serverResource) ? serverResource : null,
context.User, context.Services, context);
return result;
};
});
}

private static void CheckListResourcesFilter(McpServerOptions options)
{
options.Filters.Request.ListResourcesFilters.Add(next => async (context, cancellationToken) =>
options.Filters.Request.ListResourcesFilters.Add(next =>
{
var result = await next(context, cancellationToken);

if (HasAuthorizationMetadata(result.Resources.Select(static resource => resource.McpServerResource))
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
var resourceCollection = options.ResourceCollection;
return async (context, cancellationToken) =>
{
throw new InvalidOperationException("Authorization filter was not invoked for resources/list operation, but authorization metadata was found on the resources. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
}
var result = await next(context, cancellationToken);

if (HasAuthorizationMetadata(result.Resources.Select(resource => resourceCollection is not null && resourceCollection.TryGetPrimitive(resource.Uri, out var serverResource) ? serverResource : null))
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
{
throw new InvalidOperationException("Authorization filter was not invoked for resources/list operation, but authorization metadata was found on the resources. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
}

return result;
return result;
};
});
}

private void ConfigureListResourceTemplatesFilter(McpServerOptions options)
{
options.Filters.Request.ListResourceTemplatesFilters.Add(next => async (context, cancellationToken) =>
options.Filters.Request.ListResourceTemplatesFilters.Add(next =>
{
context.Items[AuthorizationFilterInvokedKey] = true;

var result = await next(context, cancellationToken);
await FilterAuthorizedItemsAsync(
result.ResourceTemplates, static resourceTemplate => resourceTemplate.McpServerResource,
context.User, context.Services, context);
return result;
var resourceCollection = options.ResourceCollection;
return async (context, cancellationToken) =>
{
context.Items[AuthorizationFilterInvokedKey] = true;

var result = await next(context, cancellationToken);
await FilterAuthorizedItemsAsync(
result.ResourceTemplates, resourceTemplate => resourceCollection is not null && resourceCollection.TryGetPrimitive(resourceTemplate.UriTemplate, out var serverResource) ? serverResource : null,
context.User, context.Services, context);
return result;
};
});
}

private static void CheckListResourceTemplatesFilter(McpServerOptions options)
{
options.Filters.Request.ListResourceTemplatesFilters.Add(next => async (context, cancellationToken) =>
options.Filters.Request.ListResourceTemplatesFilters.Add(next =>
{
var result = await next(context, cancellationToken);

if (HasAuthorizationMetadata(result.ResourceTemplates.Select(static resourceTemplate => resourceTemplate.McpServerResource))
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
var resourceCollection = options.ResourceCollection;
return async (context, cancellationToken) =>
{
throw new InvalidOperationException("Authorization filter was not invoked for resources/templates/list operation, but authorization metadata was found on the resource templates. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
}
var result = await next(context, cancellationToken);

if (HasAuthorizationMetadata(result.ResourceTemplates.Select(resourceTemplate => resourceCollection is not null && resourceCollection.TryGetPrimitive(resourceTemplate.UriTemplate, out var serverResource) ? serverResource : null))
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
{
throw new InvalidOperationException("Authorization filter was not invoked for resources/templates/list operation, but authorization metadata was found on the resource templates. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
}

return result;
return result;
};
});
}

Expand Down Expand Up @@ -193,31 +217,39 @@ private static void CheckReadResourceFilter(McpServerOptions options)

private void ConfigureListPromptsFilter(McpServerOptions options)
{
options.Filters.Request.ListPromptsFilters.Add(next => async (context, cancellationToken) =>
options.Filters.Request.ListPromptsFilters.Add(next =>
{
context.Items[AuthorizationFilterInvokedKey] = true;

var result = await next(context, cancellationToken);
await FilterAuthorizedItemsAsync(
result.Prompts, static prompt => prompt.McpServerPrompt,
context.User, context.Services, context);
return result;
var promptCollection = options.PromptCollection;
return async (context, cancellationToken) =>
{
context.Items[AuthorizationFilterInvokedKey] = true;

var result = await next(context, cancellationToken);
await FilterAuthorizedItemsAsync(
result.Prompts, prompt => promptCollection is not null && promptCollection.TryGetPrimitive(prompt.Name, out var serverPrompt) ? serverPrompt : null,
context.User, context.Services, context);
return result;
};
});
}

private static void CheckListPromptsFilter(McpServerOptions options)
{
options.Filters.Request.ListPromptsFilters.Add(next => async (context, cancellationToken) =>
options.Filters.Request.ListPromptsFilters.Add(next =>
{
var result = await next(context, cancellationToken);

if (HasAuthorizationMetadata(result.Prompts.Select(static prompt => prompt.McpServerPrompt))
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
var promptCollection = options.PromptCollection;
return async (context, cancellationToken) =>
{
throw new InvalidOperationException("Authorization filter was not invoked for prompts/list operation, but authorization metadata was found on the prompts. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
}
var result = await next(context, cancellationToken);

if (HasAuthorizationMetadata(result.Prompts.Select(prompt => promptCollection is not null && promptCollection.TryGetPrimitive(prompt.Name, out var serverPrompt) ? serverPrompt : null))
&& !context.Items.ContainsKey(AuthorizationFilterInvokedKey))
{
throw new InvalidOperationException("Authorization filter was not invoked for prompts/list operation, but authorization metadata was found on the prompts. Ensure that AddAuthorizationFilters() is called on the IMcpServerBuilder to configure authorization filters.");
}

return result;
return result;
};
});
}

Expand Down
7 changes: 0 additions & 7 deletions src/ModelContextProtocol.Core/Protocol/Prompt.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Diagnostics;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using ModelContextProtocol.Server;

namespace ModelContextProtocol.Protocol;

Expand Down Expand Up @@ -72,12 +71,6 @@ public sealed class Prompt : IBaseMetadata
[JsonPropertyName("_meta")]
public JsonObject? Meta { get; set; }

/// <summary>
/// Gets or sets the callable server prompt corresponding to this metadata if any.
/// </summary>
[JsonIgnore]
public McpServerPrompt? McpServerPrompt { get; set; }

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay
{
Expand Down
7 changes: 0 additions & 7 deletions src/ModelContextProtocol.Core/Protocol/Resource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using ModelContextProtocol.Server;

namespace ModelContextProtocol.Protocol;

Expand Down Expand Up @@ -101,10 +100,4 @@ public sealed class Resource : IBaseMetadata
/// </remarks>
[JsonPropertyName("_meta")]
public JsonObject? Meta { get; set; }

/// <summary>
/// Gets or sets the callable server resource corresponding to this metadata if any.
/// </summary>
[JsonIgnore]
public McpServerResource? McpServerResource { get; set; }
}
8 changes: 0 additions & 8 deletions src/ModelContextProtocol.Core/Protocol/ResourceTemplate.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using ModelContextProtocol.Server;

namespace ModelContextProtocol.Protocol;

Expand Down Expand Up @@ -94,12 +93,6 @@ public sealed class ResourceTemplate : IBaseMetadata
[JsonIgnore]
public bool IsTemplated => UriTemplate.Contains('{');

/// <summary>
/// Gets or sets the callable server resource corresponding to this metadata, if any.
/// </summary>
[JsonIgnore]
public McpServerResource? McpServerResource { get; set; }

/// <summary>Converts the <see cref="ResourceTemplate"/> into a <see cref="Resource"/>.</summary>
/// <returns>A <see cref="Resource"/> if <see cref="IsTemplated"/> is <see langword="false"/>; otherwise, <see langword="null"/>.</returns>
public Resource? AsResource()
Expand All @@ -119,7 +112,6 @@ public sealed class ResourceTemplate : IBaseMetadata
Annotations = Annotations,
Icons = Icons,
Meta = Meta,
McpServerResource = McpServerResource,
};
}
}
7 changes: 0 additions & 7 deletions src/ModelContextProtocol.Core/Protocol/Tool.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using ModelContextProtocol.Server;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
Expand Down Expand Up @@ -158,12 +157,6 @@ public ToolExecution? Execution
[JsonPropertyName("_meta")]
public JsonObject? Meta { get; set; }

/// <summary>
/// Gets or sets the callable server tool corresponding to this metadata if any.
/// </summary>
[JsonIgnore]
public McpServerTool? McpServerTool { get; set; }

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ private AIFunctionMcpServerPrompt(AIFunction function, Prompt prompt, IReadOnlyL
{
AIFunction = function;
ProtocolPrompt = prompt;
ProtocolPrompt.McpServerPrompt = this;
_metadata = metadata;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,6 @@ private AIFunctionMcpServerResource(AIFunction function, ResourceTemplate resour
{
AIFunction = function;
ProtocolResourceTemplate = resourceTemplate;
ProtocolResourceTemplate.McpServerResource = this;
ProtocolResource = resourceTemplate.AsResource();
_metadata = metadata;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,6 @@ private AIFunctionMcpServerTool(AIFunction function, Tool tool, IServiceProvider

AIFunction = function;
ProtocolTool = tool;
ProtocolTool.McpServerTool = this;

_structuredOutputRequiresWrapping = structuredOutputRequiresWrapping;
_metadata = metadata;
Expand Down
Loading