Extract Tasks into the ModelContextProtocol.Extensions.Tasks extension package (#1693)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Tarek Mahmoud Sayed <tarekms@ntdev.microsoft.com>
This commit is contained in:
Jeff Handley 2026-07-14 15:53:58 -07:00 • committed by GitHub
commit 2ca96f548b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 2559 additions and 1895 deletions

View file

@ -944,25 +944,17 @@ public abstract partial class McpClient : McpSession
McpJsonUtilities.JsonContext.Default.EmptyResult,
cancellationToken: cancellationToken).AsTask();
}
/// <summary>
/// Invokes a tool on the server.
/// </summary>
/// <param name="toolName">The name of the tool to call on the server.</param>
/// <param name="toolName">The name of the tool to invoke.</param>
/// <param name="arguments">An optional dictionary of arguments to pass to the tool.</param>
/// <param name="progress">An optional progress reporter for server notifications.</param>
/// <param name="progress">An optional progress handler for tracking operation progress.</param>
/// <param name="options">Optional request options including metadata, serialization settings, and progress tracking.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>The <see cref="CallToolResult"/> from the tool execution.</returns>
/// <returns>The result of the tool invocation.</returns>
/// <exception cref="ArgumentNullException"><paramref name="toolName"/> is <see langword="null"/>.</exception>
/// <exception cref="McpException">The request failed or the server returned an error response.</exception>
/// <remarks>
/// This overload supports the tasks extension transparently. If the server responds with a
/// task handle rather than an immediate result, this method polls <c>tasks/get</c> until the
/// task completes, dispatching any <see cref="McpTaskStatus.InputRequired"/> entries through
/// the client's registered sampling and elicitation handlers along the way. Use
/// <see cref="CallToolRawAsync"/> to disable automatic polling.
/// </remarks>
public ValueTask<CallToolResult> CallToolAsync(
string toolName,
IReadOnlyDictionary<string, object?>? arguments = null,
@ -1033,221 +1025,19 @@ public abstract partial class McpClient : McpSession
/// <returns>The result of the request.</returns>
/// <exception cref="ArgumentNullException"><paramref name="requestParams"/> is <see langword="null"/>.</exception>
/// <exception cref="McpException">The request failed or the server returned an error response.</exception>
/// <remarks>
/// This method automatically includes the <c>io.modelcontextprotocol/tasks</c> extension capability
/// in the request metadata. If the server returns a task handle instead of an immediate result,
/// this method transparently polls <c>tasks/get</c> until the task completes, fails, or is cancelled.
/// Use <see cref="CallToolRawAsync"/>
/// to receive the raw <see cref="ResultOrCreatedTask{TResult}"/> without automatic polling.
/// </remarks>
public async ValueTask<CallToolResult> CallToolAsync(
public ValueTask<CallToolResult> CallToolAsync(
CallToolRequestParams requestParams,
CancellationToken cancellationToken = default)
{
Throw.IfNull(requestParams);
var augmented = await CallToolRawAsync(requestParams, cancellationToken).ConfigureAwait(false);
if (!augmented.IsTask)
{
return augmented.Result!;
}
return await PollTaskToCompletionAsync(augmented.TaskCreated!, cancellationToken).ConfigureAwait(false);
return SendRequestAsync(
RequestMethods.ToolsCall,
requestParams,
McpJsonUtilities.JsonContext.Default.CallToolRequestParams,
McpJsonUtilities.JsonContext.Default.CallToolResult,
cancellationToken: cancellationToken);
}
/// <summary>
/// Polls a task until it reaches a terminal state and returns the final <see cref="CallToolResult"/>.
/// </summary>
private async ValueTask<CallToolResult> PollTaskToCompletionAsync(
CreateTaskResult taskCreated,
CancellationToken cancellationToken)
{
// If the server claims InputRequired but never publishes new input requests after we have
// already responded to everything it asked for, treat that as a stuck task. The client
// can still cancel earlier via cancellationToken; this guard prevents an unbounded poll
// loop when the server is misbehaving. The threshold is configurable via
// McpClientOptions.MaxConsecutiveStuckPolls.
int maxConsecutiveStuckPolls = MaxConsecutiveStuckPolls;
string taskId = taskCreated.TaskId;
long pollIntervalMs = taskCreated.PollIntervalMs ?? 1000;
HashSet<string>? resolvedRequestKeys = null;
bool isFirstPoll = true;
int consecutiveStuckPolls = 0;
while (true)
{
// Skip the delay before the first poll: many tasks complete almost immediately and we
// don't want to pay the poll interval as gratuitous latency.
if (!isFirstPoll)
{
await Task.Delay(TimeSpan.FromMilliseconds(pollIntervalMs), cancellationToken).ConfigureAwait(false);
}
isFirstPoll = false;
var taskResult = await GetTaskAsync(taskId, cancellationToken).ConfigureAwait(false);
// Update poll interval if the server changed it.
if (taskResult.PollIntervalMs is { } newInterval)
{
pollIntervalMs = newInterval;
}
switch (taskResult)
{
case CompletedTaskResult completed:
return JsonSerializer.Deserialize(completed.Result, McpJsonUtilities.JsonContext.Default.CallToolResult)
?? throw new JsonException("Failed to deserialize CallToolResult from completed task.");
case FailedTaskResult failed:
throw new McpException($"Task '{taskId}' failed: {failed.Error}");
case CancelledTaskResult:
throw new OperationCanceledException($"Task '{taskId}' was cancelled by the server.");
case InputRequiredTaskResult inputRequired:
// Dedup: only resolve input requests we haven't already responded to.
var newRequests = new Dictionary<string, InputRequest>();
if (inputRequired.InputRequests is { } incomingRequests)
{
foreach (var kvp in incomingRequests)
{
if (resolvedRequestKeys is null || !resolvedRequestKeys.Contains(kvp.Key))
{
newRequests[kvp.Key] = kvp.Value;
}
}
}
if (newRequests.Count > 0)
{
consecutiveStuckPolls = 0;
IDictionary<string, InputResponse> inputResponses;
try
{
inputResponses = await ResolveInputRequestsAsync(newRequests, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
throw;
}
catch
{
// The input handler failed (e.g., ElicitationHandler threw or no handler was registered).
// Best-effort cancel of the server-side task so it doesn't stay stuck in InputRequired
// until TTL expires.
try
{
await CancelTaskAsync(taskId, CancellationToken.None).ConfigureAwait(false);
}
catch
{
// Swallow secondary failures; we're already propagating the original exception.
}
throw;
}
await UpdateTaskAsync(new UpdateTaskRequestParams
{
TaskId = taskId,
InputResponses = inputResponses,
}, cancellationToken).ConfigureAwait(false);
resolvedRequestKeys ??= new HashSet<string>(StringComparer.Ordinal);
foreach (var key in inputResponses.Keys)
{
resolvedRequestKeys.Add(key);
}
}
else if (++consecutiveStuckPolls >= maxConsecutiveStuckPolls)
{
// Best-effort cancel of the server-side task so it doesn't leak until TTL expires.
try
{
await CancelTaskAsync(taskId, CancellationToken.None).ConfigureAwait(false);
}
catch
{
// Swallow secondary failures; we're already propagating an exception.
}
throw new McpException(
$"Task '{taskId}' has remained in '{McpTaskStatus.InputRequired}' for {maxConsecutiveStuckPolls} consecutive polls " +
"without publishing new input requests after all previously requested inputs were resolved.");
}
break;
case WorkingTaskResult:
// Continue polling.
consecutiveStuckPolls = 0;
break;
default:
throw new McpException(
$"Unexpected task result type '{taskResult.GetType().Name}' for task '{taskId}'.");
}
}
}
/// <summary>
/// Invokes a tool on the server with task extension support, returning the raw response
/// without automatic polling. The caller is responsible for handling task lifecycle.
/// </summary>
/// <param name="requestParams">The request parameters to send. The tasks extension capability will be injected into the request metadata.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A <see cref="ResultOrCreatedTask{TResult}"/> that is either an immediate result or a task handle.</returns>
/// <exception cref="ArgumentNullException"><paramref name="requestParams"/> is <see langword="null"/>.</exception>
/// <exception cref="McpException">The request failed or the server returned an error response.</exception>
/// <remarks>
/// <para>
/// Unlike <see cref="CallToolAsync(CallToolRequestParams, CancellationToken)"/>, this method does not
/// automatically poll for task completion. If the server returns a <see cref="CreateTaskResult"/>,
/// the caller must manage polling via <see cref="GetTaskAsync(string, CancellationToken)"/>.
/// </para>
/// </remarks>
public async ValueTask<ResultOrCreatedTask<CallToolResult>> CallToolRawAsync(
CallToolRequestParams requestParams,
CancellationToken cancellationToken = default)
{
Throw.IfNull(requestParams);
var paramsWithMeta = new CallToolRequestParams
{
Name = requestParams.Name,
Arguments = requestParams.Arguments,
// The SEP-2663 Tasks extension requires the 2026-07-28 or later protocol revision. On an older session, send a plain tools/call
// (no task capability envelope) so the server returns a direct CallToolResult and never
// creates a task.
Meta = IsJuly2026OrLaterProtocol() ? GetMetaWithTaskCapability(requestParams.Meta) : requestParams.Meta,
};
JsonRpcRequest jsonRpcRequest = new()
{
Method = RequestMethods.ToolsCall,
Params = JsonSerializer.SerializeToNode(paramsWithMeta, McpJsonUtilities.JsonContext.Default.CallToolRequestParams),
};
JsonRpcResponse response = await SendRequestAsync(jsonRpcRequest, cancellationToken).ConfigureAwait(false);
// Discriminate based on resultType field.
if (response.Result is JsonObject resultObj &&
resultObj.TryGetPropertyValue("resultType", out var resultTypeNode) &&
resultTypeNode?.GetValue<string>() == "task")
{
var taskCreated = resultObj.Deserialize(McpJsonUtilities.JsonContext.Default.CreateTaskResult)
?? throw new JsonException("Failed to deserialize CreateTaskResult from response.");
return new ResultOrCreatedTask<CallToolResult>(taskCreated);
}
var callToolResult = JsonSerializer.Deserialize(response.Result, McpJsonUtilities.JsonContext.Default.CallToolResult)
?? throw new JsonException("Failed to deserialize CallToolResult from response.");
return new ResultOrCreatedTask<CallToolResult>(callToolResult);
}
/// <summary>
/// Sets the logging level for the server to control which log messages are sent to the client.
/// </summary>
@ -1302,111 +1092,6 @@ public abstract partial class McpClient : McpSession
McpJsonUtilities.JsonContext.Default.EmptyResult,
cancellationToken: cancellationToken).AsTask();
}
/// <summary>
/// Retrieves the current state of a task from the server.
/// </summary>
/// <param name="taskId">The stable identifier of the task to retrieve.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A <see cref="GetTaskResult"/> subtype representing the current task state.</returns>
/// <exception cref="ArgumentNullException"><paramref name="taskId"/> is <see langword="null"/>.</exception>
/// <exception cref="McpException">The request failed or the server returned an error response.</exception>
public ValueTask<GetTaskResult> GetTaskAsync(
string taskId,
CancellationToken cancellationToken = default)
{
Throw.IfNull(taskId);
return GetTaskAsync(new GetTaskRequestParams { TaskId = taskId }, cancellationToken);
}
/// <summary>
/// Retrieves the current state of a task from the server.
/// </summary>
/// <param name="requestParams">The request parameters to send in the request.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A <see cref="GetTaskResult"/> subtype representing the current task state.</returns>
/// <exception cref="ArgumentNullException"><paramref name="requestParams"/> is <see langword="null"/>.</exception>
/// <exception cref="McpException">The request failed or the server returned an error response.</exception>
public ValueTask<GetTaskResult> GetTaskAsync(
GetTaskRequestParams requestParams,
CancellationToken cancellationToken = default)
{
Throw.IfNull(requestParams);
ThrowIfTasksNotSupported(nameof(GetTaskAsync));
return SendRequestAsync(
RequestMethods.TasksGet,
requestParams,
McpJsonUtilities.JsonContext.Default.GetTaskRequestParams,
McpJsonUtilities.JsonContext.Default.GetTaskResult,
cancellationToken: cancellationToken);
}
/// <summary>
/// Provides input responses to a task that is in the <see cref="McpTaskStatus.InputRequired"/> state.
/// </summary>
/// <param name="requestParams">The request parameters containing the task ID and input responses.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>The result acknowledging the update.</returns>
/// <exception cref="ArgumentNullException"><paramref name="requestParams"/> is <see langword="null"/>.</exception>
/// <exception cref="McpException">The request failed or the server returned an error response.</exception>
public ValueTask<UpdateTaskResult> UpdateTaskAsync(
UpdateTaskRequestParams requestParams,
CancellationToken cancellationToken = default)
{
Throw.IfNull(requestParams);
ThrowIfTasksNotSupported(nameof(UpdateTaskAsync));
return SendRequestAsync(
RequestMethods.TasksUpdate,
requestParams,
McpJsonUtilities.JsonContext.Default.UpdateTaskRequestParams,
McpJsonUtilities.JsonContext.Default.UpdateTaskResult,
cancellationToken: cancellationToken);
}
/// <summary>
/// Requests cancellation of an in-progress task on the server.
/// </summary>
/// <param name="taskId">The stable identifier of the task to cancel.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>The result acknowledging the cancellation request.</returns>
/// <exception cref="ArgumentNullException"><paramref name="taskId"/> is <see langword="null"/>.</exception>
/// <exception cref="McpException">The request failed or the server returned an error response.</exception>
public ValueTask<CancelTaskResult> CancelTaskAsync(
string taskId,
CancellationToken cancellationToken = default)
{
Throw.IfNull(taskId);
return CancelTaskAsync(new CancelTaskRequestParams { TaskId = taskId }, cancellationToken);
}
/// <summary>
/// Requests cancellation of an in-progress task on the server.
/// </summary>
/// <param name="requestParams">The request parameters to send in the request.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>The result acknowledging the cancellation request.</returns>
/// <exception cref="ArgumentNullException"><paramref name="requestParams"/> is <see langword="null"/>.</exception>
/// <exception cref="McpException">The request failed or the server returned an error response.</exception>
public ValueTask<CancelTaskResult> CancelTaskAsync(
CancelTaskRequestParams requestParams,
CancellationToken cancellationToken = default)
{
Throw.IfNull(requestParams);
ThrowIfTasksNotSupported(nameof(CancelTaskAsync));
return SendRequestAsync(
RequestMethods.TasksCancel,
requestParams,
McpJsonUtilities.JsonContext.Default.CancelTaskRequestParams,
McpJsonUtilities.JsonContext.Default.CancelTaskResult,
cancellationToken: cancellationToken);
}
/// <summary>Converts a dictionary with <see cref="object"/> values to a dictionary with <see cref="JsonElement"/> values.</summary>
private static Dictionary<string, JsonElement>? ToArgumentsDictionary(
IReadOnlyDictionary<string, object?>? arguments, JsonSerializerOptions options)
{
@ -1425,43 +1110,4 @@ public abstract partial class McpClient : McpSession
return result;
}
// Per SEP-2663 §51, the per-request opt-in uses the SEP-2575 capabilities envelope:
// _meta/io.modelcontextprotocol/clientCapabilities/extensions/io.modelcontextprotocol/tasks = {}
private static JsonObject GetMetaWithTaskCapability(JsonObject? existingMeta)
{
JsonObject meta = existingMeta is not null
? (JsonObject)existingMeta.DeepClone()
: [];
if (meta[MetaKeys.ClientCapabilities] is not JsonObject capsRoot)
{
capsRoot = [];
meta[MetaKeys.ClientCapabilities] = capsRoot;
}
if (capsRoot["extensions"] is not JsonObject extensionsRoot)
{
extensionsRoot = [];
capsRoot["extensions"] = extensionsRoot;
}
extensionsRoot.TryAdd(McpExtensions.Tasks, new JsonObject());
return meta;
}
/// <summary>
/// Throws when the negotiated protocol version does not support the SEP-2663 Tasks extension. Tasks
/// require the 2026-07-28 or later protocol revision, and a task id only ever exists when the session
/// negotiated such a revision, so invoking <c>tasks/get</c>, <c>tasks/update</c>, or <c>tasks/cancel</c>
/// on an older session is a programming error rather than a recoverable protocol condition.
/// </summary>
private void ThrowIfTasksNotSupported(string operationName)
{
if (!IsJuly2026OrLaterProtocol())
{
throw new InvalidOperationException(
$"'{operationName}' requires a newer protocol revision that supports tasks. " +
$"The negotiated protocol version is '{NegotiatedProtocolVersion ?? "(none)"}'.");
}
}
}

View file

@ -73,7 +73,7 @@ public abstract partial class McpClient : McpSession
public abstract Task<ClientCompletionDetails> Completion { get; }
/// <summary>
/// Resolves input requests embedded in an <see cref="InputRequiredTaskResult"/> by dispatching
/// Resolves input requests by dispatching
/// each request to the appropriate registered handler.
/// </summary>
/// <param name="inputRequests">
@ -82,16 +82,9 @@ public abstract partial class McpClient : McpSession
/// </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests.</param>
/// <returns>A dictionary of responses keyed by the same identifiers as the input requests.</returns>
private protected abstract ValueTask<IDictionary<string, InputResponse>> ResolveInputRequestsAsync(
public abstract ValueTask<IDictionary<string, InputResponse>> ResolveInputRequestsAsync(
IDictionary<string, InputRequest> inputRequests, CancellationToken cancellationToken);
/// <summary>
/// Gets the maximum number of consecutive stuck-in-<see cref="McpTaskStatus.InputRequired"/> polls
/// allowed by <see cref="PollTaskToCompletionAsync"/> before the client cancels and throws.
/// Sourced from <see cref="McpClientOptions.MaxConsecutiveStuckPolls"/>.
/// </summary>
private protected abstract int MaxConsecutiveStuckPolls { get; }
/// <summary>
/// Inspects a received cacheable result (<c>tools/list</c>, <c>prompts/list</c>, <c>resources/list</c>,
/// <c>resources/templates/list</c>, or <c>resources/read</c>) so derived clients can emit diagnostics.

View file

@ -179,10 +179,9 @@ internal sealed partial class McpClientImpl : McpClient
public override Task<ClientCompletionDetails> Completion => _sessionHandler.CompletionTask;
/// <inheritdoc/>
private protected override int MaxConsecutiveStuckPolls => _options.MaxConsecutiveStuckPolls;
/// <inheritdoc/>
private protected override async ValueTask<IDictionary<string, InputResponse>> ResolveInputRequestsAsync(
public override async ValueTask<IDictionary<string, InputResponse>> ResolveInputRequestsAsync(
IDictionary<string, InputRequest> inputRequests,
CancellationToken cancellationToken)
{

View file

@ -151,41 +151,4 @@ public sealed class McpClientOptions
}
}
/// <summary>
/// Gets or sets the maximum number of consecutive task polls during which a task may report
/// <see cref="McpTaskStatus.InputRequired"/> without publishing any new input requests, before
/// the client treats the task as stuck, issues a best-effort <c>tasks/cancel</c>, and throws
/// an <see cref="McpException"/>.
/// </summary>
/// <value>
/// The maximum number of consecutive stuck polls allowed. The default value is <c>60</c>.
/// </value>
/// <remarks>
/// <para>
/// This guard prevents an unbounded poll loop when the server keeps a task in
/// <see cref="McpTaskStatus.InputRequired"/> but never publishes new input requests after the
/// client has already responded to every previously surfaced request. It only affects the
/// long-poll path used by <see cref="McpClient.CallToolAsync(CallToolRequestParams, CancellationToken)"/>;
/// it does not affect direct <see cref="McpClient.GetTaskAsync(string, CancellationToken)"/> calls.
/// </para>
/// <para>
/// Callers should size this value with the configured server-side poll interval in mind: the
/// effective wall-clock timeout is roughly <c>MaxConsecutiveStuckPolls * pollIntervalMs</c>.
/// Setting this to a very small value can cause false positives for servers that are slow to
/// surface follow-up input requests; setting it too large can mask misbehaving servers.
/// </para>
/// </remarks>
/// <exception cref="ArgumentOutOfRangeException">The value is less than <c>1</c>.</exception>
public int MaxConsecutiveStuckPolls
{
get;
set
{
if (value < 1)
{
throw new ArgumentOutOfRangeException(nameof(value), value, "must be greater than or equal to 1.");
}
field = value;
}
} = 60;
}

View file

@ -57,6 +57,13 @@
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.CreateTaskResult</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
@ -71,6 +78,20 @@
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.GetTaskRequestParams</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.GetTaskResult</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
@ -113,6 +134,13 @@
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.McpTaskStatus</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
@ -211,6 +239,13 @@
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.CreateTaskResult</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
@ -225,6 +260,20 @@
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.GetTaskRequestParams</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.GetTaskResult</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
@ -267,6 +316,13 @@
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.McpTaskStatus</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
@ -365,6 +421,13 @@
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.CreateTaskResult</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
@ -379,6 +442,20 @@
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.GetTaskRequestParams</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.GetTaskResult</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
@ -421,6 +498,13 @@
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.McpTaskStatus</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
@ -519,6 +603,13 @@
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.CreateTaskResult</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
@ -533,6 +624,20 @@
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.GetTaskRequestParams</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.GetTaskResult</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
@ -575,6 +680,13 @@
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.McpTaskStatus</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0001</DiagnosticId>
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
@ -624,6 +736,27 @@
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.NotificationMethods.TaskStatusNotification</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksCancel</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksGet</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
@ -785,20 +918,6 @@
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.CreateTaskResult.get_Task</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.CreateTaskResult.set_Task(ModelContextProtocol.Protocol.McpTask)</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
@ -813,34 +932,6 @@
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.#ctor</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.get_PollInterval</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.set_PollInterval(System.Nullable{System.TimeSpan})</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.set_Status(ModelContextProtocol.Protocol.McpTaskStatus)</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
@ -960,6 +1051,13 @@
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Server.McpServerOptions.set_TaskStore(ModelContextProtocol.IMcpTaskStore)</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
@ -995,6 +1093,27 @@
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.NotificationMethods.TaskStatusNotification</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksCancel</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksGet</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
@ -1156,20 +1275,6 @@
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.CreateTaskResult.get_Task</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.CreateTaskResult.set_Task(ModelContextProtocol.Protocol.McpTask)</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
@ -1184,34 +1289,6 @@
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.#ctor</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.get_PollInterval</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.set_PollInterval(System.Nullable{System.TimeSpan})</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.set_Status(ModelContextProtocol.Protocol.McpTaskStatus)</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
@ -1331,6 +1408,13 @@
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Server.McpServerOptions.set_TaskStore(ModelContextProtocol.IMcpTaskStore)</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
@ -1366,6 +1450,27 @@
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.NotificationMethods.TaskStatusNotification</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksCancel</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksGet</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
@ -1527,20 +1632,6 @@
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.CreateTaskResult.get_Task</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.CreateTaskResult.set_Task(ModelContextProtocol.Protocol.McpTask)</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
@ -1555,34 +1646,6 @@
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.#ctor</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.get_PollInterval</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.set_PollInterval(System.Nullable{System.TimeSpan})</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.set_Status(ModelContextProtocol.Protocol.McpTaskStatus)</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
@ -1702,6 +1765,13 @@
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Server.McpServerOptions.set_TaskStore(ModelContextProtocol.IMcpTaskStore)</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
@ -1737,6 +1807,27 @@
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.NotificationMethods.TaskStatusNotification</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksCancel</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksGet</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
@ -1898,20 +1989,6 @@
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.CreateTaskResult.get_Task</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.CreateTaskResult.set_Task(ModelContextProtocol.Protocol.McpTask)</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
@ -1926,34 +2003,6 @@
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.#ctor</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.get_PollInterval</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.set_PollInterval(System.Nullable{System.TimeSpan})</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.GetTaskResult.set_Status(ModelContextProtocol.Protocol.McpTaskStatus)</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
@ -2073,6 +2122,13 @@
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Server.McpServerOptions.set_TaskStore(ModelContextProtocol.IMcpTaskStore)</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
@ -2102,57 +2158,29 @@
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0011</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Cancelled</Target>
<DiagnosticId>CP0005</DiagnosticId>
<Target>M:ModelContextProtocol.Client.McpClient.ResolveInputRequestsAsync(System.Collections.Generic.IDictionary{System.String,ModelContextProtocol.Protocol.InputRequest},System.Threading.CancellationToken)</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0011</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Failed</Target>
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0011</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Cancelled</Target>
<DiagnosticId>CP0005</DiagnosticId>
<Target>M:ModelContextProtocol.Client.McpClient.ResolveInputRequestsAsync(System.Collections.Generic.IDictionary{System.String,ModelContextProtocol.Protocol.InputRequest},System.Threading.CancellationToken)</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0011</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Failed</Target>
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0011</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Cancelled</Target>
<DiagnosticId>CP0005</DiagnosticId>
<Target>M:ModelContextProtocol.Client.McpClient.ResolveInputRequestsAsync(System.Collections.Generic.IDictionary{System.String,ModelContextProtocol.Protocol.InputRequest},System.Threading.CancellationToken)</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0011</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Failed</Target>
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0011</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Cancelled</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0011</DiagnosticId>
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Failed</Target>
<DiagnosticId>CP0005</DiagnosticId>
<Target>M:ModelContextProtocol.Client.McpClient.ResolveInputRequestsAsync(System.Collections.Generic.IDictionary{System.String,ModelContextProtocol.Protocol.InputRequest},System.Threading.CancellationToken)</Target>
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>

View file

@ -54,7 +54,13 @@ public static partial class McpJsonUtilities
return options;
}
internal static JsonTypeInfo<T> GetTypeInfo<T>(this JsonSerializerOptions options) =>
/// <summary>
/// Gets the resolved <see cref="JsonTypeInfo{T}"/> for <typeparamref name="T"/> from the specified options.
/// </summary>
/// <typeparam name="T">The type whose serialization metadata should be resolved.</typeparam>
/// <param name="options">The serializer options providing the type-info resolver chain.</param>
/// <returns>The resolved <see cref="JsonTypeInfo{T}"/>.</returns>
public static JsonTypeInfo<T> GetTypeInfo<T>(this JsonSerializerOptions options) =>
(JsonTypeInfo<T>)options.GetTypeInfo(typeof(T));
internal static JsonElement DefaultMcpToolSchema { get; } = ParseJsonElement("""{"type":"object"}"""u8);
@ -120,12 +126,6 @@ public static partial class McpJsonUtilities
[JsonSerializable(typeof(ResourceUpdatedNotificationParams))]
[JsonSerializable(typeof(RootsListChangedNotificationParams))]
[JsonSerializable(typeof(ToolListChangedNotificationParams))]
[JsonSerializable(typeof(TaskStatusNotificationParams))]
[JsonSerializable(typeof(WorkingTaskNotificationParams))]
[JsonSerializable(typeof(CompletedTaskNotificationParams))]
[JsonSerializable(typeof(FailedTaskNotificationParams))]
[JsonSerializable(typeof(CancelledTaskNotificationParams))]
[JsonSerializable(typeof(InputRequiredTaskNotificationParams))]
// MCP Request Params / Results
[JsonSerializable(typeof(CallToolRequestParams))]
@ -174,19 +174,6 @@ public static partial class McpJsonUtilities
[JsonSerializable(typeof(IDictionary<string, InputRequest>))]
[JsonSerializable(typeof(IDictionary<string, InputResponse>))]
[JsonSerializable(typeof(GetTaskRequestParams))]
[JsonSerializable(typeof(GetTaskResult))]
[JsonSerializable(typeof(WorkingTaskResult))]
[JsonSerializable(typeof(CompletedTaskResult))]
[JsonSerializable(typeof(FailedTaskResult))]
[JsonSerializable(typeof(CancelledTaskResult))]
[JsonSerializable(typeof(InputRequiredTaskResult))]
[JsonSerializable(typeof(UpdateTaskRequestParams))]
[JsonSerializable(typeof(UpdateTaskResult))]
[JsonSerializable(typeof(CancelTaskRequestParams))]
[JsonSerializable(typeof(CancelTaskResult))]
[JsonSerializable(typeof(CreateTaskResult))]
// MCP Content
[JsonSerializable(typeof(ContentBlock))]
[JsonSerializable(typeof(TextContentBlock))]

View file

@ -1,29 +0,0 @@
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol;
/// <summary>
/// Represents the parameters for a <c>tasks/cancel</c> request to signal intent to cancel an in-progress task.
/// </summary>
/// <remarks>
/// <para>
/// Cancellation is cooperative: the request signals intent, and the server decides whether and when to honor it.
/// A server is not obligated to actually stop the work; it is only obligated to acknowledge the request.
/// Eventual transition to <see cref="McpTaskStatus.Cancelled"/> is not guaranteed.
/// </para>
/// <para>
/// The <c>notifications/cancelled</c> notification must not be used for task cancellation.
/// </para>
/// <para>
/// See the <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </para>
/// </remarks>
public sealed class CancelTaskRequestParams : RequestParams
{
/// <summary>
/// Gets or sets the identifier of the task to cancel.
/// </summary>
[JsonPropertyName("taskId")]
public required string TaskId { get; set; }
}

View file

@ -1,22 +0,0 @@
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol;
/// <summary>
/// Represents the result of a <c>tasks/cancel</c> request. This is an empty acknowledgement.
/// </summary>
/// <remarks>
/// <para>
/// The server acknowledges the request with an empty result. Cancellation processing is
/// eventually consistent — the task's observable status may remain <see cref="McpTaskStatus.Working"/>
/// after the ack, and may ultimately reach a terminal status other than <see cref="McpTaskStatus.Cancelled"/>
/// if the work finished before cancellation could take effect.
/// </para>
/// <para>
/// See the <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </para>
/// </remarks>
public sealed class CancelTaskResult : Result
{
}

View file

@ -1,69 +0,0 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol;
/// <summary>
/// Represents the result returned by a server when it creates a task in lieu of a standard result.
/// </summary>
/// <remarks>
/// <para>
/// A server returns <see cref="CreateTaskResult"/> instead of the standard result shape (e.g., <see cref="CallToolResult"/>)
/// to indicate that the request will be processed asynchronously. The client then uses
/// <see cref="TaskId"/> for subsequent <c>tasks/get</c>, <c>tasks/update</c>, and <c>tasks/cancel</c> calls.
/// </para>
/// <para>
/// A server must not return <see cref="CreateTaskResult"/> to a client that did not include the
/// <c>io.modelcontextprotocol/tasks</c> extension capability on its request.
/// </para>
/// <para>
/// See the <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </para>
/// </remarks>
public sealed class CreateTaskResult : Result
{
/// <summary>
/// Gets or sets the stable identifier for this task.
/// </summary>
[JsonPropertyName("taskId")]
public required string TaskId { get; set; }
/// <summary>
/// Gets or sets the current task status.
/// </summary>
[JsonPropertyName("status")]
public required McpTaskStatus Status { get; set; }
/// <summary>
/// Gets or sets an optional message describing the current task state.
/// </summary>
[JsonPropertyName("statusMessage")]
public string? StatusMessage { get; set; }
/// <summary>
/// Gets or sets the ISO 8601 timestamp when the task was created.
/// </summary>
[JsonPropertyName("createdAt")]
public required DateTimeOffset CreatedAt { get; set; }
/// <summary>
/// Gets or sets the ISO 8601 timestamp when the task was last updated.
/// </summary>
[JsonPropertyName("lastUpdatedAt")]
public required DateTimeOffset LastUpdatedAt { get; set; }
/// <summary>
/// Gets or sets the time-to-live duration from creation, or <see langword="null"/> for unlimited.
/// </summary>
[JsonPropertyName("ttlMs")]
[JsonConverter(typeof(TimeSpanMillisecondsConverter))]
public TimeSpan? TimeToLive { get; set; }
/// <summary>
/// Gets or sets the suggested polling interval in milliseconds.
/// </summary>
[JsonPropertyName("pollIntervalMs")]
public long? PollIntervalMs { get; set; }
}

View file

@ -1,26 +0,0 @@
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol;
/// <summary>
/// Represents the parameters for a <c>tasks/get</c> request to poll for task completion.
/// </summary>
/// <remarks>
/// <para>
/// Clients poll for task completion by sending <c>tasks/get</c> requests.
/// Clients should respect the <see cref="GetTaskResult.PollIntervalMs"/> provided in responses
/// when determining polling frequency.
/// </para>
/// <para>
/// See the <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </para>
/// </remarks>
public sealed class GetTaskRequestParams : RequestParams
{
/// <summary>
/// Gets or sets the identifier of the task to query.
/// </summary>
[JsonPropertyName("taskId")]
public required string TaskId { get; set; }
}

View file

@ -1,450 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol;
/// <summary>
/// Represents the result of a <c>tasks/get</c> request, containing the full task state.
/// </summary>
/// <remarks>
/// <para>
/// This is the abstract base for status-specific task results. The concrete type returned depends on the
/// task's current <see cref="Status"/>:
/// <list type="bullet">
/// <item><see cref="WorkingTaskResult"/> — <see cref="McpTaskStatus.Working"/></item>
/// <item><see cref="CompletedTaskResult"/> — <see cref="McpTaskStatus.Completed"/></item>
/// <item><see cref="FailedTaskResult"/> — <see cref="McpTaskStatus.Failed"/></item>
/// <item><see cref="CancelledTaskResult"/> — <see cref="McpTaskStatus.Cancelled"/></item>
/// <item><see cref="InputRequiredTaskResult"/> — <see cref="McpTaskStatus.InputRequired"/></item>
/// </list>
/// </para>
/// <para>
/// See the <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </para>
/// </remarks>
[JsonConverter(typeof(Converter))]
public abstract class GetTaskResult : Result
{
/// <summary>Prevent external derivations.</summary>
private protected GetTaskResult()
{
}
/// <summary>
/// Gets or sets the stable identifier for this task.
/// </summary>
[JsonPropertyName("taskId")]
public required string TaskId { get; set; }
/// <summary>
/// Gets or sets the current task status.
/// </summary>
[JsonPropertyName("status")]
public abstract McpTaskStatus Status { get; }
/// <summary>
/// Gets or sets an optional message describing the current task state.
/// </summary>
[JsonPropertyName("statusMessage")]
public string? StatusMessage { get; set; }
/// <summary>
/// Gets or sets the ISO 8601 timestamp when the task was created.
/// </summary>
[JsonPropertyName("createdAt")]
public required DateTimeOffset CreatedAt { get; set; }
/// <summary>
/// Gets or sets the ISO 8601 timestamp when the task was last updated.
/// </summary>
[JsonPropertyName("lastUpdatedAt")]
public required DateTimeOffset LastUpdatedAt { get; set; }
/// <summary>
/// Gets or sets the time-to-live duration from creation, or <see langword="null"/> for unlimited.
/// </summary>
[JsonPropertyName("ttlMs")]
public TimeSpan? TimeToLive { get; set; }
/// <summary>
/// Gets or sets the suggested polling interval in milliseconds.
/// </summary>
[JsonPropertyName("pollIntervalMs")]
public long? PollIntervalMs { get; set; }
/// <summary>
/// JSON converter that deserializes <see cref="GetTaskResult"/> to the appropriate concrete subtype
/// based on the <c>status</c> discriminator field.
/// </summary>
internal sealed class Converter : JsonConverter<GetTaskResult>
{
public override GetTaskResult? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException("Expected StartObject token for GetTaskResult.");
}
string? taskId = null;
string? statusString = null;
string? statusMessage = null;
DateTimeOffset? createdAt = null;
DateTimeOffset? lastUpdatedAt = null;
long? ttlMs = null;
long? pollIntervalMs = null;
string? resultType = null;
JsonObject? meta = null;
JsonElement? result = null;
JsonElement? error = null;
Dictionary<string, InputRequest>? inputRequests = null;
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
break;
}
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException("Expected property name.");
}
string propertyName = reader.GetString()!;
reader.Read();
switch (propertyName)
{
case "taskId":
taskId = reader.GetString();
break;
case "status":
statusString = reader.GetString();
break;
case "statusMessage":
statusMessage = reader.GetString();
break;
case "createdAt":
createdAt = reader.GetDateTimeOffset();
break;
case "lastUpdatedAt":
lastUpdatedAt = reader.GetDateTimeOffset();
break;
case "ttlMs":
ttlMs = reader.GetInt64();
break;
case "pollIntervalMs":
pollIntervalMs = reader.GetInt64();
break;
case "resultType":
resultType = reader.GetString();
break;
case "_meta":
meta = JsonSerializer.Deserialize(ref reader, options.GetTypeInfo<JsonObject>());
break;
case "result":
result = JsonElement.ParseValue(ref reader);
break;
case "error":
error = JsonElement.ParseValue(ref reader);
break;
case "inputRequests":
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException("'inputRequests' must be a JSON object.");
}
inputRequests = new Dictionary<string, InputRequest>(StringComparer.Ordinal);
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
break;
}
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException("Expected property name in 'inputRequests'.");
}
string requestKey = reader.GetString()!;
reader.Read();
var inputRequest = JsonSerializer.Deserialize(ref reader, McpJsonUtilities.JsonContext.Default.InputRequest)
?? throw new JsonException($"Failed to deserialize InputRequest for key '{requestKey}'.");
inputRequests[requestKey] = inputRequest;
}
break;
default:
reader.Skip();
break;
}
}
if (taskId is null)
{
throw new JsonException("Missing required 'taskId' property on GetTaskResult.");
}
if (statusString is null)
{
throw new JsonException("Missing required 'status' property on GetTaskResult.");
}
if (createdAt is null)
{
throw new JsonException("Missing required 'createdAt' property on GetTaskResult.");
}
if (lastUpdatedAt is null)
{
throw new JsonException("Missing required 'lastUpdatedAt' property on GetTaskResult.");
}
GetTaskResult taskResult = statusString switch
{
"working" => new WorkingTaskResult
{
TaskId = taskId,
CreatedAt = createdAt.Value,
LastUpdatedAt = lastUpdatedAt.Value,
},
"completed" => result is not null
? new CompletedTaskResult
{
TaskId = taskId,
CreatedAt = createdAt.Value,
LastUpdatedAt = lastUpdatedAt.Value,
Result = result.Value,
}
: throw new JsonException("Completed task is missing required 'result' property."),
"failed" => error is not null
? new FailedTaskResult
{
TaskId = taskId,
CreatedAt = createdAt.Value,
LastUpdatedAt = lastUpdatedAt.Value,
Error = error.Value,
}
: throw new JsonException("Failed task is missing required 'error' property."),
"cancelled" => new CancelledTaskResult
{
TaskId = taskId,
CreatedAt = createdAt.Value,
LastUpdatedAt = lastUpdatedAt.Value,
},
"input_required" => inputRequests is not null
? new InputRequiredTaskResult
{
TaskId = taskId,
CreatedAt = createdAt.Value,
LastUpdatedAt = lastUpdatedAt.Value,
InputRequests = inputRequests,
}
: throw new JsonException("Input-required task is missing required 'inputRequests' property."),
_ => throw new JsonException($"Unknown task status: '{statusString}'.")
};
taskResult.StatusMessage = statusMessage;
taskResult.TimeToLive = ttlMs is null ? null : TimeSpan.FromMilliseconds(ttlMs.Value);
taskResult.PollIntervalMs = pollIntervalMs;
taskResult.ResultType = resultType;
taskResult.Meta = meta;
return taskResult;
}
public override void Write(Utf8JsonWriter writer, GetTaskResult value, JsonSerializerOptions options)
{
writer.WriteStartObject();
if (value.ResultType is not null)
{
writer.WriteString("resultType", value.ResultType);
}
if (value.Meta is not null)
{
writer.WritePropertyName("_meta");
JsonSerializer.Serialize(writer, value.Meta, options.GetTypeInfo<JsonObject>());
}
writer.WriteString("taskId", value.TaskId);
writer.WriteString("status", value.Status switch
{
McpTaskStatus.Working => "working",
McpTaskStatus.Completed => "completed",
McpTaskStatus.Failed => "failed",
McpTaskStatus.Cancelled => "cancelled",
McpTaskStatus.InputRequired => "input_required",
_ => throw new JsonException($"Unknown McpTaskStatus: {value.Status}")
});
if (value.StatusMessage is not null)
{
writer.WriteString("statusMessage", value.StatusMessage);
}
writer.WriteString("createdAt", value.CreatedAt);
writer.WriteString("lastUpdatedAt", value.LastUpdatedAt);
if (value.TimeToLive is not null)
{
writer.WriteNumber("ttlMs", (long)value.TimeToLive.Value.TotalMilliseconds);
}
if (value.PollIntervalMs is not null)
{
writer.WriteNumber("pollIntervalMs", value.PollIntervalMs.Value);
}
switch (value)
{
case CompletedTaskResult completed:
writer.WritePropertyName("result");
completed.Result.WriteTo(writer);
break;
case FailedTaskResult failed:
writer.WritePropertyName("error");
failed.Error.WriteTo(writer);
break;
case InputRequiredTaskResult inputRequired:
writer.WritePropertyName("inputRequests");
writer.WriteStartObject();
if (inputRequired.InputRequests is { } reqs)
{
foreach (var kvp in reqs)
{
writer.WritePropertyName(kvp.Key);
JsonSerializer.Serialize(writer, kvp.Value, McpJsonUtilities.JsonContext.Default.InputRequest);
}
}
writer.WriteEndObject();
break;
}
writer.WriteEndObject();
}
}
}
/// <summary>
/// Represents a task that is currently being processed by the server.
/// </summary>
/// <remarks>
/// See the <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </remarks>
public sealed class WorkingTaskResult : GetTaskResult
{
/// <inheritdoc/>
[JsonPropertyName("status")]
public override McpTaskStatus Status => McpTaskStatus.Working;
}
/// <summary>
/// Represents a task that has completed successfully, carrying the final result.
/// </summary>
/// <remarks>
/// <para>
/// The <see cref="Result"/> field contains the result structure matching the original request type.
/// For example, a <c>tools/call</c> task would contain the <see cref="CallToolResult"/> structure.
/// This includes tool calls that returned results with <c>isError: true</c>.
/// </para>
/// <para>
/// See the <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </para>
/// </remarks>
public sealed class CompletedTaskResult : GetTaskResult
{
/// <inheritdoc/>
[JsonPropertyName("status")]
public override McpTaskStatus Status => McpTaskStatus.Completed;
/// <summary>
/// Gets or sets the final result of the task as raw JSON.
/// </summary>
/// <remarks>
/// The structure matches the result type of the original request.
/// </remarks>
[JsonPropertyName("result")]
public required JsonElement Result { get; set; }
}
/// <summary>
/// Represents a task that failed due to a JSON-RPC error during execution.
/// </summary>
/// <remarks>
/// <para>
/// The <see cref="Error"/> field contains the JSON-RPC error object that caused the failure.
/// This status must not be used for non-JSON-RPC errors.
/// </para>
/// <para>
/// See the <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </para>
/// </remarks>
public sealed class FailedTaskResult : GetTaskResult
{
/// <inheritdoc/>
[JsonPropertyName("status")]
public override McpTaskStatus Status => McpTaskStatus.Failed;
/// <summary>
/// Gets or sets the JSON-RPC error that caused the task to fail.
/// </summary>
[JsonPropertyName("error")]
public required JsonElement Error { get; set; }
}
/// <summary>
/// Represents a task that was cancelled before completion.
/// </summary>
/// <remarks>
/// See the <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </remarks>
public sealed class CancelledTaskResult : GetTaskResult
{
/// <inheritdoc/>
[JsonPropertyName("status")]
public override McpTaskStatus Status => McpTaskStatus.Cancelled;
}
/// <summary>
/// Represents a task that requires input from the client before it can proceed.
/// </summary>
/// <remarks>
/// <para>
/// The <see cref="InputRequests"/> field contains outstanding server-to-client requests
/// that the client must fulfil. Each entry is keyed by an arbitrary identifier for matching
/// requests to responses, and each value is an <see cref="InputRequest"/> wrapping the
/// server-to-client request payload.
/// </para>
/// <para>
/// Clients must treat each entry as they would the equivalent standalone server-to-client request.
/// Clients should deduplicate keys across consecutive polls to avoid presenting the same request
/// to the user or model more than once.
/// </para>
/// <para>
/// See the <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </para>
/// </remarks>
public sealed class InputRequiredTaskResult : GetTaskResult
{
/// <inheritdoc/>
[JsonPropertyName("status")]
public override McpTaskStatus Status => McpTaskStatus.InputRequired;
/// <summary>
/// Gets or sets the server-to-client requests that need to be fulfilled.
/// </summary>
/// <remarks>
/// Keys are arbitrary identifiers for matching requests to responses.
/// Each value is an <see cref="InputRequest"/> wrapping the server-to-client request
/// (e.g., a sampling, elicitation, or roots-list request).
/// </remarks>
[JsonPropertyName("inputRequests")]
public IDictionary<string, InputRequest>? InputRequests { get; set; }
}

View file

@ -1,18 +0,0 @@
namespace ModelContextProtocol.Protocol;
/// <summary>
/// Provides constants for well-known MCP extension identifiers.
/// </summary>
public static class McpExtensions
{
/// <summary>
/// The extension identifier for the MCP Tasks extension.
/// </summary>
/// <remarks>
/// When included in client per-request capabilities, indicates the client can handle
/// <see cref="CreateTaskResult"/> in lieu of a standard result.
/// See the <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </remarks>
public const string Tasks = "io.modelcontextprotocol/tasks";
}

View file

@ -1,49 +0,0 @@
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol;
/// <summary>
/// Represents the status of an MCP task.
/// </summary>
/// <remarks>
/// Tasks are durable state machines that carry information about the underlying execution state
/// of the request they augment. See the
/// <see href="https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/seps/2663-tasks-extension.md">SEP-2663</see>
/// specification for details.
/// </remarks>
[JsonConverter(typeof(JsonStringEnumConverter<McpTaskStatus>))]
public enum McpTaskStatus
{
/// <summary>
/// The request is currently being processed.
/// </summary>
[JsonStringEnumMemberName("working")]
Working,
/// <summary>
/// The server needs input from the client before the task can proceed.
/// The <c>tasks/get</c> response will include outstanding requests in the <c>inputRequests</c> field.
/// </summary>
[JsonStringEnumMemberName("input_required")]
InputRequired,
/// <summary>
/// The request completed successfully and results are available.
/// This includes tool calls that returned results with <c>isError: true</c>.
/// </summary>
[JsonStringEnumMemberName("completed")]
Completed,
/// <summary>
/// The request was cancelled before completion.
/// </summary>
[JsonStringEnumMemberName("cancelled")]
Cancelled,
/// <summary>
/// The request failed due to a JSON-RPC error during execution.
/// This status must not be used for non-JSON-RPC errors.
/// </summary>
[JsonStringEnumMemberName("failed")]
Failed,
}

View file

@ -53,24 +53,4 @@ public static class MetaKeys
/// belonging to different subscriptions on a shared channel (especially STDIO).
/// </remarks>
public const string SubscriptionId = "io.modelcontextprotocol/subscriptionId";
/// <summary>
/// The metadata key used to associate requests, responses, and notifications with a task.
/// </summary>
/// <remarks>
/// <para>
/// This constant defines the key <c>"io.modelcontextprotocol/related-task"</c> used in the
/// <c>_meta</c> field to associate messages with their originating task across the entire
/// request lifecycle.
/// </para>
/// <para>
/// For example, an elicitation that a task-augmented tool call depends on must share the
/// same related task ID with that tool call's task.
/// </para>
/// <para>
/// For <c>tasks/get</c>, <c>tasks/list</c>, and <c>tasks/cancel</c> operations, this
/// metadata should not be included as the taskId is already present in the message structure.
/// </para>
/// </remarks>
public const string RelatedTask = "io.modelcontextprotocol/related-task";
}

View file

@ -144,16 +144,6 @@ public static class NotificationMethods
/// </remarks>
public const string CancelledNotification = "notifications/cancelled";
/// <summary>
/// The name of the notification sent by the server to push task status updates to subscribed clients.
/// </summary>
/// <remarks>
/// Part of the <c>io.modelcontextprotocol/tasks</c> extension.
/// Each notification carries a complete task state for the current status, identical to what
/// <c>tasks/get</c> would have returned at that moment.
/// </remarks>
public const string TaskStatusNotification = "notifications/tasks/status";
/// <summary>
/// The name of the notification sent first on a <see cref="RequestMethods.SubscriptionsListen"/>
/// response stream to indicate which notification types the server agreed to deliver.

View file

@ -8,8 +8,8 @@ namespace ModelContextProtocol.Protocol;
/// </summary>
public abstract class NotificationParams
{
/// <summary>Prevent external derivations.</summary>
private protected NotificationParams()
/// <summary>Initializes the base notification parameter type.</summary>
protected NotificationParams()
{
}

View file

@ -125,33 +125,6 @@ public static class RequestMethods
/// </remarks>
public const string Initialize = "initialize";
/// <summary>
/// The name of the request method sent from the client to poll for task completion.
/// </summary>
/// <remarks>
/// Part of the <c>io.modelcontextprotocol/tasks</c> extension.
/// Clients poll for task status by sending this request with the task ID.
/// </remarks>
public const string TasksGet = "tasks/get";
/// <summary>
/// The name of the request method sent from the client to provide input responses to a task.
/// </summary>
/// <remarks>
/// Part of the <c>io.modelcontextprotocol/tasks</c> extension.
/// Used when a task has <c>input_required</c> status and the client needs to fulfill outstanding requests.
/// </remarks>
public const string TasksUpdate = "tasks/update";
/// <summary>
/// The name of the request method sent from the client to signal intent to cancel a task.
/// </summary>
/// <remarks>
/// Part of the <c>io.modelcontextprotocol/tasks</c> extension.
/// Cancellation is cooperative — the server decides whether and when to honor it.
/// </remarks>
public const string TasksCancel = "tasks/cancel";
/// <summary>
/// The name of the request method sent from the client to discover the server's protocol versions,
/// capabilities, and metadata.

View file

@ -11,8 +11,8 @@ namespace ModelContextProtocol.Protocol;
/// </remarks>
public abstract class RequestParams
{
/// <summary>Prevent external derivations.</summary>
private protected RequestParams()
/// <summary>Initializes the base request parameter type.</summary>
protected RequestParams()
{
}

View file

@ -8,8 +8,8 @@ namespace ModelContextProtocol.Protocol;
/// </summary>
public abstract class Result
{
/// <summary>Prevent external derivations.</summary>
private protected Result()
/// <summary>Initializes the base result type.</summary>
protected Result()
{
}
@ -27,11 +27,9 @@ public abstract class Result
/// </summary>
/// <remarks>
/// <para>
/// When set to <c>"complete"</c>, the result is a normal completed response.
/// When set to <c>"input_required"</c>, the result is an <see cref="InputRequiredResult"/> indicating
/// that additional input is needed before the request can be completed.
/// When set to <c>"task"</c>, the result is a <see cref="CreateTaskResult"/> indicating that the server
/// has created a long-running task in lieu of returning the result directly.
/// When absent or set to <c>"complete"</c>, the result is a normal completed response.
/// Other values discriminate alternate result subtypes so callers can choose the appropriate
/// concrete payload to deserialize.
/// </para>
/// </remarks>
/// <value>Defaults to <see langword="null"/>, which is equivalent to <c>"complete"</c>.</value>

View file

@ -0,0 +1,95 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization.Metadata;
namespace ModelContextProtocol.Protocol;
/// <summary>
/// Represents the result of a request that may return either the standard result or an alternate
/// <see cref="Result"/> subtype for scenarios like asynchronous task execution.
/// </summary>
/// <typeparam name="TResult">The standard result type for the request (e.g., <see cref="CallToolResult"/>).</typeparam>
/// <remarks>
/// <para>
/// Extensions that augment request handling (such as the Tasks extension) use this type to indicate
/// that the server returned an alternate result instead of the normal one. The alternate carries its
/// own <see cref="JsonTypeInfo"/> so the transport layer can serialize it without compile-time knowledge
/// of the concrete type.
/// </para>
/// <para>
/// Use <see cref="IsAlternate"/> to determine which variant was returned, then access either
/// <see cref="Result"/> for the immediate result or <see cref="Alternate"/> for the alternate.
/// </para>
/// </remarks>
[Experimental(Experimentals.Subclassing_DiagnosticId, UrlFormat = Experimentals.Subclassing_Url)]
public class ResultOrAlternate<TResult> where TResult : Result
{
private readonly TResult? _result;
private readonly Result? _alternate;
private readonly JsonTypeInfo? _alternateTypeInfo;
/// <summary>
/// Initializes a new instance of <see cref="ResultOrAlternate{TResult}"/> with an immediate result.
/// </summary>
/// <param name="result">The standard result returned by the server.</param>
public ResultOrAlternate(TResult result)
{
Throw.IfNull(result);
_result = result;
}
/// <summary>
/// Initializes a new instance of <see cref="ResultOrAlternate{TResult}"/> with an alternate result.
/// </summary>
/// <param name="alternate">The alternate result.</param>
/// <param name="alternateTypeInfo">The <see cref="JsonTypeInfo"/> used to serialize the alternate result.</param>
private ResultOrAlternate(Result alternate, JsonTypeInfo alternateTypeInfo)
{
Throw.IfNull(alternate);
Throw.IfNull(alternateTypeInfo);
_alternate = alternate;
_alternateTypeInfo = alternateTypeInfo;
}
/// <summary>
/// Creates a <see cref="ResultOrAlternate{TResult}"/> that carries an alternate <see cref="Result"/> subtype
/// (for example an <c>InputRequiredResult</c> or a task-creation result) in place of the standard result.
/// </summary>
/// <typeparam name="TAlternate">The concrete alternate result type.</typeparam>
/// <param name="alternate">The alternate result to return instead of the standard result.</param>
/// <param name="alternateTypeInfo">
/// The <see cref="JsonTypeInfo{T}"/> used to serialize <paramref name="alternate"/>. Requiring the strongly-typed
/// contract keeps the alternate value paired with matching serializer metadata rather than an unrelated type.
/// </param>
/// <returns>A <see cref="ResultOrAlternate{TResult}"/> that wraps the alternate result.</returns>
public static ResultOrAlternate<TResult> FromAlternate<TAlternate>(TAlternate alternate, JsonTypeInfo<TAlternate> alternateTypeInfo)
where TAlternate : Result
=> new(alternate, alternateTypeInfo);
/// <summary>
/// Gets a value indicating whether the server returned an alternate result instead of the standard result.
/// </summary>
public bool IsAlternate => _alternate is not null;
/// <summary>
/// Gets the immediate result, or <see langword="null"/> if the server returned an alternate.
/// </summary>
public TResult? Result => _result;
/// <summary>
/// Gets the alternate result, or <see langword="null"/> if the server returned the standard result.
/// </summary>
public Result? Alternate => _alternate;
/// <summary>
/// Gets the <see cref="JsonTypeInfo"/> for serializing the alternate result, or <see langword="null"/>
/// if the server returned the standard result.
/// </summary>
public JsonTypeInfo? AlternateTypeInfo => _alternateTypeInfo;
/// <summary>
/// Implicitly converts a <typeparamref name="TResult"/> to a <see cref="ResultOrAlternate{TResult}"/>
/// wrapping the immediate result.
/// </summary>
/// <param name="result">The result to wrap.</param>
public static implicit operator ResultOrAlternate<TResult>(TResult result) => new(result);
}

Some files were not shown because too many files have changed in this diff Show more