Skip to content

Commit a8e28c7

Browse files
author
Esteban Solano
committed
+ code coverage for ClientOptions/Capabilities code
1 parent d6e37ba commit a8e28c7

File tree

1 file changed

+75
-2
lines changed

1 file changed

+75
-2
lines changed

tests/ModelContextProtocol.Tests/Client/McpClientFactoryTests.cs

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using System.Threading.Channels;
2+
using Microsoft.Extensions.Logging;
23
using ModelContextProtocol.Client;
34
using ModelContextProtocol.Configuration;
45
using ModelContextProtocol.Protocol.Messages;
56
using ModelContextProtocol.Protocol.Transport;
67
using ModelContextProtocol.Protocol.Types;
8+
using Moq;
79

810
namespace ModelContextProtocol.Tests.Client;
911

@@ -187,7 +189,68 @@ public async Task McpFactory_WithInvalidTransportOptions_ThrowsFormatException(s
187189
await Assert.ThrowsAsync<ArgumentException>(() => McpClientFactory.CreateAsync(config, _defaultOptions, cancellationToken: TestContext.Current.CancellationToken));
188190
}
189191

190-
private sealed class NopTransport : IClientTransport
192+
[Theory]
193+
[InlineData(typeof(NopTransport))]
194+
[InlineData(typeof(FailureTransport))]
195+
public async Task CreateAsync_WithCapabilities(Type transportType)
196+
{
197+
// Arrange
198+
var serverConfig = new McpServerConfig
199+
{
200+
Id = "TestServer",
201+
Name = "TestServer",
202+
TransportType = "stdio",
203+
Location = "test-location"
204+
};
205+
206+
var clientOptions = new McpClientOptions
207+
{
208+
ClientInfo = new Implementation
209+
{
210+
Name = "TestClient",
211+
Version = "1.0.0.0"
212+
},
213+
Capabilities = new ClientCapabilities
214+
{
215+
Sampling = new SamplingCapability
216+
{
217+
SamplingHandler = (c, t) => Task.FromResult(
218+
new CreateMessageResult {
219+
Content = new Content { Text = "result" },
220+
Model = "test-model",
221+
Role = "test-role",
222+
StopReason = "endTurn"
223+
}),
224+
},
225+
Roots = new RootsCapability
226+
{
227+
ListChanged = true,
228+
RootsHandler = (t, r) => Task.FromResult(new ListRootsResult { Roots = [] }),
229+
}
230+
}
231+
};
232+
233+
var clientTransport = (IClientTransport?)Activator.CreateInstance(transportType);
234+
IMcpClient? client = null;
235+
236+
var actionTask = McpClientFactory.CreateAsync(serverConfig, clientOptions, (config, logger) => clientTransport ?? new NopTransport(), new Mock<ILoggerFactory>().Object, CancellationToken.None);
237+
238+
// Act
239+
if (clientTransport is FailureTransport)
240+
{
241+
var exception = await Assert.ThrowsAsync<InvalidOperationException>(async() => await actionTask);
242+
Assert.Equal(FailureTransport.ExpectedMessage, exception.Message);
243+
}
244+
else
245+
{
246+
client = await actionTask;
247+
248+
// Assert
249+
Assert.NotNull(client);
250+
}
251+
}
252+
253+
private class NopTransport : IClientTransport
191254
{
192255
private readonly Channel<IJsonRpcMessage> _channel = Channel.CreateUnbounded<IJsonRpcMessage>();
193256

@@ -200,7 +263,7 @@ public Task ConnectAsync(CancellationToken cancellationToken = default) =>
200263

201264
public ValueTask DisposeAsync() => default;
202265

203-
public Task SendMessageAsync(IJsonRpcMessage message, CancellationToken cancellationToken = default)
266+
public virtual Task SendMessageAsync(IJsonRpcMessage message, CancellationToken cancellationToken = default)
204267
{
205268
switch (message)
206269
{
@@ -225,4 +288,14 @@ public Task SendMessageAsync(IJsonRpcMessage message, CancellationToken cancella
225288
return Task.CompletedTask;
226289
}
227290
}
291+
292+
private sealed class FailureTransport : NopTransport
293+
{
294+
public const string ExpectedMessage = "Something failed";
295+
296+
public override Task SendMessageAsync(IJsonRpcMessage message, CancellationToken cancellationToken = default)
297+
{
298+
throw new InvalidOperationException(ExpectedMessage);
299+
}
300+
}
228301
}

0 commit comments

Comments
 (0)