Wrap each request in a service scope (#276)
* Wrap each request in a service scope * Change request/notification delegates to return ValueTask * Address feedback
This commit is contained in:
parent
f1cc2d81de
commit
f4c87f5e2f
10 changed files with 477 additions and 306 deletions
|
|
@ -99,7 +99,7 @@ internal sealed class AIFunctionMcpServerPrompt : McpServerPrompt
|
|||
{
|
||||
ExcludeFromSchema = true,
|
||||
BindParameter = (pi, args) =>
|
||||
GetRequestContext(args)?.Server?.Services?.GetService(pi.ParameterType) ??
|
||||
GetRequestContext(args)?.Services?.GetService(pi.ParameterType) ??
|
||||
(pi.HasDefaultValue ? null :
|
||||
throw new ArgumentException("No service of the requested type was found.")),
|
||||
};
|
||||
|
|
@ -111,7 +111,7 @@ internal sealed class AIFunctionMcpServerPrompt : McpServerPrompt
|
|||
{
|
||||
ExcludeFromSchema = true,
|
||||
BindParameter = (pi, args) =>
|
||||
(GetRequestContext(args)?.Server?.Services as IKeyedServiceProvider)?.GetKeyedService(pi.ParameterType, keyedAttr.Key) ??
|
||||
(GetRequestContext(args)?.Services as IKeyedServiceProvider)?.GetKeyedService(pi.ParameterType, keyedAttr.Key) ??
|
||||
(pi.HasDefaultValue ? null :
|
||||
throw new ArgumentException("No service of the requested type was found.")),
|
||||
};
|
||||
|
|
@ -206,7 +206,7 @@ internal sealed class AIFunctionMcpServerPrompt : McpServerPrompt
|
|||
/// <item><description><see cref="ChatMessage"/> objects are converted to prompt messages</description></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public override async Task<GetPromptResult> GetAsync(
|
||||
public override async ValueTask<GetPromptResult> GetAsync(
|
||||
RequestContext<GetPromptRequestParams> request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Throw.IfNull(request);
|
||||
|
|
@ -214,7 +214,7 @@ internal sealed class AIFunctionMcpServerPrompt : McpServerPrompt
|
|||
|
||||
AIFunctionArguments arguments = new()
|
||||
{
|
||||
Services = request.Server?.Services,
|
||||
Services = request.Services,
|
||||
Context = new Dictionary<object, object?>() { [typeof(RequestContext<GetPromptRequestParams>)] = request }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ internal sealed class AIFunctionMcpServerTool : McpServerTool
|
|||
{
|
||||
ExcludeFromSchema = true,
|
||||
BindParameter = (pi, args) =>
|
||||
GetRequestContext(args)?.Server?.Services?.GetService(pi.ParameterType) ??
|
||||
GetRequestContext(args)?.Services?.GetService(pi.ParameterType) ??
|
||||
(pi.HasDefaultValue ? null :
|
||||
throw new ArgumentException("No service of the requested type was found.")),
|
||||
};
|
||||
|
|
@ -132,7 +132,7 @@ internal sealed class AIFunctionMcpServerTool : McpServerTool
|
|||
{
|
||||
ExcludeFromSchema = true,
|
||||
BindParameter = (pi, args) =>
|
||||
(GetRequestContext(args)?.Server?.Services as IKeyedServiceProvider)?.GetKeyedService(pi.ParameterType, keyedAttr.Key) ??
|
||||
(GetRequestContext(args)?.Services as IKeyedServiceProvider)?.GetKeyedService(pi.ParameterType, keyedAttr.Key) ??
|
||||
(pi.HasDefaultValue ? null :
|
||||
throw new ArgumentException("No service of the requested type was found.")),
|
||||
};
|
||||
|
|
@ -237,7 +237,7 @@ internal sealed class AIFunctionMcpServerTool : McpServerTool
|
|||
public override Tool ProtocolTool { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<CallToolResponse> InvokeAsync(
|
||||
public override async ValueTask<CallToolResponse> InvokeAsync(
|
||||
RequestContext<CallToolRequestParams> request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Throw.IfNull(request);
|
||||
|
|
@ -245,7 +245,7 @@ internal sealed class AIFunctionMcpServerTool : McpServerTool
|
|||
|
||||
AIFunctionArguments arguments = new()
|
||||
{
|
||||
Services = request.Server?.Services,
|
||||
Services = request.Services,
|
||||
Context = new Dictionary<object, object?>() { [typeof(RequestContext<CallToolRequestParams>)] = request }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public abstract class DelegatingMcpServerPrompt : McpServerPrompt
|
|||
public override Prompt ProtocolPrompt => _innerPrompt.ProtocolPrompt;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<GetPromptResult> GetAsync(
|
||||
public override ValueTask<GetPromptResult> GetAsync(
|
||||
RequestContext<GetPromptRequestParams> request,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
_innerPrompt.GetAsync(request, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public abstract class DelegatingMcpServerTool : McpServerTool
|
|||
public override Tool ProtocolTool => _innerTool.ProtocolTool;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<CallToolResponse> InvokeAsync(
|
||||
public override ValueTask<CallToolResponse> InvokeAsync(
|
||||
RequestContext<CallToolRequestParams> request,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
_innerTool.InvokeAsync(request, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ModelContextProtocol.Protocol.Messages;
|
||||
using ModelContextProtocol.Protocol.Transport;
|
||||
|
|
@ -7,6 +8,8 @@ using ModelContextProtocol.Utils;
|
|||
using ModelContextProtocol.Utils.Json;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
|
||||
namespace ModelContextProtocol.Server;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -19,6 +22,7 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
|
|||
};
|
||||
|
||||
private readonly ITransport _sessionTransport;
|
||||
private readonly bool _servicesScopePerRequest;
|
||||
|
||||
private readonly EventHandler? _toolsChangedDelegate;
|
||||
private readonly EventHandler? _promptsChangedDelegate;
|
||||
|
|
@ -54,6 +58,7 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
|
|||
ServerOptions = options;
|
||||
Services = serviceProvider;
|
||||
_endpointName = $"Server ({options.ServerInfo?.Name ?? DefaultImplementation.Name} {options.ServerInfo?.Version ?? DefaultImplementation.Version})";
|
||||
_servicesScopePerRequest = options.ScopeRequests;
|
||||
|
||||
// Configure all request handlers based on the supplied options.
|
||||
SetInitializeHandler(options);
|
||||
|
|
@ -154,7 +159,7 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
|
|||
private void SetPingHandler()
|
||||
{
|
||||
RequestHandlers.Set(RequestMethods.Ping,
|
||||
(request, _) => Task.FromResult(new PingResult()),
|
||||
async (request, _) => new PingResult(),
|
||||
McpJsonUtilities.JsonContext.Default.JsonNode,
|
||||
McpJsonUtilities.JsonContext.Default.PingResult);
|
||||
}
|
||||
|
|
@ -162,7 +167,7 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
|
|||
private void SetInitializeHandler(McpServerOptions options)
|
||||
{
|
||||
RequestHandlers.Set(RequestMethods.Initialize,
|
||||
(request, _) =>
|
||||
async (request, _) =>
|
||||
{
|
||||
ClientCapabilities = request?.Capabilities ?? new();
|
||||
ClientInfo = request?.ClientInfo;
|
||||
|
|
@ -171,13 +176,13 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
|
|||
_endpointName = $"{_endpointName}, Client ({ClientInfo?.Name} {ClientInfo?.Version})";
|
||||
GetSessionOrThrow().EndpointName = _endpointName;
|
||||
|
||||
return Task.FromResult(new InitializeResult
|
||||
return new InitializeResult
|
||||
{
|
||||
ProtocolVersion = options.ProtocolVersion,
|
||||
Instructions = options.ServerInstructions,
|
||||
ServerInfo = options.ServerInfo ?? DefaultImplementation,
|
||||
Capabilities = ServerCapabilities ?? new(),
|
||||
});
|
||||
};
|
||||
},
|
||||
McpJsonUtilities.JsonContext.Default.InitializeRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.InitializeResult);
|
||||
|
|
@ -196,7 +201,7 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
|
|||
// This capability is not optional, so return an empty result if there is no handler.
|
||||
RequestHandlers.Set(
|
||||
RequestMethods.CompletionComplete,
|
||||
(request, cancellationToken) => completeHandler(new(this, request), cancellationToken),
|
||||
(request, cancellationToken) => InvokeHandlerAsync(completeHandler, request, cancellationToken),
|
||||
McpJsonUtilities.JsonContext.Default.CompleteRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.CompleteResult);
|
||||
}
|
||||
|
|
@ -217,24 +222,24 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
|
|||
throw new McpException("Resources capability was enabled, but ListResources and/or ReadResource handlers were not specified.");
|
||||
}
|
||||
|
||||
listResourcesHandler ??= (static (_, _) => Task.FromResult(new ListResourcesResult()));
|
||||
listResourcesHandler ??= static async (_, _) => new ListResourcesResult();
|
||||
|
||||
RequestHandlers.Set(
|
||||
RequestMethods.ResourcesList,
|
||||
(request, cancellationToken) => listResourcesHandler(new(this, request), cancellationToken),
|
||||
(request, cancellationToken) => InvokeHandlerAsync(listResourcesHandler, request, cancellationToken),
|
||||
McpJsonUtilities.JsonContext.Default.ListResourcesRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.ListResourcesResult);
|
||||
|
||||
RequestHandlers.Set(
|
||||
RequestMethods.ResourcesRead,
|
||||
(request, cancellationToken) => readResourceHandler(new(this, request), cancellationToken),
|
||||
(request, cancellationToken) => InvokeHandlerAsync(readResourceHandler, request, cancellationToken),
|
||||
McpJsonUtilities.JsonContext.Default.ReadResourceRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.ReadResourceResult);
|
||||
|
||||
listResourceTemplatesHandler ??= (static (_, _) => Task.FromResult(new ListResourceTemplatesResult()));
|
||||
listResourceTemplatesHandler ??= static async (_, _) => new ListResourceTemplatesResult();
|
||||
RequestHandlers.Set(
|
||||
RequestMethods.ResourcesTemplatesList,
|
||||
(request, cancellationToken) => listResourceTemplatesHandler(new(this, request), cancellationToken),
|
||||
(request, cancellationToken) => InvokeHandlerAsync(listResourceTemplatesHandler, request, cancellationToken),
|
||||
McpJsonUtilities.JsonContext.Default.ListResourceTemplatesRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.ListResourceTemplatesResult);
|
||||
|
||||
|
|
@ -252,13 +257,13 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
|
|||
|
||||
RequestHandlers.Set(
|
||||
RequestMethods.ResourcesSubscribe,
|
||||
(request, cancellationToken) => subscribeHandler(new(this, request), cancellationToken),
|
||||
(request, cancellationToken) => InvokeHandlerAsync(subscribeHandler, request, cancellationToken),
|
||||
McpJsonUtilities.JsonContext.Default.SubscribeRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.EmptyResult);
|
||||
|
||||
RequestHandlers.Set(
|
||||
RequestMethods.ResourcesUnsubscribe,
|
||||
(request, cancellationToken) => unsubscribeHandler(new(this, request), cancellationToken),
|
||||
(request, cancellationToken) => InvokeHandlerAsync(unsubscribeHandler, request, cancellationToken),
|
||||
McpJsonUtilities.JsonContext.Default.UnsubscribeRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.EmptyResult);
|
||||
}
|
||||
|
|
@ -345,13 +350,13 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
|
|||
|
||||
RequestHandlers.Set(
|
||||
RequestMethods.PromptsList,
|
||||
(request, cancellationToken) => listPromptsHandler(new(this, request), cancellationToken),
|
||||
(request, cancellationToken) => InvokeHandlerAsync(listPromptsHandler, request, cancellationToken),
|
||||
McpJsonUtilities.JsonContext.Default.ListPromptsRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.ListPromptsResult);
|
||||
|
||||
RequestHandlers.Set(
|
||||
RequestMethods.PromptsGet,
|
||||
(request, cancellationToken) => getPromptHandler(new(this, request), cancellationToken),
|
||||
(request, cancellationToken) => InvokeHandlerAsync(getPromptHandler, request, cancellationToken),
|
||||
McpJsonUtilities.JsonContext.Default.GetPromptRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.GetPromptResult);
|
||||
}
|
||||
|
|
@ -438,13 +443,13 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
|
|||
|
||||
RequestHandlers.Set(
|
||||
RequestMethods.ToolsList,
|
||||
(request, cancellationToken) => listToolsHandler(new(this, request), cancellationToken),
|
||||
(request, cancellationToken) => InvokeHandlerAsync(listToolsHandler, request, cancellationToken),
|
||||
McpJsonUtilities.JsonContext.Default.ListToolsRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.ListToolsResult);
|
||||
|
||||
RequestHandlers.Set(
|
||||
RequestMethods.ToolsCall,
|
||||
(request, cancellationToken) => callToolHandler(new(this, request), cancellationToken),
|
||||
(request, cancellationToken) => InvokeHandlerAsync(callToolHandler, request, cancellationToken),
|
||||
McpJsonUtilities.JsonContext.Default.CallToolRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.CallToolResponse);
|
||||
}
|
||||
|
|
@ -473,16 +478,51 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
|
|||
// If a handler was provided, now delegate to it.
|
||||
if (setLoggingLevelHandler is not null)
|
||||
{
|
||||
return setLoggingLevelHandler(new(this, request), cancellationToken);
|
||||
return InvokeHandlerAsync(setLoggingLevelHandler, request, cancellationToken);
|
||||
}
|
||||
|
||||
// Otherwise, consider it handled.
|
||||
return EmptyResult.CompletedTask;
|
||||
return new ValueTask<EmptyResult>(EmptyResult.Instance);
|
||||
},
|
||||
McpJsonUtilities.JsonContext.Default.SetLevelRequestParams,
|
||||
McpJsonUtilities.JsonContext.Default.EmptyResult);
|
||||
}
|
||||
|
||||
private ValueTask<TResult> InvokeHandlerAsync<TParams, TResult>(
|
||||
Func<RequestContext<TParams>, CancellationToken, ValueTask<TResult>> handler,
|
||||
TParams? args,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return _servicesScopePerRequest ?
|
||||
InvokeScopedAsync(handler, args, cancellationToken) :
|
||||
handler(new(this) { Params = args }, cancellationToken);
|
||||
|
||||
async ValueTask<TResult> InvokeScopedAsync(
|
||||
Func<RequestContext<TParams>, CancellationToken, ValueTask<TResult>> handler,
|
||||
TParams? args,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var scope = Services?.GetService<IServiceScopeFactory>()?.CreateAsyncScope();
|
||||
try
|
||||
{
|
||||
return await handler(
|
||||
new RequestContext<TParams>(this)
|
||||
{
|
||||
Services = scope?.ServiceProvider ?? Services,
|
||||
Params = args
|
||||
},
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (scope is not null)
|
||||
{
|
||||
await scope.Value.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Maps a <see cref="LogLevel"/> to a <see cref="LoggingLevel"/>.</summary>
|
||||
internal static LoggingLevel ToLoggingLevel(LogLevel level) =>
|
||||
level switch
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public sealed class McpServerHandlers
|
|||
/// Tools from both sources will be combined when returning results to clients.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public Func<RequestContext<ListToolsRequestParams>, CancellationToken, Task<ListToolsResult>>? ListToolsHandler { get; set; }
|
||||
public Func<RequestContext<ListToolsRequestParams>, CancellationToken, ValueTask<ListToolsResult>>? ListToolsHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for <see cref="RequestMethods.ToolsCall"/> requests.
|
||||
|
|
@ -50,7 +50,7 @@ public sealed class McpServerHandlers
|
|||
/// This handler is invoked when a client makes a call to a tool that isn't found in the <see cref="McpServerTool"/> collection.
|
||||
/// The handler should implement logic to execute the requested tool and return appropriate results.
|
||||
/// </remarks>
|
||||
public Func<RequestContext<CallToolRequestParams>, CancellationToken, Task<CallToolResponse>>? CallToolHandler { get; set; }
|
||||
public Func<RequestContext<CallToolRequestParams>, CancellationToken, ValueTask<CallToolResponse>>? CallToolHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for <see cref="RequestMethods.PromptsList"/> requests.
|
||||
|
|
@ -66,7 +66,7 @@ public sealed class McpServerHandlers
|
|||
/// Prompts from both sources will be combined when returning results to clients.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public Func<RequestContext<ListPromptsRequestParams>, CancellationToken, Task<ListPromptsResult>>? ListPromptsHandler { get; set; }
|
||||
public Func<RequestContext<ListPromptsRequestParams>, CancellationToken, ValueTask<ListPromptsResult>>? ListPromptsHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for <see cref="RequestMethods.PromptsGet"/> requests.
|
||||
|
|
@ -75,7 +75,7 @@ public sealed class McpServerHandlers
|
|||
/// This handler is invoked when a client requests details for a specific prompt that isn't found in the <see cref="McpServerPrompt"/> collection.
|
||||
/// The handler should implement logic to fetch or generate the requested prompt and return appropriate results.
|
||||
/// </remarks>
|
||||
public Func<RequestContext<GetPromptRequestParams>, CancellationToken, Task<GetPromptResult>>? GetPromptHandler { get; set; }
|
||||
public Func<RequestContext<GetPromptRequestParams>, CancellationToken, ValueTask<GetPromptResult>>? GetPromptHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for <see cref="RequestMethods.ResourcesTemplatesList"/> requests.
|
||||
|
|
@ -85,7 +85,7 @@ public sealed class McpServerHandlers
|
|||
/// It supports pagination through the cursor mechanism, where the client can make
|
||||
/// repeated calls with the cursor returned by the previous call to retrieve more resource templates.
|
||||
/// </remarks>
|
||||
public Func<RequestContext<ListResourceTemplatesRequestParams>, CancellationToken, Task<ListResourceTemplatesResult>>? ListResourceTemplatesHandler { get; set; }
|
||||
public Func<RequestContext<ListResourceTemplatesRequestParams>, CancellationToken, ValueTask<ListResourceTemplatesResult>>? ListResourceTemplatesHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for <see cref="RequestMethods.ResourcesList"/> requests.
|
||||
|
|
@ -95,7 +95,7 @@ public sealed class McpServerHandlers
|
|||
/// It supports pagination through the cursor mechanism, where the client can make
|
||||
/// repeated calls with the cursor returned by the previous call to retrieve more resources.
|
||||
/// </remarks>
|
||||
public Func<RequestContext<ListResourcesRequestParams>, CancellationToken, Task<ListResourcesResult>>? ListResourcesHandler { get; set; }
|
||||
public Func<RequestContext<ListResourcesRequestParams>, CancellationToken, ValueTask<ListResourcesResult>>? ListResourcesHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for <see cref="RequestMethods.ResourcesRead"/> requests.
|
||||
|
|
@ -104,7 +104,7 @@ public sealed class McpServerHandlers
|
|||
/// This handler is invoked when a client requests the content of a specific resource identified by its URI.
|
||||
/// The handler should implement logic to locate and retrieve the requested resource.
|
||||
/// </remarks>
|
||||
public Func<RequestContext<ReadResourceRequestParams>, CancellationToken, Task<ReadResourceResult>>? ReadResourceHandler { get; set; }
|
||||
public Func<RequestContext<ReadResourceRequestParams>, CancellationToken, ValueTask<ReadResourceResult>>? ReadResourceHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for <see cref="RequestMethods.CompletionComplete"/> requests.
|
||||
|
|
@ -114,7 +114,7 @@ public sealed class McpServerHandlers
|
|||
/// The handler processes auto-completion requests, returning a list of suggestions based on the
|
||||
/// reference type and current argument value.
|
||||
/// </remarks>
|
||||
public Func<RequestContext<CompleteRequestParams>, CancellationToken, Task<CompleteResult>>? CompleteHandler { get; set; }
|
||||
public Func<RequestContext<CompleteRequestParams>, CancellationToken, ValueTask<CompleteResult>>? CompleteHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for <see cref="RequestMethods.ResourcesSubscribe"/> requests.
|
||||
|
|
@ -130,7 +130,7 @@ public sealed class McpServerHandlers
|
|||
/// whenever a relevant resource is created, updated, or deleted.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public Func<RequestContext<SubscribeRequestParams>, CancellationToken, Task<EmptyResult>>? SubscribeToResourcesHandler { get; set; }
|
||||
public Func<RequestContext<SubscribeRequestParams>, CancellationToken, ValueTask<EmptyResult>>? SubscribeToResourcesHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for <see cref="RequestMethods.ResourcesUnsubscribe"/> requests.
|
||||
|
|
@ -146,7 +146,7 @@ public sealed class McpServerHandlers
|
|||
/// to the client for the specified resources.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public Func<RequestContext<UnsubscribeRequestParams>, CancellationToken, Task<EmptyResult>>? UnsubscribeFromResourcesHandler { get; set; }
|
||||
public Func<RequestContext<UnsubscribeRequestParams>, CancellationToken, ValueTask<EmptyResult>>? UnsubscribeFromResourcesHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the handler for <see cref="RequestMethods.LoggingSetLevel"/> requests.
|
||||
|
|
@ -161,7 +161,7 @@ public sealed class McpServerHandlers
|
|||
/// at or above the specified level to the client as notifications/message notifications.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public Func<RequestContext<SetLevelRequestParams>, CancellationToken, Task<EmptyResult>>? SetLoggingLevelHandler { get; set; }
|
||||
public Func<RequestContext<SetLevelRequestParams>, CancellationToken, ValueTask<EmptyResult>>? SetLoggingLevelHandler { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Overwrite any handlers in McpServerOptions with non-null handlers from this instance.
|
||||
|
|
|
|||
|
|
@ -56,4 +56,13 @@ public class McpServerOptions
|
|||
/// to provide context about available functionality.
|
||||
/// </remarks>
|
||||
public string? ServerInstructions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether to create a new service provider scope for each handled request.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default is <see langword="true"/>. When <see langword="true"/>, each invocation of a request
|
||||
/// handler will be invoked within a new service scope.
|
||||
/// </remarks>
|
||||
public bool ScopeRequests { get; set; } = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ public abstract class McpServerPrompt : IMcpServerPrimitive
|
|||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="request"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="InvalidOperationException">The prompt implementation returns <see langword="null"/> or an unsupported result type.</exception>
|
||||
public abstract Task<GetPromptResult> GetAsync(
|
||||
public abstract ValueTask<GetPromptResult> GetAsync(
|
||||
RequestContext<GetPromptRequestParams> request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ public abstract class McpServerTool : IMcpServerPrimitive
|
|||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||
/// <returns>The call response from invoking the tool.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="request"/> is <see langword="null"/>.</exception>
|
||||
public abstract Task<CallToolResponse> InvokeAsync(
|
||||
public abstract ValueTask<CallToolResponse> InvokeAsync(
|
||||
RequestContext<CallToolRequestParams> request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ModelContextProtocol.Utils;
|
||||
|
||||
namespace ModelContextProtocol.Server;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a context container that provides access to both the server instance and the client request parameters.
|
||||
/// Provides a context container that provides access to the client request parameters and resources for the request.
|
||||
/// </summary>
|
||||
/// <typeparam name="TParams">Type of the request parameters specific to each MCP operation.</typeparam>
|
||||
/// <remarks>
|
||||
|
|
@ -11,4 +12,43 @@ namespace ModelContextProtocol.Server;
|
|||
/// This type is typically received as a parameter in handler delegates registered with <see cref="IMcpServerBuilder"/>,
|
||||
/// and may be injected as parameters into <see cref="McpServerTool"/>s.
|
||||
/// </remarks>
|
||||
public record RequestContext<TParams>(IMcpServer Server, TParams? Params);
|
||||
public sealed class RequestContext<TParams>
|
||||
{
|
||||
/// <summary>The server with which this instance is associated.</summary>
|
||||
private IMcpServer _server;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RequestContext{TParams}"/> class with the specified server.
|
||||
/// </summary>
|
||||
/// <param name="server">The server with which this instance is associated.</param>
|
||||
public RequestContext(IMcpServer server)
|
||||
{
|
||||
Throw.IfNull(server);
|
||||
|
||||
_server = server;
|
||||
Services = server.Services;
|
||||
}
|
||||
|
||||
/// <summary>Gets or sets the server with which this instance is associated.</summary>
|
||||
public IMcpServer Server
|
||||
{
|
||||
get => _server;
|
||||
set
|
||||
{
|
||||
Throw.IfNull(value);
|
||||
_server = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets or sets the services associated with this request.</summary>
|
||||
/// <remarks>
|
||||
/// This may not be the same instance stored in <see cref="IMcpServer.Services"/>
|
||||
/// if <see cref="McpServerOptions.ScopeRequests"/> was true, in which case this
|
||||
/// might be a scoped <see cref="IServiceProvider"/> derived from the server's
|
||||
/// <see cref="IMcpServer.Services"/>.
|
||||
/// </remarks>
|
||||
public IServiceProvider? Services { get; set; }
|
||||
|
||||
/// <summary>Gets or sets the parameters associated with this request.</summary>
|
||||
public TParams? Params { get; set; }
|
||||
}
|
||||
Loading…
Reference in a new issue