From 3617a54512cb1deba05286f69ec4353f9ba4c85d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 11 Jun 2026 23:57:52 +0000
Subject: [PATCH 1/3] Initial plan
From f98dc145a97a92aa83a40a697a5917be8a1c6415 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 12 Jun 2026 00:02:48 +0000
Subject: [PATCH 2/3] Rename TtlMs/DefaultTtlMs to
TimeToLiveMs/DefaultTimeToLiveMs in public APIs
Co-authored-by: PranavSenthilnathan <12225508+PranavSenthilnathan@users.noreply.github.com>
---
.../Protocol/CreateTaskResult.cs | 2 +-
.../Protocol/GetTaskResult.cs | 8 ++++----
.../Protocol/TaskStatusNotificationParams.cs | 8 ++++----
.../Server/InMemoryMcpTaskStore.cs | 4 ++--
.../Server/McpServerImpl.cs | 12 ++++++------
src/ModelContextProtocol.Core/Server/McpTaskInfo.cs | 2 +-
.../Protocol/TaskSerializationTests.cs | 6 +++---
.../Server/InMemoryMcpTaskStoreTests.cs | 6 +++---
.../Server/TaskCancellationIntegrationTests.cs | 2 +-
9 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/src/ModelContextProtocol.Core/Protocol/CreateTaskResult.cs b/src/ModelContextProtocol.Core/Protocol/CreateTaskResult.cs
index 2e5bc0c41..8e68ba071 100644
--- a/src/ModelContextProtocol.Core/Protocol/CreateTaskResult.cs
+++ b/src/ModelContextProtocol.Core/Protocol/CreateTaskResult.cs
@@ -58,7 +58,7 @@ public sealed class CreateTaskResult : Result
/// Gets or sets the time-to-live duration from creation in milliseconds, or for unlimited.
///
[JsonPropertyName("ttlMs")]
- public long? TtlMs { get; set; }
+ public long? TimeToLiveMs { get; set; }
///
/// Gets or sets the suggested polling interval in milliseconds.
diff --git a/src/ModelContextProtocol.Core/Protocol/GetTaskResult.cs b/src/ModelContextProtocol.Core/Protocol/GetTaskResult.cs
index 9366f2374..e7d29ea6f 100644
--- a/src/ModelContextProtocol.Core/Protocol/GetTaskResult.cs
+++ b/src/ModelContextProtocol.Core/Protocol/GetTaskResult.cs
@@ -67,7 +67,7 @@ private protected GetTaskResult()
/// Gets or sets the time-to-live duration from creation in milliseconds, or for unlimited.
///
[JsonPropertyName("ttlMs")]
- public long? TtlMs { get; set; }
+ public long? TimeToLiveMs { get; set; }
///
/// Gets or sets the suggested polling interval in milliseconds.
@@ -245,7 +245,7 @@ internal sealed class Converter : JsonConverter
};
taskResult.StatusMessage = statusMessage;
- taskResult.TtlMs = ttlMs;
+ taskResult.TimeToLiveMs = ttlMs;
taskResult.PollIntervalMs = pollIntervalMs;
taskResult.ResultType = resultType;
taskResult.Meta = meta;
@@ -287,9 +287,9 @@ public override void Write(Utf8JsonWriter writer, GetTaskResult value, JsonSeria
writer.WriteString("createdAt", value.CreatedAt);
writer.WriteString("lastUpdatedAt", value.LastUpdatedAt);
- if (value.TtlMs is not null)
+ if (value.TimeToLiveMs is not null)
{
- writer.WriteNumber("ttlMs", value.TtlMs.Value);
+ writer.WriteNumber("ttlMs", value.TimeToLiveMs.Value);
}
if (value.PollIntervalMs is not null)
diff --git a/src/ModelContextProtocol.Core/Protocol/TaskStatusNotificationParams.cs b/src/ModelContextProtocol.Core/Protocol/TaskStatusNotificationParams.cs
index e1bbb2f73..b3094d85a 100644
--- a/src/ModelContextProtocol.Core/Protocol/TaskStatusNotificationParams.cs
+++ b/src/ModelContextProtocol.Core/Protocol/TaskStatusNotificationParams.cs
@@ -73,7 +73,7 @@ private protected TaskStatusNotificationParams()
/// Gets or sets the time-to-live duration from creation in milliseconds, or for unlimited.
///
[JsonPropertyName("ttlMs")]
- public long? TtlMs { get; set; }
+ public long? TimeToLiveMs { get; set; }
///
/// Gets or sets the suggested polling interval in milliseconds.
@@ -247,7 +247,7 @@ internal sealed class Converter : JsonConverter
};
notification.StatusMessage = statusMessage;
- notification.TtlMs = ttlMs;
+ notification.TimeToLiveMs = ttlMs;
notification.PollIntervalMs = pollIntervalMs;
notification.Meta = meta;
@@ -283,9 +283,9 @@ public override void Write(Utf8JsonWriter writer, TaskStatusNotificationParams v
writer.WriteString("createdAt", value.CreatedAt);
writer.WriteString("lastUpdatedAt", value.LastUpdatedAt);
- if (value.TtlMs is not null)
+ if (value.TimeToLiveMs is not null)
{
- writer.WriteNumber("ttlMs", value.TtlMs.Value);
+ writer.WriteNumber("ttlMs", value.TimeToLiveMs.Value);
}
if (value.PollIntervalMs is not null)
diff --git a/src/ModelContextProtocol.Core/Server/InMemoryMcpTaskStore.cs b/src/ModelContextProtocol.Core/Server/InMemoryMcpTaskStore.cs
index a13af13e9..7be53c17d 100644
--- a/src/ModelContextProtocol.Core/Server/InMemoryMcpTaskStore.cs
+++ b/src/ModelContextProtocol.Core/Server/InMemoryMcpTaskStore.cs
@@ -34,7 +34,7 @@ public class InMemoryMcpTaskStore : IMcpTaskStore
///
/// Gets or sets the default time-to-live in milliseconds for new tasks, or for unlimited.
///
- public long? DefaultTtlMs { get; set; }
+ public long? DefaultTimeToLiveMs { get; set; }
///
public Task CreateTaskAsync(CancellationToken cancellationToken = default)
@@ -42,7 +42,7 @@ public Task CreateTaskAsync(CancellationToken cancellationToken = d
var taskId = Guid.NewGuid().ToString("N");
var now = DateTimeOffset.UtcNow;
- var info = new McpTaskInfo(taskId, McpTaskStatus.Working, now, now, DefaultTtlMs, DefaultPollIntervalMs);
+ var info = new McpTaskInfo(taskId, McpTaskStatus.Working, now, now, DefaultTimeToLiveMs, DefaultPollIntervalMs);
_tasks[taskId] = info;
return Task.FromResult(info);
diff --git a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs
index 85b1cc26a..84f0b7e6b 100644
--- a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs
+++ b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs
@@ -1009,7 +1009,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
Status = info.Status,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TtlMs = info.TtlMs,
+ TimeToLiveMs = info.TimeToLiveMs,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
ResultType = "task",
@@ -1022,7 +1022,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
TaskId = info.TaskId,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TtlMs = info.TtlMs,
+ TimeToLiveMs = info.TimeToLiveMs,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
ResultType = "complete",
@@ -1032,7 +1032,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
TaskId = info.TaskId,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TtlMs = info.TtlMs,
+ TimeToLiveMs = info.TimeToLiveMs,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
Result = info.Result ?? throw new InvalidOperationException($"Task '{info.TaskId}' is completed but has no result."),
@@ -1043,7 +1043,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
TaskId = info.TaskId,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TtlMs = info.TtlMs,
+ TimeToLiveMs = info.TimeToLiveMs,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
Error = info.Error ?? throw new InvalidOperationException($"Task '{info.TaskId}' is failed but has no error."),
@@ -1054,7 +1054,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
TaskId = info.TaskId,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TtlMs = info.TtlMs,
+ TimeToLiveMs = info.TimeToLiveMs,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
ResultType = "complete",
@@ -1064,7 +1064,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
TaskId = info.TaskId,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TtlMs = info.TtlMs,
+ TimeToLiveMs = info.TimeToLiveMs,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
// McpTaskInfo.InputRequests is IReadOnlyDictionary (covers immutable store
diff --git a/src/ModelContextProtocol.Core/Server/McpTaskInfo.cs b/src/ModelContextProtocol.Core/Server/McpTaskInfo.cs
index ab71d6505..855116c97 100644
--- a/src/ModelContextProtocol.Core/Server/McpTaskInfo.cs
+++ b/src/ModelContextProtocol.Core/Server/McpTaskInfo.cs
@@ -20,7 +20,7 @@ public sealed record McpTaskInfo(
McpTaskStatus Status,
DateTimeOffset CreatedAt,
DateTimeOffset LastUpdatedAt,
- long? TtlMs = null,
+ long? TimeToLiveMs = null,
long? PollIntervalMs = null,
string? StatusMessage = null,
JsonElement? Result = null,
diff --git a/tests/ModelContextProtocol.Tests/Protocol/TaskSerializationTests.cs b/tests/ModelContextProtocol.Tests/Protocol/TaskSerializationTests.cs
index 556403add..b57980660 100644
--- a/tests/ModelContextProtocol.Tests/Protocol/TaskSerializationTests.cs
+++ b/tests/ModelContextProtocol.Tests/Protocol/TaskSerializationTests.cs
@@ -21,7 +21,7 @@ public static void CreateTaskResult_SerializationRoundTrip_PreservesAllPropertie
StatusMessage = "Processing...",
CreatedAt = new DateTimeOffset(2025, 6, 1, 12, 0, 0, TimeSpan.Zero),
LastUpdatedAt = new DateTimeOffset(2025, 6, 1, 12, 5, 0, TimeSpan.Zero),
- TtlMs = 3600000,
+ TimeToLiveMs = 3600000,
PollIntervalMs = 5000,
ResultType = "task",
Meta = new JsonObject { ["key"] = "value" }
@@ -36,7 +36,7 @@ public static void CreateTaskResult_SerializationRoundTrip_PreservesAllPropertie
Assert.Equal("Processing...", deserialized.StatusMessage);
Assert.Equal(original.CreatedAt, deserialized.CreatedAt);
Assert.Equal(original.LastUpdatedAt, deserialized.LastUpdatedAt);
- Assert.Equal(3600000, deserialized.TtlMs);
+ Assert.Equal(3600000, deserialized.TimeToLiveMs);
Assert.Equal(5000, deserialized.PollIntervalMs);
Assert.Equal("task", deserialized.ResultType);
Assert.NotNull(deserialized.Meta);
@@ -52,7 +52,7 @@ public static void CreateTaskResult_UsesCorrectWireFieldNames()
Status = McpTaskStatus.Working,
CreatedAt = DateTimeOffset.UtcNow,
LastUpdatedAt = DateTimeOffset.UtcNow,
- TtlMs = 60000,
+ TimeToLiveMs = 60000,
PollIntervalMs = 1000,
ResultType = "task",
};
diff --git a/tests/ModelContextProtocol.Tests/Server/InMemoryMcpTaskStoreTests.cs b/tests/ModelContextProtocol.Tests/Server/InMemoryMcpTaskStoreTests.cs
index 7c87786eb..09a230747 100644
--- a/tests/ModelContextProtocol.Tests/Server/InMemoryMcpTaskStoreTests.cs
+++ b/tests/ModelContextProtocol.Tests/Server/InMemoryMcpTaskStoreTests.cs
@@ -55,13 +55,13 @@ public async Task CreateTaskAsync_UsesDefaultPollInterval()
}
[Fact]
- public async Task CreateTaskAsync_UsesDefaultTtl()
+ public async Task CreateTaskAsync_UsesDefaultTimeToLive()
{
- var store = new InMemoryMcpTaskStore { DefaultTtlMs = 30000 };
+ var store = new InMemoryMcpTaskStore { DefaultTimeToLiveMs = 30000 };
var result = await store.CreateTaskAsync(CT);
- Assert.Equal(30000, result.TtlMs);
+ Assert.Equal(30000, result.TimeToLiveMs);
}
[Fact]
diff --git a/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs b/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs
index 1b424d002..91609d817 100644
--- a/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs
+++ b/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs
@@ -34,7 +34,7 @@ protected override void ConfigureServices(ServiceCollection services, IMcpServer
options.TaskStore = new InMemoryMcpTaskStore
{
DefaultPollIntervalMs = 50,
- DefaultTtlMs = 5000,
+ DefaultTimeToLiveMs = 5000,
};
});
From 326342d4616378ecf77de883e11636cbef9dff7a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 12 Jun 2026 01:01:20 +0000
Subject: [PATCH 3/3] Change TimeToLiveMs (long?) to TimeToLive (TimeSpan?)
with TimeSpanMillisecondsConverter
Co-authored-by: PranavSenthilnathan <12225508+PranavSenthilnathan@users.noreply.github.com>
---
.../Protocol/CreateTaskResult.cs | 5 +++--
.../Protocol/GetTaskResult.cs | 10 +++++-----
.../Protocol/TaskStatusNotificationParams.cs | 10 +++++-----
.../Protocol/TimeSpanMillisecondsConverter.cs | 19 +++++++++++++++++++
.../Server/InMemoryMcpTaskStore.cs | 6 +++---
.../Server/McpServerImpl.cs | 12 ++++++------
.../Server/McpTaskInfo.cs | 2 +-
.../Protocol/TaskSerializationTests.cs | 6 +++---
.../Server/InMemoryMcpTaskStoreTests.cs | 4 ++--
.../TaskCancellationIntegrationTests.cs | 2 +-
10 files changed, 48 insertions(+), 28 deletions(-)
create mode 100644 src/ModelContextProtocol.Core/Protocol/TimeSpanMillisecondsConverter.cs
diff --git a/src/ModelContextProtocol.Core/Protocol/CreateTaskResult.cs b/src/ModelContextProtocol.Core/Protocol/CreateTaskResult.cs
index 8e68ba071..6d9bac23c 100644
--- a/src/ModelContextProtocol.Core/Protocol/CreateTaskResult.cs
+++ b/src/ModelContextProtocol.Core/Protocol/CreateTaskResult.cs
@@ -55,10 +55,11 @@ public sealed class CreateTaskResult : Result
public required DateTimeOffset LastUpdatedAt { get; set; }
///
- /// Gets or sets the time-to-live duration from creation in milliseconds, or for unlimited.
+ /// Gets or sets the time-to-live duration from creation, or for unlimited.
///
[JsonPropertyName("ttlMs")]
- public long? TimeToLiveMs { get; set; }
+ [JsonConverter(typeof(TimeSpanMillisecondsConverter))]
+ public TimeSpan? TimeToLive { get; set; }
///
/// Gets or sets the suggested polling interval in milliseconds.
diff --git a/src/ModelContextProtocol.Core/Protocol/GetTaskResult.cs b/src/ModelContextProtocol.Core/Protocol/GetTaskResult.cs
index e7d29ea6f..3fea8cc6b 100644
--- a/src/ModelContextProtocol.Core/Protocol/GetTaskResult.cs
+++ b/src/ModelContextProtocol.Core/Protocol/GetTaskResult.cs
@@ -64,10 +64,10 @@ private protected GetTaskResult()
public required DateTimeOffset LastUpdatedAt { get; set; }
///
- /// Gets or sets the time-to-live duration from creation in milliseconds, or for unlimited.
+ /// Gets or sets the time-to-live duration from creation, or for unlimited.
///
[JsonPropertyName("ttlMs")]
- public long? TimeToLiveMs { get; set; }
+ public TimeSpan? TimeToLive { get; set; }
///
/// Gets or sets the suggested polling interval in milliseconds.
@@ -245,7 +245,7 @@ internal sealed class Converter : JsonConverter
};
taskResult.StatusMessage = statusMessage;
- taskResult.TimeToLiveMs = ttlMs;
+ taskResult.TimeToLive = ttlMs is null ? null : TimeSpan.FromMilliseconds(ttlMs.Value);
taskResult.PollIntervalMs = pollIntervalMs;
taskResult.ResultType = resultType;
taskResult.Meta = meta;
@@ -287,9 +287,9 @@ public override void Write(Utf8JsonWriter writer, GetTaskResult value, JsonSeria
writer.WriteString("createdAt", value.CreatedAt);
writer.WriteString("lastUpdatedAt", value.LastUpdatedAt);
- if (value.TimeToLiveMs is not null)
+ if (value.TimeToLive is not null)
{
- writer.WriteNumber("ttlMs", value.TimeToLiveMs.Value);
+ writer.WriteNumber("ttlMs", (long)value.TimeToLive.Value.TotalMilliseconds);
}
if (value.PollIntervalMs is not null)
diff --git a/src/ModelContextProtocol.Core/Protocol/TaskStatusNotificationParams.cs b/src/ModelContextProtocol.Core/Protocol/TaskStatusNotificationParams.cs
index b3094d85a..4e859a22c 100644
--- a/src/ModelContextProtocol.Core/Protocol/TaskStatusNotificationParams.cs
+++ b/src/ModelContextProtocol.Core/Protocol/TaskStatusNotificationParams.cs
@@ -70,10 +70,10 @@ private protected TaskStatusNotificationParams()
public required DateTimeOffset LastUpdatedAt { get; set; }
///
- /// Gets or sets the time-to-live duration from creation in milliseconds, or for unlimited.
+ /// Gets or sets the time-to-live duration from creation, or for unlimited.
///
[JsonPropertyName("ttlMs")]
- public long? TimeToLiveMs { get; set; }
+ public TimeSpan? TimeToLive { get; set; }
///
/// Gets or sets the suggested polling interval in milliseconds.
@@ -247,7 +247,7 @@ internal sealed class Converter : JsonConverter
};
notification.StatusMessage = statusMessage;
- notification.TimeToLiveMs = ttlMs;
+ notification.TimeToLive = ttlMs is null ? null : TimeSpan.FromMilliseconds(ttlMs.Value);
notification.PollIntervalMs = pollIntervalMs;
notification.Meta = meta;
@@ -283,9 +283,9 @@ public override void Write(Utf8JsonWriter writer, TaskStatusNotificationParams v
writer.WriteString("createdAt", value.CreatedAt);
writer.WriteString("lastUpdatedAt", value.LastUpdatedAt);
- if (value.TimeToLiveMs is not null)
+ if (value.TimeToLive is not null)
{
- writer.WriteNumber("ttlMs", value.TimeToLiveMs.Value);
+ writer.WriteNumber("ttlMs", (long)value.TimeToLive.Value.TotalMilliseconds);
}
if (value.PollIntervalMs is not null)
diff --git a/src/ModelContextProtocol.Core/Protocol/TimeSpanMillisecondsConverter.cs b/src/ModelContextProtocol.Core/Protocol/TimeSpanMillisecondsConverter.cs
new file mode 100644
index 000000000..9ad646b48
--- /dev/null
+++ b/src/ModelContextProtocol.Core/Protocol/TimeSpanMillisecondsConverter.cs
@@ -0,0 +1,19 @@
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace ModelContextProtocol.Protocol;
+
+///
+/// Provides a JSON converter for values that serializes and deserializes
+/// them as a whole-millisecond integer.
+///
+public sealed class TimeSpanMillisecondsConverter : JsonConverter
+{
+ ///
+ public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ => TimeSpan.FromMilliseconds(reader.GetDouble());
+
+ ///
+ public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
+ => writer.WriteNumberValue((long)value.TotalMilliseconds);
+}
diff --git a/src/ModelContextProtocol.Core/Server/InMemoryMcpTaskStore.cs b/src/ModelContextProtocol.Core/Server/InMemoryMcpTaskStore.cs
index 7be53c17d..00c69844b 100644
--- a/src/ModelContextProtocol.Core/Server/InMemoryMcpTaskStore.cs
+++ b/src/ModelContextProtocol.Core/Server/InMemoryMcpTaskStore.cs
@@ -32,9 +32,9 @@ public class InMemoryMcpTaskStore : IMcpTaskStore
public long DefaultPollIntervalMs { get; set; } = 1000;
///
- /// Gets or sets the default time-to-live in milliseconds for new tasks, or for unlimited.
+ /// Gets or sets the default time-to-live for new tasks, or for unlimited.
///
- public long? DefaultTimeToLiveMs { get; set; }
+ public TimeSpan? DefaultTimeToLive { get; set; }
///
public Task CreateTaskAsync(CancellationToken cancellationToken = default)
@@ -42,7 +42,7 @@ public Task CreateTaskAsync(CancellationToken cancellationToken = d
var taskId = Guid.NewGuid().ToString("N");
var now = DateTimeOffset.UtcNow;
- var info = new McpTaskInfo(taskId, McpTaskStatus.Working, now, now, DefaultTimeToLiveMs, DefaultPollIntervalMs);
+ var info = new McpTaskInfo(taskId, McpTaskStatus.Working, now, now, DefaultTimeToLive, DefaultPollIntervalMs);
_tasks[taskId] = info;
return Task.FromResult(info);
diff --git a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs
index 84f0b7e6b..1cce71c70 100644
--- a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs
+++ b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs
@@ -1009,7 +1009,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
Status = info.Status,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TimeToLiveMs = info.TimeToLiveMs,
+ TimeToLive = info.TimeToLive,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
ResultType = "task",
@@ -1022,7 +1022,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
TaskId = info.TaskId,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TimeToLiveMs = info.TimeToLiveMs,
+ TimeToLive = info.TimeToLive,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
ResultType = "complete",
@@ -1032,7 +1032,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
TaskId = info.TaskId,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TimeToLiveMs = info.TimeToLiveMs,
+ TimeToLive = info.TimeToLive,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
Result = info.Result ?? throw new InvalidOperationException($"Task '{info.TaskId}' is completed but has no result."),
@@ -1043,7 +1043,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
TaskId = info.TaskId,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TimeToLiveMs = info.TimeToLiveMs,
+ TimeToLive = info.TimeToLive,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
Error = info.Error ?? throw new InvalidOperationException($"Task '{info.TaskId}' is failed but has no error."),
@@ -1054,7 +1054,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
TaskId = info.TaskId,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TimeToLiveMs = info.TimeToLiveMs,
+ TimeToLive = info.TimeToLive,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
ResultType = "complete",
@@ -1064,7 +1064,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
TaskId = info.TaskId,
CreatedAt = info.CreatedAt,
LastUpdatedAt = info.LastUpdatedAt,
- TimeToLiveMs = info.TimeToLiveMs,
+ TimeToLive = info.TimeToLive,
PollIntervalMs = info.PollIntervalMs,
StatusMessage = info.StatusMessage,
// McpTaskInfo.InputRequests is IReadOnlyDictionary (covers immutable store
diff --git a/src/ModelContextProtocol.Core/Server/McpTaskInfo.cs b/src/ModelContextProtocol.Core/Server/McpTaskInfo.cs
index 855116c97..87fa8ef1c 100644
--- a/src/ModelContextProtocol.Core/Server/McpTaskInfo.cs
+++ b/src/ModelContextProtocol.Core/Server/McpTaskInfo.cs
@@ -20,7 +20,7 @@ public sealed record McpTaskInfo(
McpTaskStatus Status,
DateTimeOffset CreatedAt,
DateTimeOffset LastUpdatedAt,
- long? TimeToLiveMs = null,
+ TimeSpan? TimeToLive = null,
long? PollIntervalMs = null,
string? StatusMessage = null,
JsonElement? Result = null,
diff --git a/tests/ModelContextProtocol.Tests/Protocol/TaskSerializationTests.cs b/tests/ModelContextProtocol.Tests/Protocol/TaskSerializationTests.cs
index b57980660..86acc57f6 100644
--- a/tests/ModelContextProtocol.Tests/Protocol/TaskSerializationTests.cs
+++ b/tests/ModelContextProtocol.Tests/Protocol/TaskSerializationTests.cs
@@ -21,7 +21,7 @@ public static void CreateTaskResult_SerializationRoundTrip_PreservesAllPropertie
StatusMessage = "Processing...",
CreatedAt = new DateTimeOffset(2025, 6, 1, 12, 0, 0, TimeSpan.Zero),
LastUpdatedAt = new DateTimeOffset(2025, 6, 1, 12, 5, 0, TimeSpan.Zero),
- TimeToLiveMs = 3600000,
+ TimeToLive = TimeSpan.FromHours(1),
PollIntervalMs = 5000,
ResultType = "task",
Meta = new JsonObject { ["key"] = "value" }
@@ -36,7 +36,7 @@ public static void CreateTaskResult_SerializationRoundTrip_PreservesAllPropertie
Assert.Equal("Processing...", deserialized.StatusMessage);
Assert.Equal(original.CreatedAt, deserialized.CreatedAt);
Assert.Equal(original.LastUpdatedAt, deserialized.LastUpdatedAt);
- Assert.Equal(3600000, deserialized.TimeToLiveMs);
+ Assert.Equal(TimeSpan.FromHours(1), deserialized.TimeToLive);
Assert.Equal(5000, deserialized.PollIntervalMs);
Assert.Equal("task", deserialized.ResultType);
Assert.NotNull(deserialized.Meta);
@@ -52,7 +52,7 @@ public static void CreateTaskResult_UsesCorrectWireFieldNames()
Status = McpTaskStatus.Working,
CreatedAt = DateTimeOffset.UtcNow,
LastUpdatedAt = DateTimeOffset.UtcNow,
- TimeToLiveMs = 60000,
+ TimeToLive = TimeSpan.FromMinutes(1),
PollIntervalMs = 1000,
ResultType = "task",
};
diff --git a/tests/ModelContextProtocol.Tests/Server/InMemoryMcpTaskStoreTests.cs b/tests/ModelContextProtocol.Tests/Server/InMemoryMcpTaskStoreTests.cs
index 09a230747..83afbfe23 100644
--- a/tests/ModelContextProtocol.Tests/Server/InMemoryMcpTaskStoreTests.cs
+++ b/tests/ModelContextProtocol.Tests/Server/InMemoryMcpTaskStoreTests.cs
@@ -57,11 +57,11 @@ public async Task CreateTaskAsync_UsesDefaultPollInterval()
[Fact]
public async Task CreateTaskAsync_UsesDefaultTimeToLive()
{
- var store = new InMemoryMcpTaskStore { DefaultTimeToLiveMs = 30000 };
+ var store = new InMemoryMcpTaskStore { DefaultTimeToLive = TimeSpan.FromSeconds(30) };
var result = await store.CreateTaskAsync(CT);
- Assert.Equal(30000, result.TimeToLiveMs);
+ Assert.Equal(TimeSpan.FromSeconds(30), result.TimeToLive);
}
[Fact]
diff --git a/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs b/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs
index 91609d817..0e8693353 100644
--- a/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs
+++ b/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs
@@ -34,7 +34,7 @@ protected override void ConfigureServices(ServiceCollection services, IMcpServer
options.TaskStore = new InMemoryMcpTaskStore
{
DefaultPollIntervalMs = 50,
- DefaultTimeToLiveMs = 5000,
+ DefaultTimeToLive = TimeSpan.FromSeconds(5),
};
});