Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DotNetMcp.Tests/DotNetMcp.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<OutputType>Exe</OutputType>
<!-- MCPEXP001: Task-related APIs (IMcpTaskStore, ToolTaskSupport, McpTasksCapability) are experimental in the MCP SDK -->
<NoWarn>$(NoWarn);MCPEXP001</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
59 changes: 59 additions & 0 deletions DotNetMcp.Tests/Server/McpConformanceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,65 @@ public async Task Server_ResourceList_ShouldHaveValidStructure()

#endregion

#region MCP Task Support Tests

[Fact]
public void Server_ShouldAdvertiseTasksCapability()
{
// Arrange
Assert.NotNull(_client);

// Assert - server should expose tasks capability (InMemoryMcpTaskStore is registered)
Assert.NotNull(_client.ServerCapabilities);
Assert.NotNull(_client.ServerCapabilities.Tasks);
}

[Fact]
public void Server_TasksCapability_ShouldSupportListAndCancel()
{
// Arrange
Assert.NotNull(_client);

// Assert
var tasks = _client.ServerCapabilities?.Tasks;
Assert.NotNull(tasks);
Assert.NotNull(tasks.List);
Assert.NotNull(tasks.Cancel);
}

[Fact]
public async Task Server_DotnetProject_ShouldHaveTaskSupport()
{
// Arrange
Assert.NotNull(_client);

// Act
var tools = await _client.ListToolsAsync(cancellationToken: TestContext.Current.CancellationToken);
var projectTool = tools.FirstOrDefault(t => t.Name == "dotnet_project");

// Assert - dotnet_project should declare TaskSupport = Optional so clients can run
// long operations (build, test, publish) as async tasks
Assert.NotNull(projectTool);
var execution = projectTool.ProtocolTool.Execution;
Assert.NotNull(execution);
Assert.Equal(ModelContextProtocol.Protocol.ToolTaskSupport.Optional, execution.TaskSupport);
}

[Fact]
public async Task Server_TaskList_ShouldReturnEmptyWhenNoTasksRunning()
{
// Arrange
Assert.NotNull(_client);

// Act
var tasks = await _client.ListTasksAsync(cancellationToken: TestContext.Current.CancellationToken);

// Assert - no tasks should be running at server start
Assert.NotNull(tasks);
}

#endregion

#region Helper Methods

/// <summary>
Expand Down
16 changes: 16 additions & 0 deletions DotNetMcp.Tests/Server/ServerCapabilitiesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,21 @@ public async Task DotnetServerCapabilities_SdkVersions_Lts_IsNet100()
Assert.Equal("net10.0", lts);
}

[Fact]
public async Task DotnetServerCapabilities_Supports_AsyncTasks_IsTrue()
{
// Act
var result = (await _tools.DotnetServerCapabilities()).GetText();
var jsonDoc = JsonDocument.Parse(result);
var asyncTasks = jsonDoc.RootElement
.GetProperty("supports")
.GetProperty("asyncTasks")
.GetBoolean();

// Assert - MCP Task support is enabled via InMemoryMcpTaskStore
Assert.True(asyncTasks);
}

[Fact]
public async Task DotnetServerCapabilities_JsonSchema_MatchesExpectedStructure()
{
Expand All @@ -232,6 +247,7 @@ public async Task DotnetServerCapabilities_JsonSchema_MatchesExpectedStructure()
Assert.True(capabilities.Supports.MachineReadable);
Assert.True(capabilities.Supports.Cancellation);
Assert.True(capabilities.Supports.Telemetry);
Assert.True(capabilities.Supports.AsyncTasks);
Assert.NotNull(capabilities.SdkVersions);
Assert.NotEmpty(capabilities.SdkVersions.Installed);
Assert.Equal("net10.0", capabilities.SdkVersions.Recommended);
Expand Down
3 changes: 2 additions & 1 deletion DotNetMcp/DotNetMcp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
<!-- Suppress CS1591 for missing XML comments on non-tool classes -->
<!-- The source generator creates [Description] attributes from XML documentation for MCP tool methods -->
<!-- CS1066 is now automatically suppressed by the SDK for MCP server methods -->
<NoWarn>$(NoWarn);CS1591</NoWarn>
<!-- MCPEXP001: IMcpTaskStore and related task APIs are experimental in the MCP SDK -->
<NoWarn>$(NoWarn);CS1591;MCPEXP001</NoWarn>

<!-- NuGet Package Metadata -->
<PackageId>Community.Mcp.DotNet</PackageId>
Expand Down
5 changes: 5 additions & 0 deletions DotNetMcp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol;
using ModelContextProtocol.Protocol;

var builder = Host.CreateApplicationBuilder(args);
Expand All @@ -17,6 +18,10 @@
// Register ProcessSessionManager as a singleton
builder.Services.AddSingleton<ProcessSessionManager>();

// Register InMemoryMcpTaskStore to enable MCP Task support for long-running operations.
// This allows AI clients to run build/test/publish as async tasks with polling and cancellation.
builder.Services.AddSingleton<IMcpTaskStore, InMemoryMcpTaskStore>();

builder.Services.AddMcpServer(options =>
{
// Configure server implementation with .NET-themed icon
Expand Down
8 changes: 8 additions & 0 deletions DotNetMcp/Server/ServerCapabilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ public sealed class ServerFeatureSupport
/// </summary>
[JsonPropertyName("telemetry")]
public bool Telemetry { get; init; }

/// <summary>
/// Whether the server supports MCP Task augmentation for long-running operations such as
/// build, test, and publish. When true, AI clients can call supported tools as async tasks
/// and poll for completion instead of blocking on the result.
/// </summary>
[JsonPropertyName("asyncTasks")]
public bool AsyncTasks { get; init; }
}

/// <summary>
Expand Down
3 changes: 2 additions & 1 deletion DotNetMcp/Tools/Cli/DotNetCliTools.Misc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ public async partial Task<CallToolResult> DotnetServerCapabilities()
StructuredErrors = true,
MachineReadable = true,
Cancellation = true,
Telemetry = true // SDK v0.6+ supports request duration logging and OpenTelemetry semantic conventions
Telemetry = true, // SDK v0.6+ supports request duration logging and OpenTelemetry semantic conventions
AsyncTasks = true // MCP Task support enabled: long-running operations (build, test, publish) can run as async tasks
},
SdkVersions = new SdkVersionInfo
{
Expand Down
2 changes: 1 addition & 1 deletion DotNetMcp/Tools/Cli/DotNetCliTools.Project.Consolidated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
/// <param name="propertyValue">Value to set for SetProperty action (e.g., 'Exe')</param>
/// <param name="itemType">Item type for AddItem/RemoveItem/ListItems actions (e.g., 'Using', 'Content', 'None')</param>
/// <param name="include">The Include attribute value for AddItem/RemoveItem actions</param>
[McpServerTool(Title = ".NET Project", Destructive = true, IconSource = "https://raw.githubusercontent.com/microsoft/fluentui-emoji/62ecdc0d7ca5c6df32148c169556bc8d3782fca4/assets/File%20Folder/Flat/file_folder_flat.svg")]
[McpServerTool(Title = ".NET Project", Destructive = true, TaskSupport = ToolTaskSupport.Optional, IconSource = "https://raw.githubusercontent.com/microsoft/fluentui-emoji/62ecdc0d7ca5c6df32148c169556bc8d3782fca4/assets/File%20Folder/Flat/file_folder_flat.svg")]
[McpMeta("category", "project")]
[McpMeta("priority", 10.0)]
[McpMeta("commonlyUsed", true)]
Expand Down Expand Up @@ -916,7 +916,7 @@

// Determine project argument style based on effective runner
bool usePositionalArg = effectiveRunner == TestRunner.VSTest;
string projectArgumentStyle;

Check warning on line 919 in DotNetMcp/Tools/Cli/DotNetCliTools.Project.Consolidated.cs

View workflow job for this annotation

GitHub Actions / build

The variable 'projectArgumentStyle' is assigned but its value is never used

Check warning on line 919 in DotNetMcp/Tools/Cli/DotNetCliTools.Project.Consolidated.cs

View workflow job for this annotation

GitHub Actions / build

The variable 'projectArgumentStyle' is assigned but its value is never used

if (!string.IsNullOrEmpty(project))
{
Expand Down
Loading