diff --git a/README.MD b/README.MD index 0ebc2f1f1..985524175 100644 --- a/README.MD +++ b/README.MD @@ -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", @@ -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()) diff --git a/samples/ChatWithTools/Program.cs b/samples/ChatWithTools/Program.cs index feeb06a04..2dcf06fae 100644 --- a/samples/ChatWithTools/Program.cs +++ b/samples/ChatWithTools/Program.cs @@ -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:"); diff --git a/src/ModelContextProtocol/Client/McpClientFactory.cs b/src/ModelContextProtocol/Client/McpClientFactory.cs index 0fdbc3f0c..691d165af 100644 --- a/src/ModelContextProtocol/Client/McpClientFactory.cs +++ b/src/ModelContextProtocol/Client/McpClientFactory.cs @@ -6,15 +6,36 @@ using ModelContextProtocol.Utils; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; +using System.Reflection; namespace ModelContextProtocol.Client; /// Provides factory methods for creating MCP clients. public static class McpClientFactory { + /// Default client options to use when none are supplied. + private static readonly McpClientOptions s_defaultClientOptions = CreateDefaultClientOptions(); + + /// Creates default client options to use when no options are supplied. + private static McpClientOptions CreateDefaultClientOptions() + { + var asmName = (Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()).GetName(); + return new() + { + ClientInfo = new() + { + Name = asmName.Name ?? "McpClient", + Version = asmName.Version?.ToString() ?? "1.0.0", + }, + }; + } + /// Creates an , connecting it to the specified server. /// Configuration for the target server to which the client should connect. - /// A client configuration object which specifies client capabilities and protocol version. + /// + /// A client configuration object which specifies client capabilities and protocol version. + /// If , details based on the current process will be employed. + /// /// An optional factory method which returns transport implementations based on a server configuration. /// A logger factory for creating loggers for clients. /// A token to cancel the operation. @@ -25,14 +46,14 @@ public static class McpClientFactory /// returns an invalid transport. public static async Task CreateAsync( McpServerConfig serverConfig, - McpClientOptions clientOptions, + McpClientOptions? clientOptions = null, Func? 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})"; diff --git a/tests/ModelContextProtocol.Tests/Client/McpClientFactoryTests.cs b/tests/ModelContextProtocol.Tests/Client/McpClientFactoryTests.cs index ce4c038a9..0053e8da2 100644 --- a/tests/ModelContextProtocol.Tests/Client/McpClientFactoryTests.cs +++ b/tests/ModelContextProtocol.Tests/Client/McpClientFactoryTests.cs @@ -19,13 +19,6 @@ public async Task CreateAsync_WithInvalidArgs_Throws() { await Assert.ThrowsAsync("serverConfig", () => McpClientFactory.CreateAsync((McpServerConfig)null!, _defaultOptions, cancellationToken: TestContext.Current.CancellationToken)); - await Assert.ThrowsAsync("clientOptions", () => McpClientFactory.CreateAsync(new McpServerConfig() - { - Name = "name", - Id = "id", - TransportType = TransportTypes.StdIo, - }, (McpClientOptions)null!, cancellationToken: TestContext.Current.CancellationToken)); - await Assert.ThrowsAsync("serverConfig", () => McpClientFactory.CreateAsync(new McpServerConfig() { Name = "name", @@ -41,6 +34,28 @@ await Assert.ThrowsAsync(() => 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() {