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:
parent
ffc557f920
commit
2ca96f548b
63 changed files with 2559 additions and 1895 deletions
|
|
@ -69,6 +69,7 @@
|
||||||
<Project Path="src/ModelContextProtocol.AspNetCore/ModelContextProtocol.AspNetCore.csproj" />
|
<Project Path="src/ModelContextProtocol.AspNetCore/ModelContextProtocol.AspNetCore.csproj" />
|
||||||
<Project Path="src/ModelContextProtocol.Core/ModelContextProtocol.Core.csproj" />
|
<Project Path="src/ModelContextProtocol.Core/ModelContextProtocol.Core.csproj" />
|
||||||
<Project Path="src/ModelContextProtocol.Extensions.Apps/ModelContextProtocol.Extensions.Apps.csproj" />
|
<Project Path="src/ModelContextProtocol.Extensions.Apps/ModelContextProtocol.Extensions.Apps.csproj" />
|
||||||
|
<Project Path="src/ModelContextProtocol.Extensions.Tasks/ModelContextProtocol.Extensions.Tasks.csproj" />
|
||||||
<Project Path="src/ModelContextProtocol/ModelContextProtocol.csproj" />
|
<Project Path="src/ModelContextProtocol/ModelContextProtocol.csproj" />
|
||||||
</Folder>
|
</Folder>
|
||||||
<Folder Name="/tests/">
|
<Folder Name="/tests/">
|
||||||
|
|
|
||||||
|
|
@ -590,7 +590,7 @@ In stateless mode, each HTTP request creates and disposes a short-lived `McpServ
|
||||||
|
|
||||||
## Tasks and session modes
|
## Tasks and session modes
|
||||||
|
|
||||||
[Tasks](xref:tasks) enable a "call-now, fetch-later" pattern for long-running tool calls. Task support depends on having an <xref:ModelContextProtocol.Server.IMcpTaskStore> configured (`McpServerOptions.TaskStore`), and behavior differs between session modes.
|
[Tasks](xref:tasks) enable a "call-now, fetch-later" pattern for long-running tool calls. Task support depends on having an <xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore> configured (enabled via `WithTasks`), and behavior differs between session modes.
|
||||||
|
|
||||||
### Stateless mode
|
### Stateless mode
|
||||||
|
|
||||||
|
|
@ -600,9 +600,9 @@ In stateless mode, there is no `SessionId`, so the task store does not apply ses
|
||||||
|
|
||||||
### Stateful mode
|
### Stateful mode
|
||||||
|
|
||||||
In stateful mode, the `IMcpTaskStore` receives the session's `SessionId` on every operation — `CreateTaskAsync`, `GetTaskAsync`, `ListTasksAsync`, `CancelTaskAsync`, etc. The built-in <xref:ModelContextProtocol.Server.InMemoryMcpTaskStore> enforces session isolation: tasks created in one session cannot be accessed from another.
|
In stateful mode, the `IMcpTaskStore` receives the session's `SessionId` on every operation: `CreateTaskAsync`, `GetTaskAsync`, `ListTasksAsync`, `CancelTaskAsync`, etc. The built-in <xref:ModelContextProtocol.Extensions.Tasks.InMemoryMcpTaskStore> enforces session isolation: tasks created in one session cannot be accessed from another.
|
||||||
|
|
||||||
Tasks can outlive individual HTTP requests because the tool executes in the background after returning the initial `CreateTaskResult`. Task cleanup is governed by the task's TTL (time-to-live), not by session termination. However, the `InMemoryMcpTaskStore` loses all tasks if the server process restarts. For durable tasks, implement a custom <xref:ModelContextProtocol.Server.IMcpTaskStore> backed by an external store. See [Implementing a custom task store](xref:tasks#implementing-a-custom-task-store) for guidance.
|
Tasks can outlive individual HTTP requests because the tool executes in the background after returning the initial `CreateTaskResult`. Task cleanup is governed by the task's TTL (time-to-live), not by session termination. However, the `InMemoryMcpTaskStore` loses all tasks if the server process restarts. For durable tasks, implement a custom <xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore> backed by an external store. See [Implementing a custom task store](xref:tasks#implementing-a-custom-task-store) for guidance.
|
||||||
|
|
||||||
### Task cancellation vs request cancellation
|
### Task cancellation vs request cancellation
|
||||||
|
|
||||||
|
|
@ -654,7 +654,7 @@ The `EventStreamStore` itself has TTL-based limits (default: 2-hour event expira
|
||||||
|
|
||||||
### With tasks (experimental)
|
### With tasks (experimental)
|
||||||
|
|
||||||
[Tasks](xref:tasks) are an experimental feature that enables a "call-now, fetch-later" pattern for long-running tool calls. When a client sends a task-augmented `tools/call` request, the server creates a task record in the <xref:ModelContextProtocol.Server.IMcpTaskStore>, starts the tool handler as a fire-and-forget background task, and returns the task ID immediately — the POST response completes **before the handler starts its real work**.
|
[Tasks](xref:tasks) are an experimental feature that enables a "call-now, fetch-later" pattern for long-running tool calls. When a client sends a task-augmented `tools/call` request, the server creates a task record in the <xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore>, starts the tool handler as a fire-and-forget background task, and returns the task ID immediately, so the POST response completes **before the handler starts its real work**.
|
||||||
|
|
||||||
This means:
|
This means:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ and the client polls for status, optionally exchanging additional input along th
|
||||||
|
|
||||||
A client opts into tasks on a per-request basis by including the `io.modelcontextprotocol/tasks`
|
A client opts into tasks on a per-request basis by including the `io.modelcontextprotocol/tasks`
|
||||||
extension key in the request's `_meta`. When that opt-in is present, the server **may** respond
|
extension key in the request's `_meta`. When that opt-in is present, the server **may** respond
|
||||||
with a <xref:ModelContextProtocol.Protocol.CreateTaskResult> instead of the standard result
|
with a <xref:ModelContextProtocol.Extensions.Tasks.CreateTaskResult> instead of the standard result
|
||||||
(e.g., <xref:ModelContextProtocol.Protocol.CallToolResult>). The client then polls `tasks/get`
|
(e.g., <xref:ModelContextProtocol.Protocol.CallToolResult>). The client then polls `tasks/get`
|
||||||
until the task reaches a terminal state.
|
until the task reaches a terminal state.
|
||||||
|
|
||||||
|
|
@ -39,36 +39,35 @@ the extension opt-in. The SDK enforces this on the server side.
|
||||||
└──→ Failed (terminal — JSON-RPC errors only)
|
└──→ Failed (terminal — JSON-RPC errors only)
|
||||||
```
|
```
|
||||||
|
|
||||||
<xref:ModelContextProtocol.Protocol.McpTaskStatus> wire values are serialized in snake_case:
|
<xref:ModelContextProtocol.Extensions.Tasks.McpTaskStatus> wire values are serialized in snake_case:
|
||||||
`working`, `input_required`, `completed`, `cancelled`, `failed`.
|
`working`, `input_required`, `completed`, `cancelled`, `failed`.
|
||||||
|
|
||||||
The discriminator field <xref:ModelContextProtocol.Protocol.Result.ResultType?displayProperty=nameWithType>
|
The discriminator field <xref:ModelContextProtocol.Protocol.Result.ResultType?displayProperty=nameWithType>
|
||||||
on the response payload is `"task"` for <xref:ModelContextProtocol.Protocol.CreateTaskResult>
|
on the response payload is `"task"` for <xref:ModelContextProtocol.Extensions.Tasks.CreateTaskResult>
|
||||||
and `"complete"` for ordinary results.
|
and `"complete"` for ordinary results.
|
||||||
|
|
||||||
### Server configuration
|
### Server configuration
|
||||||
|
|
||||||
#### Using the task store
|
#### Using the task store
|
||||||
|
|
||||||
The easiest way to enable tasks is to set an <xref:ModelContextProtocol.Server.IMcpTaskStore>
|
Tasks support lives in the `ModelContextProtocol.Extensions.Tasks` package. The easiest way to
|
||||||
on <xref:ModelContextProtocol.Server.McpServerOptions.TaskStore?displayProperty=nameWithType>.
|
enable tasks is to call <xref:ModelContextProtocol.Extensions.Tasks.McpTasksBuilderExtensions.WithTasks*>
|
||||||
The SDK ships <xref:ModelContextProtocol.Server.InMemoryMcpTaskStore> for development and tests:
|
on the server builder, passing an <xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore>.
|
||||||
|
The SDK ships <xref:ModelContextProtocol.Extensions.Tasks.InMemoryMcpTaskStore> for development and tests:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
#pragma warning disable MCPEXP001
|
#pragma warning disable MCPEXP001
|
||||||
|
|
||||||
builder.Services.AddMcpServer(options =>
|
using ModelContextProtocol.Extensions.Tasks;
|
||||||
{
|
|
||||||
options.TaskStore = new InMemoryMcpTaskStore();
|
builder.Services.AddMcpServer()
|
||||||
})
|
.WithTools<MyTools>()
|
||||||
.WithTools<MyTools>();
|
.WithTasks(new InMemoryMcpTaskStore());
|
||||||
```
|
```
|
||||||
|
|
||||||
When a `TaskStore` is configured the SDK automatically:
|
When tasks are enabled with `WithTasks` the SDK automatically:
|
||||||
|
|
||||||
- Wires `tasks/get`, `tasks/update`, and `tasks/cancel` handlers from the store. Explicit
|
- Wires the `tasks/get`, `tasks/update`, and `tasks/cancel` handlers from the store.
|
||||||
handlers in <xref:ModelContextProtocol.Server.McpServerOptions.Handlers> still take precedence
|
|
||||||
for any slot they fill.
|
|
||||||
- Advertises the `io.modelcontextprotocol/tasks` extension in
|
- Advertises the `io.modelcontextprotocol/tasks` extension in
|
||||||
<xref:ModelContextProtocol.Protocol.ServerCapabilities.Extensions?displayProperty=nameWithType>.
|
<xref:ModelContextProtocol.Protocol.ServerCapabilities.Extensions?displayProperty=nameWithType>.
|
||||||
- Wraps each `[McpServerTool]` invocation so that, when the client opts in to the extension,
|
- Wraps each `[McpServerTool]` invocation so that, when the client opts in to the extension,
|
||||||
|
|
@ -81,40 +80,21 @@ When a `TaskStore` is configured the SDK automatically:
|
||||||
`tasks/cancel`, so cancellation propagates cooperatively.
|
`tasks/cancel`, so cancellation propagates cooperatively.
|
||||||
|
|
||||||
For production scenarios that need durability, session isolation, multi-process routing, or
|
For production scenarios that need durability, session isolation, multi-process routing, or
|
||||||
TTL-based cleanup, implement <xref:ModelContextProtocol.Server.IMcpTaskStore> yourself
|
TTL-based cleanup, implement <xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore> yourself
|
||||||
(see [Implementing a custom task store](#implementing-a-custom-task-store) below).
|
(see [Implementing a custom task store](#implementing-a-custom-task-store) below).
|
||||||
|
|
||||||
#### Custom task handlers
|
|
||||||
|
|
||||||
For full control without a store, set the handlers directly. Each handler is an
|
|
||||||
<xref:ModelContextProtocol.Server.McpRequestHandler`2> that receives an
|
|
||||||
<xref:ModelContextProtocol.Server.RequestContext`1> with typed parameters:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
options.Handlers.GetTaskHandler = (context, ct) =>
|
|
||||||
{
|
|
||||||
var taskId = context.Params!.TaskId;
|
|
||||||
// … look up state and return one of the GetTaskResult subtypes.
|
|
||||||
return new ValueTask<GetTaskResult>(new WorkingTaskResult { TaskId = taskId, /* … */ });
|
|
||||||
};
|
|
||||||
|
|
||||||
options.Handlers.UpdateTaskHandler = (context, ct) => /* return ValueTask<UpdateTaskResult> */;
|
|
||||||
options.Handlers.CancelTaskHandler = (context, ct) => /* return ValueTask<CancelTaskResult> */;
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Important**: configure all three lifecycle handlers (or use a `TaskStore`) before opting
|
|
||||||
> into task responses. If a tool handler returns a `CreateTaskResult` but no `tasks/get`
|
|
||||||
> handler is wired, the server throws `InvalidOperationException` at request time so misconfigured
|
|
||||||
> deployments fail loudly instead of shipping unpollable tasks.
|
|
||||||
|
|
||||||
#### Returning a task from a tool handler
|
#### Returning a task from a tool handler
|
||||||
|
|
||||||
<xref:ModelContextProtocol.Server.McpServerHandlers.CallToolWithTaskHandler?displayProperty=nameWithType>
|
For full control without the store's auto-wrapping, set
|
||||||
returns <xref:ModelContextProtocol.Protocol.ResultOrCreatedTask`1>, so each invocation can choose
|
<xref:ModelContextProtocol.Server.McpServerHandlers.CallToolWithAlternateHandler?displayProperty=nameWithType>.
|
||||||
between an immediate result and a background task:
|
It returns a <xref:ModelContextProtocol.Protocol.ResultOrAlternate`1>, so each invocation can choose
|
||||||
|
between an immediate result and an alternate result such as a
|
||||||
|
<xref:ModelContextProtocol.Extensions.Tasks.CreateTaskResult>:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
options.Handlers.CallToolWithTaskHandler = async (context, ct) =>
|
using ModelContextProtocol.Extensions.Tasks;
|
||||||
|
|
||||||
|
options.Handlers.CallToolWithAlternateHandler = async (context, ct) =>
|
||||||
{
|
{
|
||||||
if (ShouldRunInline(context.Params!))
|
if (ShouldRunInline(context.Params!))
|
||||||
{
|
{
|
||||||
|
|
@ -122,7 +102,7 @@ options.Handlers.CallToolWithTaskHandler = async (context, ct) =>
|
||||||
}
|
}
|
||||||
|
|
||||||
var taskId = await StartBackgroundWorkAsync(context.Params!, ct);
|
var taskId = await StartBackgroundWorkAsync(context.Params!, ct);
|
||||||
return new CreateTaskResult
|
var created = new CreateTaskResult
|
||||||
{
|
{
|
||||||
TaskId = taskId,
|
TaskId = taskId,
|
||||||
Status = McpTaskStatus.Working,
|
Status = McpTaskStatus.Working,
|
||||||
|
|
@ -130,22 +110,32 @@ options.Handlers.CallToolWithTaskHandler = async (context, ct) =>
|
||||||
LastUpdatedAt = DateTimeOffset.UtcNow,
|
LastUpdatedAt = DateTimeOffset.UtcNow,
|
||||||
PollIntervalMs = 1000,
|
PollIntervalMs = 1000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return new ResultOrAlternate<CallToolResult>(created, McpTasksJsonContext.Default.CreateTaskResult);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> This low-level handler is mutually exclusive with `WithTasks`. When a store is configured, the
|
||||||
|
> SDK does the wrapping for you and throws `InvalidOperationException` if the alternate handler also
|
||||||
|
> returns an alternate. Use one mechanism or the other. When you return a task this way you are also
|
||||||
|
> responsible for serving `tasks/get`, `tasks/update`, and `tasks/cancel`, which the store provides
|
||||||
|
> automatically.
|
||||||
|
|
||||||
> <xref:ModelContextProtocol.Server.McpServerHandlers.CallToolHandler?displayProperty=nameWithType>
|
> <xref:ModelContextProtocol.Server.McpServerHandlers.CallToolHandler?displayProperty=nameWithType>
|
||||||
> and <xref:ModelContextProtocol.Server.McpServerHandlers.CallToolWithTaskHandler?displayProperty=nameWithType>
|
> and <xref:ModelContextProtocol.Server.McpServerHandlers.CallToolWithAlternateHandler?displayProperty=nameWithType>
|
||||||
> are mutually exclusive. Setting one while the other is already non-null throws
|
> are mutually exclusive. Setting one while the other is already non-null throws
|
||||||
> `InvalidOperationException` at the property setter.
|
> `InvalidOperationException` at the property setter.
|
||||||
|
|
||||||
#### Task scope for server-initiated requests
|
#### Task scope for server-initiated requests
|
||||||
|
|
||||||
When you start background work from a custom <xref:ModelContextProtocol.Server.McpServerHandlers.CallToolWithTaskHandler?displayProperty=nameWithType>
|
When you start background work from a custom <xref:ModelContextProtocol.Server.McpServerHandlers.CallToolWithAlternateHandler?displayProperty=nameWithType>
|
||||||
(rather than the SDK's auto-wrapping), use <xref:ModelContextProtocol.Server.McpServer.CreateMcpTaskScope*>
|
(rather than the SDK's auto-wrapping), use <xref:ModelContextProtocol.Extensions.Tasks.McpTasksServerExtensions.CreateMcpTaskScope*>
|
||||||
to route elicitation, sampling, and `roots/list` calls through the task store as input requests
|
to route elicitation, sampling, and `roots/list` calls through the task store as input requests
|
||||||
instead of direct JSON-RPC messages:
|
instead of direct JSON-RPC messages:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
|
using ModelContextProtocol.Extensions.Tasks;
|
||||||
|
|
||||||
using (server.CreateMcpTaskScope(taskId, taskStore))
|
using (server.CreateMcpTaskScope(taskId, taskStore))
|
||||||
{
|
{
|
||||||
// ElicitAsync/SampleAsync/RequestRootsAsync calls in here are surfaced as
|
// ElicitAsync/SampleAsync/RequestRootsAsync calls in here are surfaced as
|
||||||
|
|
@ -156,13 +146,13 @@ using (server.CreateMcpTaskScope(taskId, taskStore))
|
||||||
|
|
||||||
`CreateMcpTaskScope` returns an `IDisposable` that restores the prior ambient context on
|
`CreateMcpTaskScope` returns an `IDisposable` that restores the prior ambient context on
|
||||||
`Dispose`. The scope is established automatically for `[McpServerTool]` methods that run via
|
`Dispose`. The scope is established automatically for `[McpServerTool]` methods that run via
|
||||||
`McpServerOptions.TaskStore`, so this API is only needed for custom handlers.
|
`WithTasks`, so this API is only needed for custom handlers.
|
||||||
|
|
||||||
### Client usage
|
### Client usage
|
||||||
|
|
||||||
#### Automatic polling
|
#### Automatic polling
|
||||||
|
|
||||||
<xref:ModelContextProtocol.Client.McpClient.CallToolAsync(ModelContextProtocol.Protocol.CallToolRequestParams,System.Threading.CancellationToken)>
|
<xref:ModelContextProtocol.Extensions.Tasks.McpTasksClientExtensions.CallToolWithPollingAsync*>
|
||||||
handles the full task lifecycle automatically:
|
handles the full task lifecycle automatically:
|
||||||
|
|
||||||
- Injects the `io.modelcontextprotocol/tasks` extension capability into the request's `_meta`.
|
- Injects the `io.modelcontextprotocol/tasks` extension capability into the request's `_meta`.
|
||||||
|
|
@ -176,21 +166,25 @@ handles the full task lifecycle automatically:
|
||||||
or throws <xref:ModelContextProtocol.McpException> on `Failed`/`Cancelled`.
|
or throws <xref:ModelContextProtocol.McpException> on `Failed`/`Cancelled`.
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var result = await client.CallToolAsync(
|
using ModelContextProtocol.Extensions.Tasks;
|
||||||
|
|
||||||
|
var result = await client.CallToolWithPollingAsync(
|
||||||
new CallToolRequestParams { Name = "long-running-tool", Arguments = arguments },
|
new CallToolRequestParams { Name = "long-running-tool", Arguments = arguments },
|
||||||
cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Manual control
|
#### Manual control
|
||||||
|
|
||||||
Use <xref:ModelContextProtocol.Client.McpClient.CallToolRawAsync*> to receive the raw
|
Use <xref:ModelContextProtocol.Extensions.Tasks.McpTasksClientExtensions.CallToolAsTaskAsync*> to receive the raw
|
||||||
<xref:ModelContextProtocol.Protocol.ResultOrCreatedTask`1> without auto-polling, then drive the
|
<xref:ModelContextProtocol.Extensions.Tasks.ResultOrCreatedTask`1> without auto-polling, then drive the
|
||||||
lifecycle yourself using <xref:ModelContextProtocol.Client.McpClient.GetTaskAsync*>,
|
lifecycle yourself using <xref:ModelContextProtocol.Extensions.Tasks.McpTasksClientExtensions.GetTaskAsync*>,
|
||||||
<xref:ModelContextProtocol.Client.McpClient.UpdateTaskAsync*>, and
|
<xref:ModelContextProtocol.Extensions.Tasks.McpTasksClientExtensions.UpdateTaskAsync*>, and
|
||||||
<xref:ModelContextProtocol.Client.McpClient.CancelTaskAsync*>:
|
<xref:ModelContextProtocol.Extensions.Tasks.McpTasksClientExtensions.CancelTaskAsync*>:
|
||||||
|
|
||||||
```csharp
|
```csharp
|
||||||
var raw = await client.CallToolRawAsync(requestParams, cancellationToken);
|
using ModelContextProtocol.Extensions.Tasks;
|
||||||
|
|
||||||
|
var raw = await client.CallToolAsTaskAsync(requestParams, cancellationToken);
|
||||||
if (raw.IsTask)
|
if (raw.IsTask)
|
||||||
{
|
{
|
||||||
var taskId = raw.TaskCreated!.TaskId;
|
var taskId = raw.TaskCreated!.TaskId;
|
||||||
|
|
@ -206,17 +200,17 @@ if (raw.IsTask)
|
||||||
|
|
||||||
#### Stuck-task detector
|
#### Stuck-task detector
|
||||||
|
|
||||||
`CallToolAsync` includes a safety net for misbehaving servers: if the task stays in
|
`CallToolWithPollingAsync` includes a safety net for misbehaving servers: if the task stays in
|
||||||
<xref:ModelContextProtocol.Protocol.McpTaskStatus.InputRequired> across many consecutive polls
|
<xref:ModelContextProtocol.Extensions.Tasks.McpTaskStatus.InputRequired> across many consecutive polls
|
||||||
without exposing any new input request keys (i.e. every previously requested input has already
|
without exposing any new input request keys (i.e. every previously requested input has already
|
||||||
been resolved by the client and yet the server keeps returning `InputRequired`), the client
|
been resolved by the client and yet the server keeps returning `InputRequired`), the client
|
||||||
gives up, issues a best-effort `tasks/cancel`, and throws
|
gives up, issues a best-effort `tasks/cancel`, and throws
|
||||||
<xref:ModelContextProtocol.McpException>. This guards against a server that never transitions
|
<xref:ModelContextProtocol.McpException>. This guards against a server that never transitions
|
||||||
out of `InputRequired` and prevents an unbounded poll loop.
|
out of `InputRequired` and prevents an unbounded poll loop.
|
||||||
|
|
||||||
The threshold defaults to `60` consecutive stuck polls and is configurable via
|
The threshold defaults to `60` consecutive stuck polls and is configurable via the
|
||||||
<xref:ModelContextProtocol.Client.McpClientOptions.MaxConsecutiveStuckPolls>. The effective
|
`maxConsecutiveStuckPolls` parameter on `CallToolWithPollingAsync`. The effective
|
||||||
wall-clock timeout is roughly `MaxConsecutiveStuckPolls * pollIntervalMs`, so tune the option
|
wall-clock timeout is roughly `maxConsecutiveStuckPolls * pollIntervalMs`, so tune the value
|
||||||
with the server-side poll cadence in mind. Setting it too low risks false positives for servers
|
with the server-side poll cadence in mind. Setting it too low risks false positives for servers
|
||||||
that are slow to surface follow-up input requests; setting it too high can mask misbehaving
|
that are slow to surface follow-up input requests; setting it too high can mask misbehaving
|
||||||
servers.
|
servers.
|
||||||
|
|
@ -224,11 +218,11 @@ servers.
|
||||||
### Input requests (multi-round-trip)
|
### Input requests (multi-round-trip)
|
||||||
|
|
||||||
When a task needs additional input from the client, the server transitions it to
|
When a task needs additional input from the client, the server transitions it to
|
||||||
<xref:ModelContextProtocol.Protocol.McpTaskStatus.InputRequired> and returns the outstanding
|
<xref:ModelContextProtocol.Extensions.Tasks.McpTaskStatus.InputRequired> and returns the outstanding
|
||||||
requests in <xref:ModelContextProtocol.Protocol.InputRequiredTaskResult.InputRequests>. Each
|
requests in <xref:ModelContextProtocol.Extensions.Tasks.InputRequiredTaskResult.InputRequests>. Each
|
||||||
entry is an arbitrary key paired with a `{ method, params }` envelope representing an
|
entry is an arbitrary key paired with a `{ method, params }` envelope representing an
|
||||||
equivalent standalone server-to-client request. The client provides answers via
|
equivalent standalone server-to-client request. The client provides answers via
|
||||||
<xref:ModelContextProtocol.Client.McpClient.UpdateTaskAsync*>, keyed by the same identifiers.
|
<xref:ModelContextProtocol.Extensions.Tasks.McpTasksClientExtensions.UpdateTaskAsync*>, keyed by the same identifiers.
|
||||||
|
|
||||||
Supported input request methods:
|
Supported input request methods:
|
||||||
|
|
||||||
|
|
@ -241,34 +235,34 @@ Per SEP-2663:
|
||||||
|
|
||||||
- Each input request key **must** be unique over the lifetime of the task.
|
- Each input request key **must** be unique over the lifetime of the task.
|
||||||
- Clients **should** deduplicate keys across polls so a request is only presented to the user
|
- Clients **should** deduplicate keys across polls so a request is only presented to the user
|
||||||
or model once. `CallToolAsync` does this automatically.
|
or model once. `CallToolWithPollingAsync` does this automatically.
|
||||||
- Servers **should** ignore `inputResponses` entries whose key does not currently correspond to
|
- Servers **should** ignore `inputResponses` entries whose key does not currently correspond to
|
||||||
an outstanding request, including responses for terminal-state tasks.
|
an outstanding request, including responses for terminal-state tasks.
|
||||||
<xref:ModelContextProtocol.Server.InMemoryMcpTaskStore> follows this rule.
|
<xref:ModelContextProtocol.Extensions.Tasks.InMemoryMcpTaskStore> follows this rule.
|
||||||
|
|
||||||
### Implementing a custom task store
|
### Implementing a custom task store
|
||||||
|
|
||||||
Implement <xref:ModelContextProtocol.Server.IMcpTaskStore> for production scenarios. Key
|
Implement <xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore> for production scenarios. Key
|
||||||
requirements drawn from the SEP and the SDK contract:
|
requirements drawn from the SEP and the SDK contract:
|
||||||
|
|
||||||
1. **Thread safety** — every method may be called concurrently.
|
1. **Thread safety** — every method may be called concurrently.
|
||||||
2. **Idempotent terminal transitions** —
|
2. **Idempotent terminal transitions** —
|
||||||
<xref:ModelContextProtocol.Server.IMcpTaskStore.SetCompletedAsync*>,
|
<xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore.SetCompletedAsync*>,
|
||||||
<xref:ModelContextProtocol.Server.IMcpTaskStore.SetFailedAsync*>, and
|
<xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore.SetFailedAsync*>, and
|
||||||
<xref:ModelContextProtocol.Server.IMcpTaskStore.SetCancelledAsync*> must be no-ops on a task
|
<xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore.SetCancelledAsync*> must be no-ops on a task
|
||||||
that is already in a terminal state so a late cancellation cannot overwrite a result.
|
that is already in a terminal state so a late cancellation cannot overwrite a result.
|
||||||
3. **`InputResponseReceived` event** — after persisting an input response inside
|
3. **`InputResponseReceived` event** — after persisting an input response inside
|
||||||
<xref:ModelContextProtocol.Server.IMcpTaskStore.ResolveInputRequestsAsync*>, raise
|
<xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore.ResolveInputRequestsAsync*>, raise
|
||||||
<xref:ModelContextProtocol.Server.IMcpTaskStore.InputResponseReceived?displayProperty=nameWithType>
|
<xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore.InputResponseReceived?displayProperty=nameWithType>
|
||||||
for each resolved entry. This is the only mechanism that wakes a pending
|
for each resolved entry. This is the only mechanism that wakes a pending
|
||||||
`server.ElicitAsync`/`server.SampleAsync` call waiting inside a task scope. In distributed
|
`server.ElicitAsync`/`server.SampleAsync` call waiting inside a task scope. In distributed
|
||||||
deployments where a different server instance receives the `tasks/update`, the event must
|
deployments where a different server instance receives the `tasks/update`, the event must
|
||||||
be propagated to the originating server (for example via Redis pub/sub, SignalR, or a custom
|
be propagated to the originating server (for example via Redis pub/sub, SignalR, or a custom
|
||||||
transport).
|
transport).
|
||||||
4. **Strong-consistency on `CreateTaskAsync`** —
|
4. **Strong-consistency on `CreateTaskAsync`** —
|
||||||
<xref:ModelContextProtocol.Server.IMcpTaskStore.CreateTaskAsync*> must not return until the
|
<xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore.CreateTaskAsync*> must not return until the
|
||||||
task is durably persisted, so that a subsequent
|
task is durably persisted, so that a subsequent
|
||||||
<xref:ModelContextProtocol.Server.IMcpTaskStore.GetTaskAsync*> with the returned task ID
|
<xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore.GetTaskAsync*> with the returned task ID
|
||||||
resolves immediately — even from a different process or node. Stores backed by
|
resolves immediately — even from a different process or node. Stores backed by
|
||||||
eventually-consistent storage must wait for the write to become visible (quorum
|
eventually-consistent storage must wait for the write to become visible (quorum
|
||||||
acknowledgement, write-through, etc.) before returning. Required by SEP-2663 §306.
|
acknowledgement, write-through, etc.) before returning. Required by SEP-2663 §306.
|
||||||
|
|
@ -310,12 +304,12 @@ public sealed class MyTaskStore : IMcpTaskStore
|
||||||
|
|
||||||
### Status semantics
|
### Status semantics
|
||||||
|
|
||||||
<xref:ModelContextProtocol.Protocol.McpTaskStatus.Completed> is the terminal status whenever the
|
<xref:ModelContextProtocol.Extensions.Tasks.McpTaskStatus.Completed> is the terminal status whenever the
|
||||||
underlying request produced its standard result, *including a
|
underlying request produced its standard result, *including a
|
||||||
<xref:ModelContextProtocol.Protocol.CallToolResult> with `IsError = true`*. Per SEP-2663,
|
<xref:ModelContextProtocol.Protocol.CallToolResult> with `IsError = true`*. Per SEP-2663,
|
||||||
tool-level error results are not promoted to `Failed`.
|
tool-level error results are not promoted to `Failed`.
|
||||||
|
|
||||||
<xref:ModelContextProtocol.Protocol.McpTaskStatus.Failed> is reserved for JSON-RPC protocol-level
|
<xref:ModelContextProtocol.Extensions.Tasks.McpTaskStatus.Failed> is reserved for JSON-RPC protocol-level
|
||||||
errors during execution — for example, a malformed request, or an unhandled exception in a custom
|
errors during execution — for example, a malformed request, or an unhandled exception in a custom
|
||||||
handler that the SDK converts to a JSON-RPC error. Use
|
handler that the SDK converts to a JSON-RPC error. Use
|
||||||
<xref:ModelContextProtocol.Protocol.CallToolResult.IsError?displayProperty=nameWithType> for
|
<xref:ModelContextProtocol.Protocol.CallToolResult.IsError?displayProperty=nameWithType> for
|
||||||
|
|
@ -341,7 +335,7 @@ In the built-in SDK pipeline, when a task is wrapped by a configured `TaskStore`
|
||||||
|
|
||||||
#### Immutable store design
|
#### Immutable store design
|
||||||
|
|
||||||
<xref:ModelContextProtocol.Server.InMemoryMcpTaskStore> uses immutable record snapshots with
|
<xref:ModelContextProtocol.Extensions.Tasks.InMemoryMcpTaskStore> uses immutable record snapshots with
|
||||||
compare-and-swap updates for lock-free thread safety. `InputRequests` and `InputResponses` are
|
compare-and-swap updates for lock-free thread safety. `InputRequests` and `InputResponses` are
|
||||||
exposed as `ImmutableDictionary<,>` so observers cannot mutate internal state.
|
exposed as `ImmutableDictionary<,>` so observers cannot mutate internal state.
|
||||||
|
|
||||||
|
|
@ -357,13 +351,13 @@ responsible for handling — or rejecting — the input requests surfaced throug
|
||||||
|
|
||||||
- **Server-push task status notifications (SEP-2575)**: not yet implemented. Clients rely on
|
- **Server-push task status notifications (SEP-2575)**: not yet implemented. Clients rely on
|
||||||
polling exclusively.
|
polling exclusively.
|
||||||
- **Lazy task creation**: when a tool runs through `TaskStore`, the store's
|
- **Lazy task creation**: when a tool runs through the task store, the store's
|
||||||
<xref:ModelContextProtocol.Server.IMcpTaskStore.CreateTaskAsync*> is invoked eagerly before
|
<xref:ModelContextProtocol.Extensions.Tasks.IMcpTaskStore.CreateTaskAsync*> is invoked eagerly before
|
||||||
the inner handler runs, so tools that complete inline still incur a store write. There is
|
the inner handler runs, so tools that complete inline still incur a store write. There is
|
||||||
currently no built-in deferral.
|
currently no built-in deferral.
|
||||||
- **Mid-execution promotion to task**: an `[McpServerTool]` method cannot start executing
|
- **Mid-execution promotion to task**: an `[McpServerTool]` method cannot start executing
|
||||||
synchronously and then transition its remaining work to a background task. Use a custom
|
synchronously and then transition its remaining work to a background task. Use a custom
|
||||||
<xref:ModelContextProtocol.Server.McpServerHandlers.CallToolWithTaskHandler?displayProperty=nameWithType>
|
<xref:ModelContextProtocol.Server.McpServerHandlers.CallToolWithAlternateHandler?displayProperty=nameWithType>
|
||||||
if you need that pattern.
|
if you need that pattern.
|
||||||
- **`roots/list` as an input request**: the server SDK routes `RequestRootsAsync` through the
|
- **`roots/list` as an input request**: the server SDK routes `RequestRootsAsync` through the
|
||||||
task channel when called from inside a task scope, but the client SDK does not currently
|
task channel when called from inside a task scope, but the client SDK does not currently
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,17 @@
|
||||||
// Demonstrates the MCP tasks extension (SEP-2663):
|
// Demonstrates the MCP tasks extension (SEP-2663):
|
||||||
//
|
//
|
||||||
// - A server is configured with InMemoryMcpTaskStore so that any [McpServerTool] invocation
|
// - A server is configured with .WithTasks(store) so that any [McpServerTool] invocation
|
||||||
// becomes a background task when the client opts in via the per-request _meta marker.
|
// becomes a background task when the client opts in via the per-request _meta marker.
|
||||||
// - The client invokes the same tool two ways:
|
// - The client invokes the tool and manually drives the lifecycle via GetTaskAsync.
|
||||||
// 1. CallToolAsync — the SDK auto-polls until the task completes and returns the final
|
|
||||||
// CallToolResult, just like a synchronous call.
|
|
||||||
// 2. CallToolRawAsync — the caller drives the lifecycle manually (GetTaskAsync polls,
|
|
||||||
// CancelTaskAsync, etc.). Use this when you need to surface progress to a UI or stream
|
|
||||||
// status updates rather than block on a single await.
|
|
||||||
//
|
//
|
||||||
// Both server and client are wired together in-process over an in-memory pipe so the sample
|
// Both server and client are wired together in-process over an in-memory pipe so the sample
|
||||||
// is self-contained — no separate server process or HTTP transport required.
|
// is self-contained — no separate server process or HTTP transport required.
|
||||||
|
|
||||||
|
#pragma warning disable MCPEXP001, MCPEXP002, MCPEXP004
|
||||||
|
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using ModelContextProtocol.Client;
|
using ModelContextProtocol.Client;
|
||||||
|
using ModelContextProtocol.Extensions.Tasks;
|
||||||
using ModelContextProtocol.Protocol;
|
using ModelContextProtocol.Protocol;
|
||||||
using ModelContextProtocol.Server;
|
using ModelContextProtocol.Server;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
|
@ -21,28 +20,25 @@ using System.Text.Json;
|
||||||
|
|
||||||
Pipe clientToServerPipe = new(), serverToClientPipe = new();
|
Pipe clientToServerPipe = new(), serverToClientPipe = new();
|
||||||
|
|
||||||
await using McpServer server = McpServer.Create(
|
var store = new InMemoryMcpTaskStore { DefaultPollIntervalMs = 250 };
|
||||||
new StreamServerTransport(clientToServerPipe.Reader.AsStream(), serverToClientPipe.Writer.AsStream()),
|
|
||||||
new McpServerOptions
|
var services = new ServiceCollection();
|
||||||
{
|
services.AddMcpServer()
|
||||||
// Setting TaskStore is all that's needed for [McpServerTool]-attributed tools to be
|
.WithTools([McpServerTool.Create(SlowTools.RunReport, new() { Name = "run-report" })])
|
||||||
// automatically wrapped as background tasks when the client opts in.
|
.WithTasks(store);
|
||||||
TaskStore = new InMemoryMcpTaskStore { DefaultPollIntervalMs = 250 },
|
services.AddSingleton<ITransport>(new StreamServerTransport(clientToServerPipe.Reader.AsStream(), serverToClientPipe.Writer.AsStream()));
|
||||||
ToolCollection = [McpServerTool.Create(SlowTools.RunReport, new() { Name = "run-report" })],
|
|
||||||
});
|
await using var serviceProvider = services.BuildServiceProvider();
|
||||||
|
var server = serviceProvider.GetRequiredService<McpServer>();
|
||||||
_ = server.RunAsync();
|
_ = server.RunAsync();
|
||||||
|
|
||||||
await using McpClient client = await McpClient.CreateAsync(
|
await using McpClient client = await McpClient.CreateAsync(
|
||||||
new StreamClientTransport(clientToServerPipe.Writer.AsStream(), serverToClientPipe.Reader.AsStream()));
|
new StreamClientTransport(
|
||||||
|
serverInput: clientToServerPipe.Writer.AsStream(),
|
||||||
|
serverOutput: serverToClientPipe.Reader.AsStream()));
|
||||||
|
|
||||||
Console.WriteLine("=== CallToolAsync (auto-poll) ===");
|
Console.WriteLine("=== CallToolAsTaskAsync (manual poll) ===");
|
||||||
var auto = await client.CallToolAsync(
|
var raw = await client.CallToolAsTaskAsync(new CallToolRequestParams { Name = "run-report" });
|
||||||
new CallToolRequestParams { Name = "run-report" });
|
|
||||||
Console.WriteLine($" result: {((TextContentBlock)auto.Content[0]).Text}");
|
|
||||||
Console.WriteLine();
|
|
||||||
|
|
||||||
Console.WriteLine("=== CallToolRawAsync (manual poll) ===");
|
|
||||||
var raw = await client.CallToolRawAsync(new CallToolRequestParams { Name = "run-report" });
|
|
||||||
if (!raw.IsTask)
|
if (!raw.IsTask)
|
||||||
{
|
{
|
||||||
// Either the server doesn't advertise the tasks extension or it chose to run the call
|
// Either the server doesn't advertise the tasks extension or it chose to run the call
|
||||||
|
|
@ -88,9 +84,6 @@ while (true)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case InputRequiredTaskResult inputRequired:
|
case InputRequiredTaskResult inputRequired:
|
||||||
// The auto-poll path (CallToolAsync above) routes these through the registered
|
|
||||||
// ElicitationHandler/SamplingHandler automatically. The manual path needs to call
|
|
||||||
// UpdateTaskAsync with responses for each outstanding key.
|
|
||||||
Console.WriteLine($" poll {pollCount}: input requested ({inputRequired.InputRequests?.Count ?? 0} key(s))");
|
Console.WriteLine($" poll {pollCount}: input requested ({inputRequired.InputRequests?.Count ?? 0} key(s))");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\src\ModelContextProtocol\ModelContextProtocol.csproj" />
|
<ProjectReference Include="..\..\src\ModelContextProtocol\ModelContextProtocol.csproj" />
|
||||||
|
<ProjectReference Include="..\..\src\ModelContextProtocol.Extensions.Tasks\ModelContextProtocol.Extensions.Tasks.csproj" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -944,25 +944,17 @@ public abstract partial class McpClient : McpSession
|
||||||
McpJsonUtilities.JsonContext.Default.EmptyResult,
|
McpJsonUtilities.JsonContext.Default.EmptyResult,
|
||||||
cancellationToken: cancellationToken).AsTask();
|
cancellationToken: cancellationToken).AsTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invokes a tool on the server.
|
/// Invokes a tool on the server.
|
||||||
/// </summary>
|
/// </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="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="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>
|
/// <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="ArgumentNullException"><paramref name="toolName"/> is <see langword="null"/>.</exception>
|
||||||
/// <exception cref="McpException">The request failed or the server returned an error response.</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(
|
public ValueTask<CallToolResult> CallToolAsync(
|
||||||
string toolName,
|
string toolName,
|
||||||
IReadOnlyDictionary<string, object?>? arguments = null,
|
IReadOnlyDictionary<string, object?>? arguments = null,
|
||||||
|
|
@ -1033,221 +1025,19 @@ public abstract partial class McpClient : McpSession
|
||||||
/// <returns>The result of the request.</returns>
|
/// <returns>The result of the request.</returns>
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="requestParams"/> is <see langword="null"/>.</exception>
|
/// <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>
|
/// <exception cref="McpException">The request failed or the server returned an error response.</exception>
|
||||||
/// <remarks>
|
public ValueTask<CallToolResult> CallToolAsync(
|
||||||
/// 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(
|
|
||||||
CallToolRequestParams requestParams,
|
CallToolRequestParams requestParams,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
Throw.IfNull(requestParams);
|
Throw.IfNull(requestParams);
|
||||||
|
|
||||||
var augmented = await CallToolRawAsync(requestParams, cancellationToken).ConfigureAwait(false);
|
return SendRequestAsync(
|
||||||
|
RequestMethods.ToolsCall,
|
||||||
if (!augmented.IsTask)
|
requestParams,
|
||||||
{
|
McpJsonUtilities.JsonContext.Default.CallToolRequestParams,
|
||||||
return augmented.Result!;
|
McpJsonUtilities.JsonContext.Default.CallToolResult,
|
||||||
}
|
cancellationToken: cancellationToken);
|
||||||
|
|
||||||
return await PollTaskToCompletionAsync(augmented.TaskCreated!, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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>
|
/// <summary>
|
||||||
/// Sets the logging level for the server to control which log messages are sent to the client.
|
/// Sets the logging level for the server to control which log messages are sent to the client.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -1302,111 +1092,6 @@ public abstract partial class McpClient : McpSession
|
||||||
McpJsonUtilities.JsonContext.Default.EmptyResult,
|
McpJsonUtilities.JsonContext.Default.EmptyResult,
|
||||||
cancellationToken: cancellationToken).AsTask();
|
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(
|
private static Dictionary<string, JsonElement>? ToArgumentsDictionary(
|
||||||
IReadOnlyDictionary<string, object?>? arguments, JsonSerializerOptions options)
|
IReadOnlyDictionary<string, object?>? arguments, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
|
|
@ -1425,43 +1110,4 @@ public abstract partial class McpClient : McpSession
|
||||||
return result;
|
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)"}'.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ public abstract partial class McpClient : McpSession
|
||||||
public abstract Task<ClientCompletionDetails> Completion { get; }
|
public abstract Task<ClientCompletionDetails> Completion { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resolves input requests embedded in an <see cref="InputRequiredTaskResult"/> by dispatching
|
/// Resolves input requests by dispatching
|
||||||
/// each request to the appropriate registered handler.
|
/// each request to the appropriate registered handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inputRequests">
|
/// <param name="inputRequests">
|
||||||
|
|
@ -82,16 +82,9 @@ public abstract partial class McpClient : McpSession
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests.</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>
|
/// <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);
|
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>
|
/// <summary>
|
||||||
/// Inspects a received cacheable result (<c>tools/list</c>, <c>prompts/list</c>, <c>resources/list</c>,
|
/// 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.
|
/// <c>resources/templates/list</c>, or <c>resources/read</c>) so derived clients can emit diagnostics.
|
||||||
|
|
|
||||||
|
|
@ -179,10 +179,9 @@ internal sealed partial class McpClientImpl : McpClient
|
||||||
public override Task<ClientCompletionDetails> Completion => _sessionHandler.CompletionTask;
|
public override Task<ClientCompletionDetails> Completion => _sessionHandler.CompletionTask;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
private protected override int MaxConsecutiveStuckPolls => _options.MaxConsecutiveStuckPolls;
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
private protected override async ValueTask<IDictionary<string, InputResponse>> ResolveInputRequestsAsync(
|
public override async ValueTask<IDictionary<string, InputResponse>> ResolveInputRequestsAsync(
|
||||||
IDictionary<string, InputRequest> inputRequests,
|
IDictionary<string, InputRequest> inputRequests,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,13 @@
|
||||||
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
|
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
|
||||||
|
|
@ -71,6 +78,20 @@
|
||||||
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
|
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
|
||||||
|
|
@ -113,6 +134,13 @@
|
||||||
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
|
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
|
||||||
|
|
@ -211,6 +239,13 @@
|
||||||
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
|
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
|
||||||
|
|
@ -225,6 +260,20 @@
|
||||||
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
|
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
|
||||||
|
|
@ -267,6 +316,13 @@
|
||||||
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
|
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
|
||||||
|
|
@ -365,6 +421,13 @@
|
||||||
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
|
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
|
||||||
|
|
@ -379,6 +442,20 @@
|
||||||
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
|
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
|
||||||
|
|
@ -421,6 +498,13 @@
|
||||||
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
|
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
|
||||||
|
|
@ -519,6 +603,13 @@
|
||||||
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
|
<Target>T:ModelContextProtocol.Protocol.ElicitationMcpTasksCapability</Target>
|
||||||
|
|
@ -533,6 +624,20 @@
|
||||||
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
|
<Target>T:ModelContextProtocol.Protocol.ListMcpTasksCapability</Target>
|
||||||
|
|
@ -575,6 +680,13 @@
|
||||||
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0001</DiagnosticId>
|
<DiagnosticId>CP0001</DiagnosticId>
|
||||||
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
|
<Target>T:ModelContextProtocol.Protocol.McpTaskStatusNotificationParams</Target>
|
||||||
|
|
@ -624,6 +736,27 @@
|
||||||
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
|
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
|
||||||
|
|
@ -785,20 +918,6 @@
|
||||||
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
|
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
|
||||||
|
|
@ -813,34 +932,6 @@
|
||||||
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
|
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
|
||||||
|
|
@ -960,6 +1051,13 @@
|
||||||
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
|
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
|
||||||
|
|
@ -995,6 +1093,27 @@
|
||||||
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
|
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
|
||||||
|
|
@ -1156,20 +1275,6 @@
|
||||||
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
|
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
|
||||||
|
|
@ -1184,34 +1289,6 @@
|
||||||
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
|
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
|
||||||
|
|
@ -1331,6 +1408,13 @@
|
||||||
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
|
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
|
||||||
|
|
@ -1366,6 +1450,27 @@
|
||||||
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
|
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
|
||||||
|
|
@ -1527,20 +1632,6 @@
|
||||||
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
|
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
|
||||||
|
|
@ -1555,34 +1646,6 @@
|
||||||
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
|
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
|
||||||
|
|
@ -1702,6 +1765,13 @@
|
||||||
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
|
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
|
||||||
|
|
@ -1737,6 +1807,27 @@
|
||||||
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
|
<Target>F:ModelContextProtocol.Protocol.RequestMethods.TasksList</Target>
|
||||||
|
|
@ -1898,20 +1989,6 @@
|
||||||
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
|
<Target>M:ModelContextProtocol.Protocol.ElicitRequestParams.get_Task</Target>
|
||||||
|
|
@ -1926,34 +2003,6 @@
|
||||||
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
|
<Target>M:ModelContextProtocol.Protocol.ServerCapabilities.get_Tasks</Target>
|
||||||
|
|
@ -2073,6 +2122,13 @@
|
||||||
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</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>
|
<Suppression>
|
||||||
<DiagnosticId>CP0002</DiagnosticId>
|
<DiagnosticId>CP0002</DiagnosticId>
|
||||||
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
|
<Target>M:ModelContextProtocol.Server.McpServerToolAttribute.get_TaskSupport</Target>
|
||||||
|
|
@ -2102,57 +2158,29 @@
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</Suppression>
|
||||||
<Suppression>
|
<Suppression>
|
||||||
<DiagnosticId>CP0011</DiagnosticId>
|
<DiagnosticId>CP0005</DiagnosticId>
|
||||||
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Cancelled</Target>
|
<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>
|
<Left>lib/net10.0/ModelContextProtocol.Core.dll</Left>
|
||||||
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net10.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</Suppression>
|
||||||
<Suppression>
|
<Suppression>
|
||||||
<DiagnosticId>CP0011</DiagnosticId>
|
<DiagnosticId>CP0005</DiagnosticId>
|
||||||
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Failed</Target>
|
<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.Cancelled</Target>
|
|
||||||
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
|
<Left>lib/net8.0/ModelContextProtocol.Core.dll</Left>
|
||||||
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net8.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</Suppression>
|
||||||
<Suppression>
|
<Suppression>
|
||||||
<DiagnosticId>CP0011</DiagnosticId>
|
<DiagnosticId>CP0005</DiagnosticId>
|
||||||
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Failed</Target>
|
<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.Cancelled</Target>
|
|
||||||
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
|
<Left>lib/net9.0/ModelContextProtocol.Core.dll</Left>
|
||||||
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/net9.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
</Suppression>
|
</Suppression>
|
||||||
<Suppression>
|
<Suppression>
|
||||||
<DiagnosticId>CP0011</DiagnosticId>
|
<DiagnosticId>CP0005</DiagnosticId>
|
||||||
<Target>F:ModelContextProtocol.Protocol.McpTaskStatus.Failed</Target>
|
<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.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>
|
|
||||||
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
|
<Left>lib/netstandard2.0/ModelContextProtocol.Core.dll</Left>
|
||||||
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
<Right>lib/netstandard2.0/ModelContextProtocol.Core.dll</Right>
|
||||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,13 @@ public static partial class McpJsonUtilities
|
||||||
return options;
|
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));
|
(JsonTypeInfo<T>)options.GetTypeInfo(typeof(T));
|
||||||
|
|
||||||
internal static JsonElement DefaultMcpToolSchema { get; } = ParseJsonElement("""{"type":"object"}"""u8);
|
internal static JsonElement DefaultMcpToolSchema { get; } = ParseJsonElement("""{"type":"object"}"""u8);
|
||||||
|
|
@ -120,12 +126,6 @@ public static partial class McpJsonUtilities
|
||||||
[JsonSerializable(typeof(ResourceUpdatedNotificationParams))]
|
[JsonSerializable(typeof(ResourceUpdatedNotificationParams))]
|
||||||
[JsonSerializable(typeof(RootsListChangedNotificationParams))]
|
[JsonSerializable(typeof(RootsListChangedNotificationParams))]
|
||||||
[JsonSerializable(typeof(ToolListChangedNotificationParams))]
|
[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
|
// MCP Request Params / Results
|
||||||
[JsonSerializable(typeof(CallToolRequestParams))]
|
[JsonSerializable(typeof(CallToolRequestParams))]
|
||||||
|
|
@ -174,19 +174,6 @@ public static partial class McpJsonUtilities
|
||||||
[JsonSerializable(typeof(IDictionary<string, InputRequest>))]
|
[JsonSerializable(typeof(IDictionary<string, InputRequest>))]
|
||||||
[JsonSerializable(typeof(IDictionary<string, InputResponse>))]
|
[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
|
// MCP Content
|
||||||
[JsonSerializable(typeof(ContentBlock))]
|
[JsonSerializable(typeof(ContentBlock))]
|
||||||
[JsonSerializable(typeof(TextContentBlock))]
|
[JsonSerializable(typeof(TextContentBlock))]
|
||||||
|
|
|
||||||
|
|
@ -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";
|
|
||||||
}
|
|
||||||
|
|
@ -53,24 +53,4 @@ public static class MetaKeys
|
||||||
/// belonging to different subscriptions on a shared channel (especially STDIO).
|
/// belonging to different subscriptions on a shared channel (especially STDIO).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public const string SubscriptionId = "io.modelcontextprotocol/subscriptionId";
|
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";
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,16 +144,6 @@ public static class NotificationMethods
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public const string CancelledNotification = "notifications/cancelled";
|
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>
|
/// <summary>
|
||||||
/// The name of the notification sent first on a <see cref="RequestMethods.SubscriptionsListen"/>
|
/// 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.
|
/// response stream to indicate which notification types the server agreed to deliver.
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ namespace ModelContextProtocol.Protocol;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class NotificationParams
|
public abstract class NotificationParams
|
||||||
{
|
{
|
||||||
/// <summary>Prevent external derivations.</summary>
|
/// <summary>Initializes the base notification parameter type.</summary>
|
||||||
private protected NotificationParams()
|
protected NotificationParams()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,33 +125,6 @@ public static class RequestMethods
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public const string Initialize = "initialize";
|
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>
|
/// <summary>
|
||||||
/// The name of the request method sent from the client to discover the server's protocol versions,
|
/// The name of the request method sent from the client to discover the server's protocol versions,
|
||||||
/// capabilities, and metadata.
|
/// capabilities, and metadata.
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ namespace ModelContextProtocol.Protocol;
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public abstract class RequestParams
|
public abstract class RequestParams
|
||||||
{
|
{
|
||||||
/// <summary>Prevent external derivations.</summary>
|
/// <summary>Initializes the base request parameter type.</summary>
|
||||||
private protected RequestParams()
|
protected RequestParams()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ namespace ModelContextProtocol.Protocol;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class Result
|
public abstract class Result
|
||||||
{
|
{
|
||||||
/// <summary>Prevent external derivations.</summary>
|
/// <summary>Initializes the base result type.</summary>
|
||||||
private protected Result()
|
protected Result()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,11 +27,9 @@ public abstract class Result
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// When set to <c>"complete"</c>, the result is a normal completed response.
|
/// When absent or 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
|
/// Other values discriminate alternate result subtypes so callers can choose the appropriate
|
||||||
/// that additional input is needed before the request can be completed.
|
/// concrete payload to deserialize.
|
||||||
/// 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.
|
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <value>Defaults to <see langword="null"/>, which is equivalent to <c>"complete"</c>.</value>
|
/// <value>Defaults to <see langword="null"/>, which is equivalent to <c>"complete"</c>.</value>
|
||||||
|
|
|
||||||
95
src/ModelContextProtocol.Core/Protocol/ResultOrAlternate.cs
Normal file
95
src/ModelContextProtocol.Core/Protocol/ResultOrAlternate.cs
Normal 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);
|
||||||
|
}
|
||||||
|
|
@ -46,48 +46,35 @@ internal sealed class RequestHandlers : Dictionary<string, Func<JsonRpcRequest,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning disable MCPEXP002 // SetWithAlternate consumes the experimental ResultOrAlternate seam
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a handler that may return either a standard result or a <see cref="CreateTaskResult"/>
|
/// Registers a handler that may return either a standard result or an alternate <see cref="Result"/>
|
||||||
/// for task-augmented execution.
|
/// subtype for scenarios like task-augmented execution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SetTaskAugmented<TParams, TResult>(
|
public void SetWithAlternate<TParams, TResult>(
|
||||||
string method,
|
string method,
|
||||||
Func<TParams, JsonRpcRequest, CancellationToken, ValueTask<ResultOrCreatedTask<TResult>>> handler,
|
Func<TParams, JsonRpcRequest, CancellationToken, ValueTask<ResultOrAlternate<TResult>>> handler,
|
||||||
JsonTypeInfo<TParams> requestTypeInfo,
|
JsonTypeInfo<TParams> requestTypeInfo,
|
||||||
JsonTypeInfo<TResult> responseTypeInfo,
|
JsonTypeInfo<TResult> responseTypeInfo)
|
||||||
JsonTypeInfo<CreateTaskResult> taskResultTypeInfo)
|
|
||||||
where TResult : Result
|
where TResult : Result
|
||||||
{
|
{
|
||||||
Throw.IfNull(method);
|
Throw.IfNull(method);
|
||||||
Throw.IfNull(handler);
|
Throw.IfNull(handler);
|
||||||
Throw.IfNull(requestTypeInfo);
|
Throw.IfNull(requestTypeInfo);
|
||||||
Throw.IfNull(responseTypeInfo);
|
Throw.IfNull(responseTypeInfo);
|
||||||
Throw.IfNull(taskResultTypeInfo);
|
|
||||||
|
|
||||||
this[method] = async (request, cancellationToken) =>
|
this[method] = async (request, cancellationToken) =>
|
||||||
{
|
{
|
||||||
TParams typedRequest = JsonSerializer.Deserialize(request.Params, requestTypeInfo)!;
|
TParams typedRequest = JsonSerializer.Deserialize(request.Params, requestTypeInfo)!;
|
||||||
var augmented = await handler(typedRequest, request, cancellationToken).ConfigureAwait(false);
|
var augmented = await handler(typedRequest, request, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
if (augmented.IsTask)
|
if (augmented.IsAlternate)
|
||||||
{
|
{
|
||||||
// Guard against a misconfiguration where a handler opts into task-augmented
|
return JsonSerializer.SerializeToNode(augmented.Alternate!, augmented.AlternateTypeInfo!);
|
||||||
// execution but the server has no task lifecycle handlers wired up. Without
|
|
||||||
// tasks/get, a client that received a CreateTaskResult would have no way to
|
|
||||||
// poll the task to completion. Configure McpServerOptions.TaskStore or set
|
|
||||||
// the task handlers explicitly via McpServerOptions.Handlers.
|
|
||||||
if (!ContainsKey(RequestMethods.TasksGet))
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(
|
|
||||||
$"Handler for '{method}' returned a {nameof(CreateTaskResult)}, but the server has no " +
|
|
||||||
$"'{RequestMethods.TasksGet}' handler registered. Configure McpServerOptions.TaskStore " +
|
|
||||||
"or set the task handlers explicitly in McpServerOptions.Handlers before starting the server.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return JsonSerializer.SerializeToNode(augmented.TaskCreated!, taskResultTypeInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return JsonSerializer.SerializeToNode(augmented.Result!, responseTypeInfo);
|
return JsonSerializer.SerializeToNode(augmented.Result!, responseTypeInfo);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
#pragma warning restore MCPEXP002
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue