Implement SEP-2663 Tasks Extension (#1579)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
ed07fdb6f4
commit
dbb7a20176
2 changed files with 8190 additions and 11405 deletions
|
|
@ -72,12 +72,23 @@ public class McpServerBuilderExtensionsMessageFilterTests(ITestOutputHelper test
|
|||
{
|
||||
List<string> messageTypes = [];
|
||||
|
||||
// The client sends notifications/initialized fire-and-forget, so unlike the initialize and
|
||||
// tools/list request/response exchanges it has no synchronization point the test can await.
|
||||
// Signal once the filter finishes processing it so the strict counts below observe a
|
||||
// complete, stable log instead of racing the still-in-flight notification.
|
||||
var initializedNotificationProcessed = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
McpServerBuilder
|
||||
.WithMessageFilters(filters => filters.AddIncomingFilter((next) => async (context, cancellationToken) =>
|
||||
{
|
||||
var messageTypeName = context.JsonRpcMessage.GetType().Name;
|
||||
messageTypes.Add(messageTypeName);
|
||||
await next(context, cancellationToken);
|
||||
|
||||
if (context.JsonRpcMessage is JsonRpcNotification { Method: NotificationMethods.InitializedNotification })
|
||||
{
|
||||
initializedNotificationProcessed.TrySetResult(true);
|
||||
}
|
||||
}))
|
||||
.WithTools<TestTool>();
|
||||
|
||||
|
|
@ -87,6 +98,10 @@ public class McpServerBuilderExtensionsMessageFilterTests(ITestOutputHelper test
|
|||
|
||||
await client.ListToolsAsync(cancellationToken: TestContext.Current.CancellationToken);
|
||||
|
||||
// Wait for the fire-and-forget initialized notification to flow through the filter pipeline
|
||||
// before snapshotting the counts; otherwise the strict counts below can race the notification.
|
||||
await initializedNotificationProcessed.Task.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken);
|
||||
|
||||
// The message filter should intercept JsonRpcRequest messages.
|
||||
// Use strict counts so a regression that invokes the filter pipeline more than once per
|
||||
// incoming message (analogous to the SendRequestAsync double-wrap regression on the outgoing
|
||||
|
|
|
|||
|
|
@ -284,57 +284,4 @@ public class McpServerOptionsSetupTests
|
|||
Assert.NotNull(options.Capabilities?.Completions);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region TaskStore Tests
|
||||
[Fact]
|
||||
public void TaskStore_IsPopulatedFromDI_WhenNotExplicitlySet()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddMcpServer();
|
||||
services.AddSingleton<IMcpTaskStore, InMemoryMcpTaskStore>();
|
||||
|
||||
var options = services.BuildServiceProvider().GetRequiredService<IOptions<McpServerOptions>>().Value;
|
||||
|
||||
Assert.IsType<InMemoryMcpTaskStore>(options.TaskStore);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TaskStore_ExplicitOption_TakesPrecedenceOverDI()
|
||||
{
|
||||
var explicitStore = new InMemoryMcpTaskStore();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddMcpServer(options => options.TaskStore = explicitStore);
|
||||
services.AddSingleton<IMcpTaskStore, InMemoryMcpTaskStore>();
|
||||
|
||||
var options = services.BuildServiceProvider().GetRequiredService<IOptions<McpServerOptions>>().Value;
|
||||
|
||||
Assert.Same(explicitStore, options.TaskStore);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TaskStore_RemainsNull_WhenNothingIsRegistered()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddMcpServer();
|
||||
|
||||
var options = services.BuildServiceProvider().GetRequiredService<IOptions<McpServerOptions>>().Value;
|
||||
|
||||
Assert.Null(options.TaskStore);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TaskStore_CanBeOverriddenToNull_AfterDIRegistration()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
services.AddMcpServer();
|
||||
services.AddSingleton<IMcpTaskStore, InMemoryMcpTaskStore>();
|
||||
|
||||
services.Configure<McpServerOptions>(options => options.TaskStore = null);
|
||||
|
||||
var options = services.BuildServiceProvider().GetRequiredService<IOptions<McpServerOptions>>().Value;
|
||||
|
||||
Assert.Null(options.TaskStore);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
Loading…
Reference in a new issue