Fix resource subscription handling (#89)
* Fix resource subscription handling Add resource subscription tests * Fix typo * Typo * small fixes * Fix concurrency issue with test * Align with specification schemas
This commit is contained in:
parent
08b0a04dab
commit
34a6f1c665
3 changed files with 210 additions and 36 deletions
|
|
@ -3,6 +3,7 @@ using McpDotNet.Configuration;
|
|||
using McpDotNet.Protocol.Messages;
|
||||
using McpDotNet.Protocol.Transport;
|
||||
using McpDotNet.Protocol.Types;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace McpDotNet.Tests;
|
||||
|
||||
|
|
@ -208,6 +209,67 @@ public class ClientIntegrationTests : IClassFixture<ClientIntegrationTestFixture
|
|||
Assert.NotNull(result.Contents[0].Blob);
|
||||
}
|
||||
|
||||
// Not supported by "everything" server version on npx
|
||||
[Fact]
|
||||
public async Task SubscribeResource_Stdio()
|
||||
{
|
||||
// arrange
|
||||
var clientId = "test_server";
|
||||
|
||||
// act
|
||||
int counter = 0;
|
||||
await using var client = await _fixture.CreateClientAsync(clientId);
|
||||
client.AddNotificationHandler(NotificationMethods.ResourceUpdatedNotification, (notification) =>
|
||||
{
|
||||
var notificationParams = JsonSerializer.Deserialize<ResourceUpdatedNotificationParams>(notification.Params!.ToString() ?? string.Empty);
|
||||
++counter;
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
await client.SubscribeToResourceAsync("test://static/resource/1", CancellationToken.None);
|
||||
|
||||
// notifications happen every 5 seconds, so we wait for 10 seconds to ensure we get at least one notification
|
||||
await Task.Delay(10000);
|
||||
|
||||
// assert
|
||||
Assert.True(counter > 0);
|
||||
}
|
||||
|
||||
// Not supported by "everything" server version on npx
|
||||
[Fact]
|
||||
public async Task UnsubscribeResource_Stdio()
|
||||
{
|
||||
// arrange
|
||||
var clientId = "test_server";
|
||||
|
||||
// act
|
||||
int counter = 0;
|
||||
await using var client = await _fixture.CreateClientAsync(clientId);
|
||||
client.AddNotificationHandler(NotificationMethods.ResourceUpdatedNotification, (notification) =>
|
||||
{
|
||||
var notificationParams = JsonSerializer.Deserialize<ResourceUpdatedNotificationParams>(notification.Params!.ToString() ?? string.Empty);
|
||||
++counter;
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
await client.SubscribeToResourceAsync("test://static/resource/1", CancellationToken.None);
|
||||
|
||||
// notifications happen every 5 seconds, so we wait for 10 seconds to ensure we get at least one notification
|
||||
await Task.Delay(10000);
|
||||
|
||||
// reset counter
|
||||
int counterAfterSubscribe = counter;
|
||||
|
||||
// unsubscribe
|
||||
await client.UnsubscribeFromResourceAsync("test://static/resource/1", CancellationToken.None);
|
||||
counter = 0;
|
||||
|
||||
// notifications happen every 5 seconds, so we wait for 10 seconds to ensure we would've gotten at least one notification
|
||||
await Task.Delay(10000);
|
||||
|
||||
// assert
|
||||
Assert.True(counterAfterSubscribe > 0);
|
||||
Assert.Equal(0, counter);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GetClients))]
|
||||
public async Task GetCompletion_Stdio_ResourceReference(string clientId)
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ public class McpServerBuilderExtensionsHandlerTests
|
|||
[Fact]
|
||||
public void WithSubscribeToResourcesHandler_Sets_Handler()
|
||||
{
|
||||
Func<RequestContext<string>, CancellationToken, Task> handler = (context, token) => Task.CompletedTask;
|
||||
Func<RequestContext<SubscribeRequestParams>, CancellationToken, Task<EmptyResult>> handler = (context, token) => Task.FromResult(new EmptyResult());
|
||||
|
||||
_builder.Object.WithSubscribeToResourcesHandler(handler);
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ public class McpServerBuilderExtensionsHandlerTests
|
|||
[Fact]
|
||||
public void WithUnsubscribeFromResourcesHandler_Sets_Handler()
|
||||
{
|
||||
Func<RequestContext<string>, CancellationToken, Task> handler = (context, token) => Task.CompletedTask;
|
||||
Func<RequestContext<UnsubscribeRequestParams>, CancellationToken, Task<EmptyResult>> handler = (context, token) => Task.FromResult(new EmptyResult());
|
||||
|
||||
_builder.Object.WithUnsubscribeFromResourcesHandler(handler);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ public class McpServerHandlerTests
|
|||
handlers.ListResourcesHandler = (p, c) => Task.FromResult(new ListResourcesResult());
|
||||
handlers.ReadResourceHandler = (p, c) => Task.FromResult(new ReadResourceResult());
|
||||
handlers.GetCompletionHandler = (p, c) => Task.FromResult(new CompleteResult());
|
||||
handlers.SubscribeToResourcesHandler = (s, c) => Task.CompletedTask;
|
||||
handlers.UnsubscribeFromResourcesHandler = (s, c) => Task.CompletedTask;
|
||||
handlers.SubscribeToResourcesHandler = (s, c) => Task.FromResult(new EmptyResult());
|
||||
handlers.UnsubscribeFromResourcesHandler = (s, c) => Task.FromResult(new EmptyResult());
|
||||
|
||||
Assert.NotNull(handlers.ListToolsHandler);
|
||||
Assert.NotNull(handlers.CallToolHandler);
|
||||
|
|
|
|||
Loading…
Reference in a new issue