Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,10 @@ For more information about MCP:
## Getting Started (Client)

To get started writing a client, the `McpClientFactory.CreateAsync` method is used to instantiate and connect an `IMcpClient`
to a server, with details about the client and server specified in `McpClientOptions` and `McpServerConfig` objects.
Once you have an `IMcpClient`, you can interact with it, such as to enumerate all available tools and invoke tools.
to a server. Once you have an `IMcpClient`, you can interact with it, such as to enumerate all available tools and invoke tools.

```csharp
McpClientOptions options = new()
{
ClientInfo = new() { Name = "TestClient", Version = "1.0.0" }
};

McpServerConfig config = new()
var client = await McpClientFactory.CreateAsync(new()
{
Id = "everything",
Name = "Everything",
Expand All @@ -39,9 +33,7 @@ McpServerConfig config = new()
["command"] = "npx",
["arguments"] = "-y @modelcontextprotocol/server-everything",
}
};

var client = await McpClientFactory.CreateAsync(config, options);
});

// Print the list of tools available from the server.
await foreach (var tool in client.ListToolsAsync())
Expand Down
3 changes: 1 addition & 2 deletions samples/ChatWithTools/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
{
["command"] = "npx", ["arguments"] = "-y @modelcontextprotocol/server-everything",
}
},
new() { ClientInfo = new() { Name = "ChatClient", Version = "1.0.0" } });
});

// Get all available tools
Console.WriteLine("Tools available:");
Expand Down
27 changes: 24 additions & 3 deletions src/ModelContextProtocol/Client/McpClientFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,36 @@
using ModelContextProtocol.Utils;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System.Reflection;

namespace ModelContextProtocol.Client;

/// <summary>Provides factory methods for creating MCP clients.</summary>
public static class McpClientFactory
{
/// <summary>Default client options to use when none are supplied.</summary>
private static readonly McpClientOptions s_defaultClientOptions = CreateDefaultClientOptions();

/// <summary>Creates default client options to use when no options are supplied.</summary>
private static McpClientOptions CreateDefaultClientOptions()
{
var asmName = (Assembly.GetEntryAssembly() ?? Assembly.GetCallingAssembly()).GetName();
return new()
{
ClientInfo = new()
{
Name = asmName.Name ?? "McpClient",
Version = asmName.Version?.ToString() ?? "1.0.0",
},
};
}

/// <summary>Creates an <see cref="IMcpClient"/>, connecting it to the specified server.</summary>
/// <param name="serverConfig">Configuration for the target server to which the client should connect.</param>
/// <param name="clientOptions">A client configuration object which specifies client capabilities and protocol version.</param>
/// <param name="clientOptions">
/// A client configuration object which specifies client capabilities and protocol version.
/// If <see langword="null"/>, details based on the current process will be employed.
/// </param>
/// <param name="createTransportFunc">An optional factory method which returns transport implementations based on a server configuration.</param>
/// <param name="loggerFactory">A logger factory for creating loggers for clients.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Expand All @@ -25,14 +46,14 @@ public static class McpClientFactory
/// <exception cref="InvalidOperationException"><paramref name="createTransportFunc"/> returns an invalid transport.</exception>
public static async Task<IMcpClient> CreateAsync(
McpServerConfig serverConfig,
McpClientOptions clientOptions,
McpClientOptions? clientOptions = null,
Func<McpServerConfig, ILoggerFactory?, IClientTransport>? createTransportFunc = null,
ILoggerFactory? loggerFactory = null,
CancellationToken cancellationToken = default)
{
Throw.IfNull(serverConfig);
Throw.IfNull(clientOptions);

clientOptions ??= s_defaultClientOptions;
createTransportFunc ??= CreateTransport;

string endpointName = $"Client ({serverConfig.Id}: {serverConfig.Name})";
Expand Down
29 changes: 22 additions & 7 deletions tests/ModelContextProtocol.Tests/Client/McpClientFactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,6 @@ public async Task CreateAsync_WithInvalidArgs_Throws()
{
await Assert.ThrowsAsync<ArgumentNullException>("serverConfig", () => McpClientFactory.CreateAsync((McpServerConfig)null!, _defaultOptions, cancellationToken: TestContext.Current.CancellationToken));

await Assert.ThrowsAsync<ArgumentNullException>("clientOptions", () => McpClientFactory.CreateAsync(new McpServerConfig()
{
Name = "name",
Id = "id",
TransportType = TransportTypes.StdIo,
}, (McpClientOptions)null!, cancellationToken: TestContext.Current.CancellationToken));

await Assert.ThrowsAsync<ArgumentException>("serverConfig", () => McpClientFactory.CreateAsync(new McpServerConfig()
{
Name = "name",
Expand All @@ -41,6 +34,28 @@ await Assert.ThrowsAsync<InvalidOperationException>(() => McpClientFactory.Creat
}, _defaultOptions, (_, __) => null!, cancellationToken: TestContext.Current.CancellationToken));
}

[Fact]
public async Task CreateAsync_NullOptions_EntryAssemblyInferred()
{
// Arrange
var serverConfig = new McpServerConfig
{
Id = "test-server",
Name = "Test Server",
TransportType = TransportTypes.StdIo,
Location = "/path/to/server",
};

// Act
await using var client = await McpClientFactory.CreateAsync(
serverConfig,
null,
(_, __) => new NopTransport(),
cancellationToken: TestContext.Current.CancellationToken);

Assert.NotNull(client);
}

[Fact]
public async Task CreateAsync_WithValidStdioConfig_CreatesNewClient()
{
Expand Down