Decouple Handlers and Collections from protocol types (#765)
* Decouple Handlers and Collections (e.g. ToolsHandler and ToolsCollection) from Capabilities by promoting them to the options types. Also, group all handlers in container classes, for server, I decided to move McpServerHandlers down to Mcp.Core and move the NotificationHandlers there too. Also, Fix ListResourceTemplatesHandler issue. * Add remarks for empty protocol capability types * Keep JsonIgnore properties and mark them as Obsolete * Continue supporting Obsolete members * Update Obsolete messages to indicate the member will be removed * Add EditorBrowsable Never to the remaining obsolete members
This commit is contained in:
parent
39b0ed3c18
commit
5f992994c3
1 changed files with 1588 additions and 1161 deletions
|
|
@ -84,7 +84,7 @@ internal sealed partial class McpServerImpl : McpServer
|
|||
ConfigurePing();
|
||||
|
||||
// Register any notification handlers that were provided.
|
||||
if (options.Capabilities?.NotificationHandlers is { } notificationHandlers)
|
||||
if (options.Handlers.NotificationHandlers is { } notificationHandlers)
|
||||
{
|
||||
_notificationHandlers.RegisterRange(notificationHandlers);
|
||||
}
|
||||
|
|
@ -92,9 +92,9 @@ internal sealed partial class McpServerImpl : McpServer
|
|||
// Now that everything has been configured, subscribe to any necessary notifications.
|
||||
if (transport is not StreamableHttpServerTransport streamableHttpTransport || streamableHttpTransport.Stateless is false)
|
||||
{
|
||||
Register(ServerOptions.Capabilities?.Tools?.ToolCollection, NotificationMethods.ToolListChangedNotification);
|
||||
Register(ServerOptions.Capabilities?.Prompts?.PromptCollection, NotificationMethods.PromptListChangedNotification);
|
||||
Register(ServerOptions.Capabilities?.Resources?.ResourceCollection, NotificationMethods.ResourceListChangedNotification);
|
||||
Register(ServerOptions.ToolCollection, NotificationMethods.ToolListChangedNotification);
|
||||
Register(ServerOptions.PromptCollection, NotificationMethods.PromptListChangedNotification);
|
||||
Register(ServerOptions.ResourceCollection, NotificationMethods.ResourceListChangedNotification);
|
||||
|
||||
void Register<TPrimitive>(McpServerPrimitiveCollection<TPrimitive>? collection, string notificationMethod)
|
||||
where TPrimitive : IMcpServerPrimitive
|
||||
|
|
@ -230,22 +230,26 @@ internal sealed partial class McpServerImpl : McpServer
|
|||
|
||||
private void ConfigureCompletion(McpServerOptions options)
|
||||
{
|
||||
if (options.Capabilities?.Completions is not { } completionsCapability)
|
||||
var completeHandler = options.Handlers.CompleteHandler;
|
||||
var completionsCapability = options.Capabilities?.Completions;
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
completeHandler ??= completionsCapability?.CompleteHandler;
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
if (completeHandler is null && completionsCapability is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var completeHandler = completionsCapability.CompleteHandler ?? (static async (_, __) => new CompleteResult());
|
||||
completeHandler ??= (static async (_, __) => new CompleteResult());
|
||||
completeHandler = BuildFilterPipeline(completeHandler, options.Filters.CompleteFilters);
|
||||
|
||||
ServerCapabilities.Completions = new()
|
||||
{
|
||||
CompleteHandler = completeHandler
|
||||
};
|
||||
ServerCapabilities.Completions = new();
|
||||
|
||||
SetHandler(
|
||||
RequestMethods.CompletionComplete,
|
||||
ServerCapabilities.Completions.CompleteHandler,
|
||||
completeHandler,
|
||||
McpJsonUtilities.JsonContext.Default.CompleteRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.CompleteResult);
|
||||
}
|
||||
|
|
@ -257,21 +261,38 @@ internal sealed partial class McpServerImpl : McpServer
|
|||
|
||||
private void ConfigureResources(McpServerOptions options)
|
||||
{
|
||||
if (options.Capabilities?.Resources is not { } resourcesCapability)
|
||||
var listResourcesHandler = options.Handlers.ListResourcesHandler;
|
||||
var listResourceTemplatesHandler = options.Handlers.ListResourceTemplatesHandler;
|
||||
var readResourceHandler = options.Handlers.ReadResourceHandler;
|
||||
var subscribeHandler = options.Handlers.SubscribeToResourcesHandler;
|
||||
var unsubscribeHandler = options.Handlers.UnsubscribeFromResourcesHandler;
|
||||
var resources = options.ResourceCollection;
|
||||
var resourcesCapability = options.Capabilities?.Resources;
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
listResourcesHandler ??= resourcesCapability?.ListResourcesHandler;
|
||||
listResourceTemplatesHandler ??= resourcesCapability?.ListResourceTemplatesHandler;
|
||||
readResourceHandler ??= resourcesCapability?.ReadResourceHandler;
|
||||
subscribeHandler ??= resourcesCapability?.SubscribeToResourcesHandler;
|
||||
unsubscribeHandler ??= resourcesCapability?.UnsubscribeFromResourcesHandler;
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
if (listResourcesHandler is null && listResourceTemplatesHandler is null && readResourceHandler is null &&
|
||||
subscribeHandler is null && unsubscribeHandler is null && resources is null &&
|
||||
resourcesCapability is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ServerCapabilities.Resources = new();
|
||||
|
||||
var listResourcesHandler = resourcesCapability.ListResourcesHandler ?? (static async (_, __) => new ListResourcesResult());
|
||||
var listResourceTemplatesHandler = resourcesCapability.ListResourceTemplatesHandler ?? (static async (_, __) => new ListResourceTemplatesResult());
|
||||
var readResourceHandler = resourcesCapability.ReadResourceHandler ?? (static async (request, _) => throw new McpException($"Unknown resource URI: '{request.Params?.Uri}'", McpErrorCode.InvalidParams));
|
||||
var subscribeHandler = resourcesCapability.SubscribeToResourcesHandler ?? (static async (_, __) => new EmptyResult());
|
||||
var unsubscribeHandler = resourcesCapability.UnsubscribeFromResourcesHandler ?? (static async (_, __) => new EmptyResult());
|
||||
var resources = resourcesCapability.ResourceCollection;
|
||||
var listChanged = resourcesCapability.ListChanged;
|
||||
var subscribe = resourcesCapability.Subscribe;
|
||||
listResourcesHandler ??= (static async (_, __) => new ListResourcesResult());
|
||||
listResourceTemplatesHandler ??= (static async (_, __) => new ListResourceTemplatesResult());
|
||||
readResourceHandler ??= (static async (request, _) => throw new McpException($"Unknown resource URI: '{request.Params?.Uri}'", McpErrorCode.InvalidParams));
|
||||
subscribeHandler ??= (static async (_, __) => new EmptyResult());
|
||||
unsubscribeHandler ??= (static async (_, __) => new EmptyResult());
|
||||
var listChanged = resourcesCapability?.ListChanged;
|
||||
var subscribe = resourcesCapability?.Subscribe;
|
||||
|
||||
// Handle resources provided via DI.
|
||||
if (resources is { IsEmpty: false })
|
||||
|
|
@ -376,12 +397,6 @@ internal sealed partial class McpServerImpl : McpServer
|
|||
subscribeHandler = BuildFilterPipeline(subscribeHandler, options.Filters.SubscribeToResourcesFilters);
|
||||
unsubscribeHandler = BuildFilterPipeline(unsubscribeHandler, options.Filters.UnsubscribeFromResourcesFilters);
|
||||
|
||||
ServerCapabilities.Resources.ListResourcesHandler = listResourcesHandler;
|
||||
ServerCapabilities.Resources.ListResourceTemplatesHandler = listResourceTemplatesHandler;
|
||||
ServerCapabilities.Resources.ReadResourceHandler = readResourceHandler;
|
||||
ServerCapabilities.Resources.ResourceCollection = resources;
|
||||
ServerCapabilities.Resources.SubscribeToResourcesHandler = subscribeHandler;
|
||||
ServerCapabilities.Resources.UnsubscribeFromResourcesHandler = unsubscribeHandler;
|
||||
ServerCapabilities.Resources.ListChanged = listChanged;
|
||||
ServerCapabilities.Resources.Subscribe = subscribe;
|
||||
|
||||
|
|
@ -418,17 +433,27 @@ internal sealed partial class McpServerImpl : McpServer
|
|||
|
||||
private void ConfigurePrompts(McpServerOptions options)
|
||||
{
|
||||
if (options.Capabilities?.Prompts is not { } promptsCapability)
|
||||
var listPromptsHandler = options.Handlers.ListPromptsHandler;
|
||||
var getPromptHandler = options.Handlers.GetPromptHandler;
|
||||
var prompts = options.PromptCollection;
|
||||
var promptsCapability = options.Capabilities?.Prompts;
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
listPromptsHandler ??= promptsCapability?.ListPromptsHandler;
|
||||
getPromptHandler ??= promptsCapability?.GetPromptHandler;
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
if (listPromptsHandler is null && getPromptHandler is null && prompts is null &&
|
||||
promptsCapability is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ServerCapabilities.Prompts = new();
|
||||
|
||||
var listPromptsHandler = promptsCapability.ListPromptsHandler ?? (static async (_, __) => new ListPromptsResult());
|
||||
var getPromptHandler = promptsCapability.GetPromptHandler ?? (static async (request, _) => throw new McpException($"Unknown prompt: '{request.Params?.Name}'", McpErrorCode.InvalidParams));
|
||||
var prompts = promptsCapability.PromptCollection;
|
||||
var listChanged = promptsCapability.ListChanged;
|
||||
listPromptsHandler ??= (static async (_, __) => new ListPromptsResult());
|
||||
getPromptHandler ??= (static async (request, _) => throw new McpException($"Unknown prompt: '{request.Params?.Name}'", McpErrorCode.InvalidParams));
|
||||
var listChanged = promptsCapability?.ListChanged;
|
||||
|
||||
// Handle tools provided via DI by augmenting the handlers to incorporate them.
|
||||
if (prompts is { IsEmpty: false })
|
||||
|
|
@ -479,9 +504,6 @@ internal sealed partial class McpServerImpl : McpServer
|
|||
return handler(request, cancellationToken);
|
||||
});
|
||||
|
||||
ServerCapabilities.Prompts.ListPromptsHandler = listPromptsHandler;
|
||||
ServerCapabilities.Prompts.GetPromptHandler = getPromptHandler;
|
||||
ServerCapabilities.Prompts.PromptCollection = prompts;
|
||||
ServerCapabilities.Prompts.ListChanged = listChanged;
|
||||
|
||||
SetHandler(
|
||||
|
|
@ -499,17 +521,27 @@ internal sealed partial class McpServerImpl : McpServer
|
|||
|
||||
private void ConfigureTools(McpServerOptions options)
|
||||
{
|
||||
if (options.Capabilities?.Tools is not { } toolsCapability)
|
||||
var listToolsHandler = options.Handlers.ListToolsHandler;
|
||||
var callToolHandler = options.Handlers.CallToolHandler;
|
||||
var tools = options.ToolCollection;
|
||||
var toolsCapability = options.Capabilities?.Tools;
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
listToolsHandler ??= toolsCapability?.ListToolsHandler;
|
||||
callToolHandler ??= toolsCapability?.CallToolHandler;
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
if (listToolsHandler is null && callToolHandler is null && tools is null &&
|
||||
toolsCapability is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ServerCapabilities.Tools = new();
|
||||
|
||||
var listToolsHandler = toolsCapability.ListToolsHandler ?? (static async (_, __) => new ListToolsResult());
|
||||
var callToolHandler = toolsCapability.CallToolHandler ?? (static async (request, _) => throw new McpException($"Unknown tool: '{request.Params?.Name}'", McpErrorCode.InvalidParams));
|
||||
var tools = toolsCapability.ToolCollection;
|
||||
var listChanged = toolsCapability.ListChanged;
|
||||
listToolsHandler ??= (static async (_, __) => new ListToolsResult());
|
||||
callToolHandler ??= (static async (request, _) => throw new McpException($"Unknown tool: '{request.Params?.Name}'", McpErrorCode.InvalidParams));
|
||||
var listChanged = toolsCapability?.ListChanged;
|
||||
|
||||
// Handle tools provided via DI by augmenting the handlers to incorporate them.
|
||||
if (tools is { IsEmpty: false })
|
||||
|
|
@ -591,9 +623,6 @@ internal sealed partial class McpServerImpl : McpServer
|
|||
}
|
||||
});
|
||||
|
||||
ServerCapabilities.Tools.ListToolsHandler = listToolsHandler;
|
||||
ServerCapabilities.Tools.CallToolHandler = callToolHandler;
|
||||
ServerCapabilities.Tools.ToolCollection = tools;
|
||||
ServerCapabilities.Tools.ListChanged = listChanged;
|
||||
|
||||
SetHandler(
|
||||
|
|
@ -612,7 +641,11 @@ internal sealed partial class McpServerImpl : McpServer
|
|||
private void ConfigureLogging(McpServerOptions options)
|
||||
{
|
||||
// We don't require that the handler be provided, as we always store the provided log level to the server.
|
||||
var setLoggingLevelHandler = options.Capabilities?.Logging?.SetLoggingLevelHandler;
|
||||
var setLoggingLevelHandler = options.Handlers.SetLoggingLevelHandler;
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
setLoggingLevelHandler ??= options.Capabilities?.Logging?.SetLoggingLevelHandler;
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
// Apply filters to the handler
|
||||
if (setLoggingLevelHandler is not null)
|
||||
|
|
@ -621,7 +654,6 @@ internal sealed partial class McpServerImpl : McpServer
|
|||
}
|
||||
|
||||
ServerCapabilities.Logging = new();
|
||||
ServerCapabilities.Logging.SetLoggingLevelHandler = setLoggingLevelHandler;
|
||||
|
||||
_requestHandlers.Set(
|
||||
RequestMethods.LoggingSetLevel,
|
||||
|
|
|
|||
Loading…
Reference in a new issue