|
9 | 9 | using ModelContextProtocol.Tests.Transport;
|
10 | 10 | using System.Text.RegularExpressions;
|
11 | 11 | using Microsoft.Extensions.AI;
|
| 12 | +using System.Threading.Channels; |
| 13 | +using ModelContextProtocol.Protocol.Messages; |
12 | 14 |
|
13 | 15 | namespace ModelContextProtocol.Tests.Configuration;
|
14 | 16 |
|
@@ -83,6 +85,45 @@ public async Task Can_List_Registered_Tools()
|
83 | 85 | Assert.Equal("Echoes the input back to the client.", doubleEchoTool.Description);
|
84 | 86 | }
|
85 | 87 |
|
| 88 | + [Fact] |
| 89 | + public async Task Can_Be_Notified_Of_Tool_Changes() |
| 90 | + { |
| 91 | + IMcpClient client = await CreateMcpClientForServer(); |
| 92 | + |
| 93 | + var tools = await client.ListToolsAsync(TestContext.Current.CancellationToken); |
| 94 | + Assert.Equal(10, tools.Count); |
| 95 | + |
| 96 | + Channel<JsonRpcNotification> listChanged = Channel.CreateUnbounded<JsonRpcNotification>(); |
| 97 | + client.AddNotificationHandler("notifications/tools/list_changed", notification => |
| 98 | + { |
| 99 | + listChanged.Writer.TryWrite(notification); |
| 100 | + return Task.CompletedTask; |
| 101 | + }); |
| 102 | + |
| 103 | + var notificationRead = listChanged.Reader.ReadAsync(TestContext.Current.CancellationToken); |
| 104 | + Assert.False(notificationRead.IsCompleted); |
| 105 | + |
| 106 | + var serverTools = _server.ServerOptions.Capabilities?.Tools?.ToolCollection; |
| 107 | + Assert.NotNull(serverTools); |
| 108 | + |
| 109 | + var newTool = McpServerTool.Create([McpServerTool(name: "NewTool")] () => "42"); |
| 110 | + serverTools.Add(newTool); |
| 111 | + await notificationRead; |
| 112 | + |
| 113 | + tools = await client.ListToolsAsync(TestContext.Current.CancellationToken); |
| 114 | + Assert.Equal(11, tools.Count); |
| 115 | + Assert.Contains(tools, t => t.Name == "NewTool"); |
| 116 | + |
| 117 | + notificationRead = listChanged.Reader.ReadAsync(TestContext.Current.CancellationToken); |
| 118 | + Assert.False(notificationRead.IsCompleted); |
| 119 | + serverTools.Remove(newTool); |
| 120 | + await notificationRead; |
| 121 | + |
| 122 | + tools = await client.ListToolsAsync(TestContext.Current.CancellationToken); |
| 123 | + Assert.Equal(10, tools.Count); |
| 124 | + Assert.DoesNotContain(tools, t => t.Name == "NewTool"); |
| 125 | + } |
| 126 | + |
86 | 127 | [Fact]
|
87 | 128 | public async Task Can_Call_Registered_Tool()
|
88 | 129 | {
|
|
0 commit comments