|  | 
| 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