diff --git a/DotNetMcp.Tests/DotNetMcp.Tests.csproj b/DotNetMcp.Tests/DotNetMcp.Tests.csproj
index 852ca5a..a1e295b 100644
--- a/DotNetMcp.Tests/DotNetMcp.Tests.csproj
+++ b/DotNetMcp.Tests/DotNetMcp.Tests.csproj
@@ -14,7 +14,7 @@
-
+
diff --git a/DotNetMcp.Tests/Server/McpConformanceTests.cs b/DotNetMcp.Tests/Server/McpConformanceTests.cs
index ac73d3b..c44abf5 100644
--- a/DotNetMcp.Tests/Server/McpConformanceTests.cs
+++ b/DotNetMcp.Tests/Server/McpConformanceTests.cs
@@ -713,22 +713,21 @@ public async Task Server_CompleteHandler_ShouldReturnConfigurationSuggestions()
#endregion
- #region MCP Task Support Tests (Graceful Degradation)
+ #region MCP Task Support Tests
- // Task support is intentionally disabled: MCP SDK v1.1.0's ExecuteToolAsTaskAsync
- // disposes the DI scope before the background task resolves services, causing
- // ObjectDisposedException on every tool call. Without InMemoryMcpTaskStore,
- // the server runs tools synchronously and does not advertise task capabilities.
+ // Task support is enabled: MCP SDK v1.2.0 fixed the DI scope lifetime bug (#1430).
+ // InMemoryMcpTaskStore is registered, so tool calls with TaskSupport = Optional
+ // can run as background tasks.
[Fact]
- public void Server_ShouldNotAdvertiseTasksCapability_WhenTaskStoreNotRegistered()
+ public void Server_ShouldAdvertiseTasksCapability_WhenTaskStoreRegistered()
{
// Arrange
Assert.NotNull(_client);
- // Assert - no task store means no tasks capability advertised
+ // Assert - task store is registered so tasks capability is advertised
Assert.NotNull(_client.ServerCapabilities);
- Assert.Null(_client.ServerCapabilities.Tasks);
+ Assert.NotNull(_client.ServerCapabilities.Tasks);
}
[Fact]
@@ -741,10 +740,7 @@ public async Task Server_DotnetProject_ShouldDeclareTaskSupportOptional()
var tools = await _client.ListToolsAsync(cancellationToken: TestContext.Current.CancellationToken);
var projectTool = tools.FirstOrDefault(t => t.Name == "dotnet_project");
- // Assert - the tool attribute declares TaskSupport = Optional so it's ready when
- // task support is re-enabled by un-commenting the IMcpTaskStore registration in Program.cs
- // (pending fix of https://github.com/modelcontextprotocol/csharp-sdk/issues/1430).
- // Without a task store registered, the SDK runs it synchronously inline (graceful degradation).
+ // Assert - the tool attribute declares TaskSupport = Optional
Assert.NotNull(projectTool);
var execution = projectTool.ProtocolTool.Execution;
Assert.NotNull(execution);
@@ -752,12 +748,12 @@ public async Task Server_DotnetProject_ShouldDeclareTaskSupportOptional()
}
[Fact]
- public async Task Server_DotnetProject_ShouldWorkSynchronously()
+ public async Task Server_DotnetProject_ShouldWorkWithTaskStore()
{
- // Arrange - verify tools work reliably via normal tools/call (no tasks)
+ // Arrange - verify tools work reliably with task store registered
Assert.NotNull(_client);
- // Act - standard synchronous tool call
+ // Act - tool call (task store is present; SDK may run as task or inline)
var result = await _client.CallToolAsync(
"dotnet_project",
new Dictionary
diff --git a/DotNetMcp.Tests/Server/ServerCapabilitiesTests.cs b/DotNetMcp.Tests/Server/ServerCapabilitiesTests.cs
index 65b2b5c..6a7396b 100644
--- a/DotNetMcp.Tests/Server/ServerCapabilitiesTests.cs
+++ b/DotNetMcp.Tests/Server/ServerCapabilitiesTests.cs
@@ -2,6 +2,7 @@
using DotNetMcp;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
+using ModelContextProtocol;
using Xunit;
namespace DotNetMcp.Tests;
@@ -16,7 +17,7 @@ public ServerCapabilitiesTests()
{
_logger = NullLogger.Instance;
_concurrencyManager = new ConcurrencyManager();
- _tools = new DotNetCliTools(_logger, _concurrencyManager, new ProcessSessionManager());
+ _tools = new DotNetCliTools(_logger, _concurrencyManager, new ProcessSessionManager(), taskStore: new InMemoryMcpTaskStore());
}
[Fact]
@@ -210,7 +211,7 @@ public async Task DotnetServerCapabilities_SdkVersions_Lts_IsNet100()
}
[Fact]
- public async Task DotnetServerCapabilities_Supports_AsyncTasks_IsFalse()
+ public async Task DotnetServerCapabilities_Supports_AsyncTasks_IsTrue()
{
// Act
var result = (await _tools.DotnetServerCapabilities()).GetText();
@@ -220,8 +221,8 @@ public async Task DotnetServerCapabilities_Supports_AsyncTasks_IsFalse()
.GetProperty("asyncTasks")
.GetBoolean();
- // Assert - MCP Task support disabled due to SDK v1.1.0 DI scope lifetime bug
- Assert.False(asyncTasks);
+ // Assert - MCP Task support enabled with MCP SDK v1.2.0 fix for DI scope lifetime bug
+ Assert.True(asyncTasks);
}
[Fact]
@@ -262,7 +263,7 @@ public async Task DotnetServerCapabilities_JsonSchema_MatchesExpectedStructure()
Assert.True(capabilities.Supports.MachineReadable);
Assert.True(capabilities.Supports.Cancellation);
Assert.True(capabilities.Supports.Telemetry);
- Assert.False(capabilities.Supports.AsyncTasks);
+ Assert.True(capabilities.Supports.AsyncTasks);
Assert.True(capabilities.Supports.Prompts);
Assert.True(capabilities.Supports.Elicitation);
Assert.True(capabilities.Supports.Completions);
diff --git a/DotNetMcp/DotNetMcp.csproj b/DotNetMcp/DotNetMcp.csproj
index 2a2d5a4..d2896a6 100644
--- a/DotNetMcp/DotNetMcp.csproj
+++ b/DotNetMcp/DotNetMcp.csproj
@@ -51,7 +51,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/DotNetMcp/Program.cs b/DotNetMcp/Program.cs
index 226cd72..8cbbb3d 100644
--- a/DotNetMcp/Program.cs
+++ b/DotNetMcp/Program.cs
@@ -21,12 +21,8 @@
// Register ProcessSessionManager as a singleton
builder.Services.AddSingleton();
-// TODO: Re-enable InMemoryMcpTaskStore once the MCP SDK fixes the DI scope lifetime bug.
-// Upstream issue: https://github.com/modelcontextprotocol/csharp-sdk/issues/1430
-// MCP SDK v1.1.0's ExecuteToolAsTaskAsync disposes the request-scoped IServiceProvider
-// before the background task resolves services, causing ObjectDisposedException on every
-// tool call. Without a task store, the SDK runs tools synchronously inline.
-// builder.Services.AddSingleton();
+// Register InMemoryMcpTaskStore for async task support (MCP SDK v1.2.0 fixed #1430).
+builder.Services.AddSingleton();
// Register ToolMetricsAccumulator for in-memory telemetry collection.
// The accumulator is also captured by the telemetry filter added below.
diff --git a/DotNetMcp/Tools/Cli/DotNetCliTools.Misc.cs b/DotNetMcp/Tools/Cli/DotNetCliTools.Misc.cs
index fcb8fc5..67d6c58 100644
--- a/DotNetMcp/Tools/Cli/DotNetCliTools.Misc.cs
+++ b/DotNetMcp/Tools/Cli/DotNetCliTools.Misc.cs
@@ -71,7 +71,7 @@ public async partial Task DotnetServerCapabilities()
Cancellation = true,
Telemetry = true, // SDK v0.6+ supports request duration logging and OpenTelemetry semantic conventions
Metrics = true, // In-memory per-tool metrics via MCP message filter (dotnet_server_metrics tool)
- AsyncTasks = _taskStore != null, // Derived from DI: true when IMcpTaskStore is registered; currently false (MCP SDK DI scope bug https://github.com/modelcontextprotocol/csharp-sdk/issues/1430)
+ AsyncTasks = _taskStore != null, // Derived from DI: true when IMcpTaskStore is registered
Prompts = true, // Predefined prompt catalog: create_new_webapi, add_package_and_restore, run_tests_with_coverage
Elicitation = true, // Elicitation for confirmation before destructive ops (Clean, solution Remove)
McpLogging = true, // MCP log notifications sent to client during key operations (build, test, publish, restore, package add/update)
diff --git a/README.md b/README.md
index d1e301e..e8bf8fc 100644
--- a/README.md
+++ b/README.md
@@ -1096,7 +1096,7 @@ Key files to start with:
- 📖 [Concurrency Safety](doc/concurrency.md) - Parallel execution guidance for AI orchestrators
- 📖 [Testing](doc/testing.md) - How to run tests (including opt-in interactive tests)
- 📖 [Model Context Protocol](https://modelcontextprotocol.io/) - Official MCP specification
-- 📖 [MCP C# SDK Docs](https://modelcontextprotocol.github.io/csharp-sdk/) - SDK documentation
+- 📖 [MCP C# SDK Docs](https://csharp.sdk.modelcontextprotocol.io/) - SDK documentation
## Interoperability