Implement MCP task support (SEP-1686) (#1170)

Co-authored-by: Stephen Halter <halter73@gmail.com>
This commit is contained in:
Eirik Tsarpalis 2026-01-28 05:21:02 +02:00 • committed by GitHub
commit 10e4f5b20f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -46,6 +46,14 @@ public class TestServerTransport : ITransport
await SamplingAsync(request, cancellationToken);
else if (request.Method == RequestMethods.ElicitationCreate)
await ElicitAsync(request, cancellationToken);
else if (request.Method == RequestMethods.TasksGet)
await TasksGetAsync(request, cancellationToken);
else if (request.Method == RequestMethods.TasksResult)
await TasksResultAsync(request, cancellationToken);
else if (request.Method == RequestMethods.TasksList)
await TasksListAsync(request, cancellationToken);
else if (request.Method == RequestMethods.TasksCancel)
await TasksCancelAsync(request, cancellationToken);
else
await WriteMessageAsync(request, cancellationToken);
}
@ -71,19 +79,161 @@ public class TestServerTransport : ITransport
private async Task SamplingAsync(JsonRpcRequest request, CancellationToken cancellationToken)
{
await WriteMessageAsync(new JsonRpcResponse
// Check if the request is task-augmented (has Task metadata)
var requestParams = JsonSerializer.Deserialize<CreateMessageRequestParams>(request.Params, McpJsonUtilities.DefaultOptions);
if (requestParams?.Task is not null && MockTask is not null)
{
Id = request.Id,
Result = JsonSerializer.SerializeToNode(new CreateMessageResult { Content = [new TextContentBlock { Text = "" }], Model = "model"}, McpJsonUtilities.DefaultOptions),
}, cancellationToken);
// Return a task-augmented response
await WriteMessageAsync(new JsonRpcResponse
{
Id = request.Id,
Result = JsonSerializer.SerializeToNode(new CreateTaskResult { Task = MockTask }, McpJsonUtilities.DefaultOptions),
}, cancellationToken);
}
else
{
// Return a normal sampling response
await WriteMessageAsync(new JsonRpcResponse
{
Id = request.Id,
Result = JsonSerializer.SerializeToNode(new CreateMessageResult { Content = [new TextContentBlock { Text = "" }], Model = "model" }, McpJsonUtilities.DefaultOptions),
}, cancellationToken);
}
}
private async Task ElicitAsync(JsonRpcRequest request, CancellationToken cancellationToken)
{
// Check if the request is task-augmented (has Task metadata)
var requestParams = JsonSerializer.Deserialize<ElicitRequestParams>(request.Params, McpJsonUtilities.DefaultOptions);
if (requestParams?.Task is not null && MockTask is not null)
{
// Return a task-augmented response
await WriteMessageAsync(new JsonRpcResponse
{
Id = request.Id,
Result = JsonSerializer.SerializeToNode(new CreateTaskResult { Task = MockTask }, McpJsonUtilities.DefaultOptions),
}, cancellationToken);
}
else
{
// Return a normal elicitation response
await WriteMessageAsync(new JsonRpcResponse
{
Id = request.Id,
Result = JsonSerializer.SerializeToNode(new ElicitResult { Action = "decline" }, McpJsonUtilities.DefaultOptions),
}, cancellationToken);
}
}
/// <summary>
/// Gets or sets the task to return from tasks/get requests.
/// </summary>
public McpTask? MockTask { get; set; }
/// <summary>
/// Gets or sets the result to return from tasks/result requests.
/// </summary>
public object? MockTaskResult { get; set; }
/// <summary>
/// Gets or sets the list of tasks to return from tasks/list requests.
/// </summary>
public McpTask[]? MockTaskList { get; set; }
private async Task TasksGetAsync(JsonRpcRequest request, CancellationToken cancellationToken)
{
var task = MockTask ?? new McpTask
{
TaskId = "test-task-id",
Status = McpTaskStatus.Completed,
CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-5),
LastUpdatedAt = DateTimeOffset.UtcNow,
};
await WriteMessageAsync(new JsonRpcResponse
{
Id = request.Id,
Result = JsonSerializer.SerializeToNode(new ElicitResult { Action = "decline" }, McpJsonUtilities.DefaultOptions),
Result = JsonSerializer.SerializeToNode(new GetTaskResult
{
TaskId = task.TaskId,
Status = task.Status,
StatusMessage = task.StatusMessage,
CreatedAt = task.CreatedAt,
LastUpdatedAt = task.LastUpdatedAt,
TimeToLive = task.TimeToLive,
PollInterval = task.PollInterval
}, McpJsonUtilities.DefaultOptions),
}, cancellationToken);
}
private async Task TasksResultAsync(JsonRpcRequest request, CancellationToken cancellationToken)
{
var result = MockTaskResult ?? new CreateMessageResult
{
Content = [new TextContentBlock { Text = "Task result" }],
Model = "test-model"
};
await WriteMessageAsync(new JsonRpcResponse
{
Id = request.Id,
Result = JsonSerializer.SerializeToNode(result, McpJsonUtilities.DefaultOptions),
}, cancellationToken);
}
private async Task TasksListAsync(JsonRpcRequest request, CancellationToken cancellationToken)
{
var tasks = MockTaskList ?? [
new McpTask
{
TaskId = "task-1",
Status = McpTaskStatus.Completed,
CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-5),
LastUpdatedAt = DateTimeOffset.UtcNow,
},
new McpTask
{
TaskId = "task-2",
Status = McpTaskStatus.Working,
CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-3),
LastUpdatedAt = DateTimeOffset.UtcNow,
}
];
await WriteMessageAsync(new JsonRpcResponse
{
Id = request.Id,
Result = JsonSerializer.SerializeToNode(new ListTasksResult
{
Tasks = tasks,
}, McpJsonUtilities.DefaultOptions),
}, cancellationToken);
}
private async Task TasksCancelAsync(JsonRpcRequest request, CancellationToken cancellationToken)
{
var task = MockTask ?? new McpTask
{
TaskId = "test-task-id",
Status = McpTaskStatus.Cancelled,
StatusMessage = "Task cancelled by request",
CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-5),
LastUpdatedAt = DateTimeOffset.UtcNow,
};
await WriteMessageAsync(new JsonRpcResponse
{
Id = request.Id,
Result = JsonSerializer.SerializeToNode(new CancelMcpTaskResult
{
TaskId = task.TaskId,
Status = McpTaskStatus.Cancelled,
StatusMessage = task.StatusMessage ?? "Task cancelled",
CreatedAt = task.CreatedAt,
LastUpdatedAt = DateTimeOffset.UtcNow,
TimeToLive = task.TimeToLive,
PollInterval = task.PollInterval
}, McpJsonUtilities.DefaultOptions),
}, cancellationToken);
}