Add 3-arg RequestContext constructor and obsolete 2-arg to eliminate null-forgiving operator usage (#1462)

This commit is contained in:
Copilot 2026-03-27 12:33:23 -07:00 • committed by GitHub
commit 7dcdbafe9d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 190 additions and 219 deletions

View file

@ -29,7 +29,7 @@ internal sealed class RequestHandlers : Dictionary<string, Func<JsonRpcRequest,
/// </remarks>
public void Set<TParams, TResult>(
string method,
Func<TParams?, JsonRpcRequest, CancellationToken, ValueTask<TResult>> handler,
Func<TParams, JsonRpcRequest, CancellationToken, ValueTask<TResult>> handler,
JsonTypeInfo<TParams> requestTypeInfo,
JsonTypeInfo<TResult> responseTypeInfo)
{
@ -40,7 +40,7 @@ internal sealed class RequestHandlers : Dictionary<string, Func<JsonRpcRequest,
this[method] = async (request, cancellationToken) =>
{
TParams? typedRequest = JsonSerializer.Deserialize(request.Params, requestTypeInfo);
TParams typedRequest = JsonSerializer.Deserialize(request.Params, requestTypeInfo)!;
object? result = await handler(typedRequest, request, cancellationToken).ConfigureAwait(false);
return JsonSerializer.SerializeToNode(result, responseTypeInfo);
};

View file

@ -386,14 +386,14 @@ internal sealed class AIFunctionMcpServerResource : McpServerResource
TextContent tc => new()
{
Contents = [new TextResourceContents { Uri = request.Params!.Uri, MimeType = ProtocolResourceTemplate.MimeType, Text = tc.Text }],
Contents = [new TextResourceContents { Uri = request.Params.Uri, MimeType = ProtocolResourceTemplate.MimeType, Text = tc.Text }],
},
DataContent dc => new()
{
Contents = [new BlobResourceContents
{
Uri = request.Params!.Uri,
Uri = request.Params.Uri,
MimeType = dc.MediaType,
Blob = EncodingUtilities.GetUtf8Bytes(dc.Base64Data.Span)
}],
@ -401,7 +401,7 @@ internal sealed class AIFunctionMcpServerResource : McpServerResource
string text => new()
{
Contents = [new TextResourceContents { Uri = request.Params!.Uri, MimeType = ProtocolResourceTemplate.MimeType, Text = text }],
Contents = [new TextResourceContents { Uri = request.Params.Uri, MimeType = ProtocolResourceTemplate.MimeType, Text = text }],
},
IEnumerable<ResourceContents> contents => new()
@ -416,14 +416,14 @@ internal sealed class AIFunctionMcpServerResource : McpServerResource
{
TextContent tc => new TextResourceContents
{
Uri = request.Params!.Uri,
Uri = request.Params.Uri,
MimeType = ProtocolResourceTemplate.MimeType,
Text = tc.Text
},
DataContent dc => new BlobResourceContents
{
Uri = request.Params!.Uri,
Uri = request.Params.Uri,
MimeType = dc.MediaType,
Blob = EncodingUtilities.GetUtf8Bytes(dc.Base64Data.Span)
},
@ -436,7 +436,7 @@ internal sealed class AIFunctionMcpServerResource : McpServerResource
{
Contents = strings.Select<string, ResourceContents>(text => new TextResourceContents
{
Uri = request.Params!.Uri,
Uri = request.Params.Uri,
MimeType = ProtocolResourceTemplate.MimeType,
Text = text
}).ToList(),

View file

@ -954,7 +954,7 @@ internal sealed partial class McpServerImpl : McpServer
// If a handler was provided, now delegate to it.
if (setLoggingLevelHandler is not null)
{
return InvokeHandlerAsync(setLoggingLevelHandler, request, jsonRpcRequest, cancellationToken);
return InvokeHandlerAsync(setLoggingLevelHandler, request!, jsonRpcRequest, cancellationToken);
}
// Otherwise, consider it handled.
@ -966,17 +966,17 @@ internal sealed partial class McpServerImpl : McpServer
private ValueTask<TResult> InvokeHandlerAsync<TParams, TResult>(
McpRequestHandler<TParams, TResult> handler,
TParams? args,
TParams args,
JsonRpcRequest jsonRpcRequest,
CancellationToken cancellationToken = default)
{
return _servicesScopePerRequest ?
InvokeScopedAsync(handler, args, jsonRpcRequest, cancellationToken) :
handler(new(new DestinationBoundMcpServer(this, jsonRpcRequest.Context?.RelatedTransport), jsonRpcRequest) { Params = args }, cancellationToken);
handler(new(new DestinationBoundMcpServer(this, jsonRpcRequest.Context?.RelatedTransport), jsonRpcRequest, args), cancellationToken);
async ValueTask<TResult> InvokeScopedAsync(
McpRequestHandler<TParams, TResult> handler,
TParams? args,
TParams args,
JsonRpcRequest jsonRpcRequest,
CancellationToken cancellationToken)
{
@ -984,10 +984,9 @@ internal sealed partial class McpServerImpl : McpServer
try
{
return await handler(
new RequestContext<TParams>(new DestinationBoundMcpServer(this, jsonRpcRequest.Context?.RelatedTransport), jsonRpcRequest)
new RequestContext<TParams>(new DestinationBoundMcpServer(this, jsonRpcRequest.Context?.RelatedTransport), jsonRpcRequest, args)
{
Services = scope?.ServiceProvider ?? Services,
Params = args
},
cancellationToken).ConfigureAwait(false);
}

View file

@ -13,19 +13,34 @@ namespace ModelContextProtocol.Server;
/// </remarks>
public sealed class RequestContext<TParams> : MessageContext
{
/// <summary>
/// Initializes a new instance of the <see cref="RequestContext{TParams}"/> class with the specified server, JSON-RPC request, and request parameters.
/// </summary>
/// <param name="server">The server with which this instance is associated.</param>
/// <param name="jsonRpcRequest">The JSON-RPC request associated with this context.</param>
/// <param name="parameters">The parameters associated with this request.</param>
/// <exception cref="ArgumentNullException"><paramref name="server"/> or <paramref name="jsonRpcRequest"/> is <see langword="null"/>.</exception>
public RequestContext(McpServer server, JsonRpcRequest jsonRpcRequest, TParams parameters)
: base(server, jsonRpcRequest)
{
Params = parameters;
}
/// <summary>
/// Initializes a new instance of the <see cref="RequestContext{TParams}"/> class with the specified server and JSON-RPC request.
/// </summary>
/// <param name="server">The server with which this instance is associated.</param>
/// <param name="jsonRpcRequest">The JSON-RPC request associated with this context.</param>
/// <exception cref="ArgumentNullException"><paramref name="server"/> or <paramref name="jsonRpcRequest"/> is <see langword="null"/>.</exception>
[Obsolete(Obsoletions.RequestContextParamsConstructor_Message, DiagnosticId = Obsoletions.RequestContextParamsConstructor_DiagnosticId, UrlFormat = Obsoletions.RequestContextParamsConstructor_Url)]
public RequestContext(McpServer server, JsonRpcRequest jsonRpcRequest)
: base(server, jsonRpcRequest)
{
Params = default!;
}
/// <summary>Gets or sets the parameters associated with this request.</summary>
public TParams? Params { get; set; }
public TParams Params { get; set; }
/// <summary>
/// Gets or sets the primitive that matched the request.