From 514c28e2e66cb57487c19646105907d609f0dbc6 Mon Sep 17 00:00:00 2001 From: PederHP Date: Mon, 31 Mar 2025 20:59:24 +0200 Subject: [PATCH 01/12] Allow override of name and description of McpClientTool --- .../Client/McpClientTool.cs | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/ModelContextProtocol/Client/McpClientTool.cs b/src/ModelContextProtocol/Client/McpClientTool.cs index 10ccd81a6..d67785c00 100644 --- a/src/ModelContextProtocol/Client/McpClientTool.cs +++ b/src/ModelContextProtocol/Client/McpClientTool.cs @@ -9,21 +9,50 @@ namespace ModelContextProtocol.Client; public sealed class McpClientTool : AIFunction { private readonly IMcpClient _client; + private readonly string? _nameOverride; + private readonly string? _descriptionOverride; - internal McpClientTool(IMcpClient client, Tool tool) + internal McpClientTool(IMcpClient client, Tool tool, string? nameOverride = null, string? descriptionOverride = null) { _client = client; ProtocolTool = tool; + _nameOverride = nameOverride; + _descriptionOverride = descriptionOverride; + } + + /// + /// Creates a new instance of the tool with the specified name. + /// This is useful for optimizing the tool name for specific models or for prefixing the tool name with a (usually server-derived) namespace to avoid conflicts. + /// The server will still be called with the original tool name, so no mapping is required. + /// + /// The model-facing name to give the tool + /// Equivalent McpClientTool, but with the provided name + public McpClientTool WithName(string name) + { + return new McpClientTool(_client, ProtocolTool, name, _descriptionOverride); + } + + /// + /// Creates a new instance of the tool with the specified description. + /// This is can be used to provide modified or additional (e.g. examples) context to the model about the tool. + /// This will in general require a hard-coded mapping in the client. + /// It is not recommended to use this without running evaluations to ensure the model actually benefits from the custom description. + /// + /// + /// + public McpClientTool WithDescription(string description) + { + return new McpClientTool(_client, ProtocolTool, _nameOverride, description); } /// Gets the protocol type for this instance. public Tool ProtocolTool { get; } /// - public override string Name => ProtocolTool.Name; + public override string Name => _nameOverride ?? ProtocolTool.Name; /// - public override string Description => ProtocolTool.Description ?? string.Empty; + public override string Description => _descriptionOverride ?? ProtocolTool.Description ?? string.Empty; /// public override JsonElement JsonSchema => ProtocolTool.InputSchema; @@ -41,5 +70,5 @@ internal McpClientTool(IMcpClient client, Tool tool) CallToolResponse result = await _client.CallToolAsync(ProtocolTool.Name, argDict, cancellationToken).ConfigureAwait(false); return JsonSerializer.SerializeToElement(result, McpJsonUtilities.JsonContext.Default.CallToolResponse); - } + } } \ No newline at end of file From 729edc1b9340cc05d9580221e3aa9bd793f9e56f Mon Sep 17 00:00:00 2001 From: PederHP Date: Mon, 31 Mar 2025 20:59:24 +0200 Subject: [PATCH 02/12] Allow override of name and description of McpClientTool --- .../Client/McpClientTool.cs | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/src/ModelContextProtocol/Client/McpClientTool.cs b/src/ModelContextProtocol/Client/McpClientTool.cs index 10ccd81a6..2c2098301 100644 --- a/src/ModelContextProtocol/Client/McpClientTool.cs +++ b/src/ModelContextProtocol/Client/McpClientTool.cs @@ -9,21 +9,50 @@ namespace ModelContextProtocol.Client; public sealed class McpClientTool : AIFunction { private readonly IMcpClient _client; + private readonly string? _nameOverride; + private readonly string? _descriptionOverride; - internal McpClientTool(IMcpClient client, Tool tool) + internal McpClientTool(IMcpClient client, Tool tool, string? nameOverride = null, string? descriptionOverride = null) { _client = client; ProtocolTool = tool; + _nameOverride = nameOverride; + _descriptionOverride = descriptionOverride; + } + + /// + /// Creates a new instance of the tool with the specified name. + /// This is useful for optimizing the tool name for specific models or for prefixing the tool name with a (usually server-derived) namespace to avoid conflicts. + /// The server will still be called with the original tool name, so no mapping is required. + /// + /// The model-facing name to give the tool + /// Equivalent McpClientTool, but with the provided name + public McpClientTool WithName(string name) + { + return new McpClientTool(_client, ProtocolTool, name, _descriptionOverride); + } + + /// + /// Creates a new instance of the tool with the specified description. + /// This can be used to provide modified or additional (e.g. examples) context to the model about the tool. + /// This will in general require a hard-coded mapping in the client. + /// It is not recommended to use this without running evaluations to ensure the model actually benefits from the custom description. + /// + /// + /// + public McpClientTool WithDescription(string description) + { + return new McpClientTool(_client, ProtocolTool, _nameOverride, description); } /// Gets the protocol type for this instance. public Tool ProtocolTool { get; } /// - public override string Name => ProtocolTool.Name; + public override string Name => _nameOverride ?? ProtocolTool.Name; /// - public override string Description => ProtocolTool.Description ?? string.Empty; + public override string Description => _descriptionOverride ?? ProtocolTool.Description ?? string.Empty; /// public override JsonElement JsonSchema => ProtocolTool.InputSchema; From 1dcbc0b5c066071f9d4c710903c84467852669f8 Mon Sep 17 00:00:00 2001 From: PederHP Date: Tue, 1 Apr 2025 15:02:24 +0200 Subject: [PATCH 03/12] Tweaks --- .../Client/McpClientTool.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/ModelContextProtocol/Client/McpClientTool.cs b/src/ModelContextProtocol/Client/McpClientTool.cs index 2c2098301..d4c588728 100644 --- a/src/ModelContextProtocol/Client/McpClientTool.cs +++ b/src/ModelContextProtocol/Client/McpClientTool.cs @@ -9,15 +9,15 @@ namespace ModelContextProtocol.Client; public sealed class McpClientTool : AIFunction { private readonly IMcpClient _client; - private readonly string? _nameOverride; - private readonly string? _descriptionOverride; + private readonly string? _name; + private readonly string? _description; - internal McpClientTool(IMcpClient client, Tool tool, string? nameOverride = null, string? descriptionOverride = null) + internal McpClientTool(IMcpClient client, Tool tool, string? name = null, string? description = null) { _client = client; ProtocolTool = tool; - _nameOverride = nameOverride; - _descriptionOverride = descriptionOverride; + _name = name ?? tool.Name; + _description = description ?? tool.Description; } /// @@ -25,11 +25,11 @@ internal McpClientTool(IMcpClient client, Tool tool, string? nameOverride = null /// This is useful for optimizing the tool name for specific models or for prefixing the tool name with a (usually server-derived) namespace to avoid conflicts. /// The server will still be called with the original tool name, so no mapping is required. /// - /// The model-facing name to give the tool - /// Equivalent McpClientTool, but with the provided name - public McpClientTool WithName(string name) + /// The model-facing name to give the tool. Pass null to clear the name override and to use the MCP Tool name again. + /// Copy of this McpClientTool with the provided name + public McpClientTool WithName(string? name) { - return new McpClientTool(_client, ProtocolTool, name, _descriptionOverride); + return new McpClientTool(_client, ProtocolTool, name, _description); } /// @@ -38,21 +38,21 @@ public McpClientTool WithName(string name) /// This will in general require a hard-coded mapping in the client. /// It is not recommended to use this without running evaluations to ensure the model actually benefits from the custom description. /// - /// - /// - public McpClientTool WithDescription(string description) + /// The description to give the tool. Pass null to clear the description override and to use the MCP Tool description again. + /// Copy of this McpClientTool with the provided description + public McpClientTool WithDescription(string? description) { - return new McpClientTool(_client, ProtocolTool, _nameOverride, description); + return new McpClientTool(_client, ProtocolTool, _name, description); } /// Gets the protocol type for this instance. public Tool ProtocolTool { get; } /// - public override string Name => _nameOverride ?? ProtocolTool.Name; + public override string Name => _name ?? ProtocolTool.Name; /// - public override string Description => _descriptionOverride ?? ProtocolTool.Description ?? string.Empty; + public override string Description => _description ?? ProtocolTool.Description ?? string.Empty; /// public override JsonElement JsonSchema => ProtocolTool.InputSchema; From 74c4b011138a3558ed7ee5792482805ab994cc7c Mon Sep 17 00:00:00 2001 From: PederHP Date: Tue, 1 Apr 2025 15:19:11 +0200 Subject: [PATCH 04/12] tweak --- src/ModelContextProtocol/Client/McpClientTool.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ModelContextProtocol/Client/McpClientTool.cs b/src/ModelContextProtocol/Client/McpClientTool.cs index d4c588728..53326c9fa 100644 --- a/src/ModelContextProtocol/Client/McpClientTool.cs +++ b/src/ModelContextProtocol/Client/McpClientTool.cs @@ -49,10 +49,10 @@ public McpClientTool WithDescription(string? description) public Tool ProtocolTool { get; } /// - public override string Name => _name ?? ProtocolTool.Name; + public override string Name => _name!; /// - public override string Description => _description ?? ProtocolTool.Description ?? string.Empty; + public override string Description => _description ?? string.Empty; /// public override JsonElement JsonSchema => ProtocolTool.InputSchema; From 229e6516ab47b1d5899936372bea01da9bbb7aa8 Mon Sep 17 00:00:00 2001 From: PederHP Date: Wed, 2 Apr 2025 07:43:14 +0200 Subject: [PATCH 05/12] remove null as reset --- src/ModelContextProtocol/Client/McpClientTool.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ModelContextProtocol/Client/McpClientTool.cs b/src/ModelContextProtocol/Client/McpClientTool.cs index 53326c9fa..65fe6ade7 100644 --- a/src/ModelContextProtocol/Client/McpClientTool.cs +++ b/src/ModelContextProtocol/Client/McpClientTool.cs @@ -25,9 +25,9 @@ internal McpClientTool(IMcpClient client, Tool tool, string? name = null, string /// This is useful for optimizing the tool name for specific models or for prefixing the tool name with a (usually server-derived) namespace to avoid conflicts. /// The server will still be called with the original tool name, so no mapping is required. /// - /// The model-facing name to give the tool. Pass null to clear the name override and to use the MCP Tool name again. + /// The model-facing name to give the tool. /// Copy of this McpClientTool with the provided name - public McpClientTool WithName(string? name) + public McpClientTool WithName(string name) { return new McpClientTool(_client, ProtocolTool, name, _description); } @@ -38,9 +38,9 @@ public McpClientTool WithName(string? name) /// This will in general require a hard-coded mapping in the client. /// It is not recommended to use this without running evaluations to ensure the model actually benefits from the custom description. /// - /// The description to give the tool. Pass null to clear the description override and to use the MCP Tool description again. + /// The description to give the tool. /// Copy of this McpClientTool with the provided description - public McpClientTool WithDescription(string? description) + public McpClientTool WithDescription(string description) { return new McpClientTool(_client, ProtocolTool, _name, description); } From 77e44349313dcff7ae5563de1e2a598b918da915 Mon Sep 17 00:00:00 2001 From: Peder Holdgaard Pedersen <127606677+PederHP@users.noreply.github.com> Date: Wed, 2 Apr 2025 17:12:12 +0200 Subject: [PATCH 06/12] Update src/ModelContextProtocol/Client/McpClientTool.cs Co-authored-by: Eirik Tsarpalis --- src/ModelContextProtocol/Client/McpClientTool.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ModelContextProtocol/Client/McpClientTool.cs b/src/ModelContextProtocol/Client/McpClientTool.cs index 65fe6ade7..07ddeca03 100644 --- a/src/ModelContextProtocol/Client/McpClientTool.cs +++ b/src/ModelContextProtocol/Client/McpClientTool.cs @@ -29,6 +29,7 @@ internal McpClientTool(IMcpClient client, Tool tool, string? name = null, string /// Copy of this McpClientTool with the provided name public McpClientTool WithName(string name) { + Throw.IfNull(name); return new McpClientTool(_client, ProtocolTool, name, _description); } From f1fd4bb12157fb74662a2ede2676eb4ce2b1a79e Mon Sep 17 00:00:00 2001 From: Peder Holdgaard Pedersen <127606677+PederHP@users.noreply.github.com> Date: Wed, 2 Apr 2025 17:12:42 +0200 Subject: [PATCH 07/12] Update src/ModelContextProtocol/Client/McpClientTool.cs Co-authored-by: Eirik Tsarpalis --- src/ModelContextProtocol/Client/McpClientTool.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ModelContextProtocol/Client/McpClientTool.cs b/src/ModelContextProtocol/Client/McpClientTool.cs index 07ddeca03..f06eac3ac 100644 --- a/src/ModelContextProtocol/Client/McpClientTool.cs +++ b/src/ModelContextProtocol/Client/McpClientTool.cs @@ -9,8 +9,8 @@ namespace ModelContextProtocol.Client; public sealed class McpClientTool : AIFunction { private readonly IMcpClient _client; - private readonly string? _name; - private readonly string? _description; + private readonly string _name; + private readonly string _description; internal McpClientTool(IMcpClient client, Tool tool, string? name = null, string? description = null) { From 155cc6f7c792cd5abfb28df49d06a46245c107ee Mon Sep 17 00:00:00 2001 From: PederHP Date: Wed, 2 Apr 2025 20:26:15 +0200 Subject: [PATCH 08/12] Tweaks --- src/ModelContextProtocol/Client/McpClientTool.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ModelContextProtocol/Client/McpClientTool.cs b/src/ModelContextProtocol/Client/McpClientTool.cs index f06eac3ac..00cd80d8f 100644 --- a/src/ModelContextProtocol/Client/McpClientTool.cs +++ b/src/ModelContextProtocol/Client/McpClientTool.cs @@ -1,5 +1,6 @@ using ModelContextProtocol.Protocol.Types; using ModelContextProtocol.Utils.Json; +using ModelContextProtocol.Utils; using Microsoft.Extensions.AI; using System.Text.Json; @@ -17,7 +18,7 @@ internal McpClientTool(IMcpClient client, Tool tool, string? name = null, string _client = client; ProtocolTool = tool; _name = name ?? tool.Name; - _description = description ?? tool.Description; + _description = description ?? tool.Description ?? string.Empty; } /// @@ -50,10 +51,10 @@ public McpClientTool WithDescription(string description) public Tool ProtocolTool { get; } /// - public override string Name => _name!; + public override string Name => _name; /// - public override string Description => _description ?? string.Empty; + public override string Description => _description; /// public override JsonElement JsonSchema => ProtocolTool.InputSchema; From aa0e673d25cf60ef2392a87e5cafaaa89d4c8a53 Mon Sep 17 00:00:00 2001 From: PederHP Date: Wed, 2 Apr 2025 20:43:40 +0200 Subject: [PATCH 09/12] Fix --- src/ModelContextProtocol/Client/McpClientTool.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ModelContextProtocol/Client/McpClientTool.cs b/src/ModelContextProtocol/Client/McpClientTool.cs index 7ff234ba2..4deb2690d 100644 --- a/src/ModelContextProtocol/Client/McpClientTool.cs +++ b/src/ModelContextProtocol/Client/McpClientTool.cs @@ -32,7 +32,7 @@ internal McpClientTool(IMcpClient client, Tool tool, JsonSerializerOptions seria public McpClientTool WithName(string name) { Throw.IfNull(name); - return new McpClientTool(_client, ProtocolTool, name, _description); + return new McpClientTool(_client, ProtocolTool, JsonSerializerOptions, name, _description); } /// @@ -45,7 +45,7 @@ public McpClientTool WithName(string name) /// Copy of this McpClientTool with the provided description public McpClientTool WithDescription(string description) { - return new McpClientTool(_client, ProtocolTool, _name, description); + return new McpClientTool(_client, ProtocolTool, JsonSerializerOptions, _name, description); } /// Gets the protocol type for this instance. From 3df8fa41b40b5a966e99d3313c9831eef8711f66 Mon Sep 17 00:00:00 2001 From: PederHP Date: Wed, 2 Apr 2025 20:49:47 +0200 Subject: [PATCH 10/12] Cannot be null --- src/ModelContextProtocol/Client/McpClientTool.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ModelContextProtocol/Client/McpClientTool.cs b/src/ModelContextProtocol/Client/McpClientTool.cs index 4deb2690d..58cb02d53 100644 --- a/src/ModelContextProtocol/Client/McpClientTool.cs +++ b/src/ModelContextProtocol/Client/McpClientTool.cs @@ -13,7 +13,7 @@ public sealed class McpClientTool : AIFunction private readonly string _name; private readonly string _description; - internal McpClientTool(IMcpClient client, Tool tool, JsonSerializerOptions serializerOptions,string? name = null, string? description = null) + internal McpClientTool(IMcpClient client, Tool tool, JsonSerializerOptions serializerOptions, string? name = null, string? description = null) { _client = client; ProtocolTool = tool; @@ -31,7 +31,6 @@ internal McpClientTool(IMcpClient client, Tool tool, JsonSerializerOptions seria /// Copy of this McpClientTool with the provided name public McpClientTool WithName(string name) { - Throw.IfNull(name); return new McpClientTool(_client, ProtocolTool, JsonSerializerOptions, name, _description); } From 9458c031d3ca0aa034f0ad81e24b7e1ce02de3a0 Mon Sep 17 00:00:00 2001 From: PederHP Date: Wed, 2 Apr 2025 20:58:06 +0200 Subject: [PATCH 11/12] Tests --- .../Client/McpClientExtensionsTests.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/ModelContextProtocol.Tests/Client/McpClientExtensionsTests.cs b/tests/ModelContextProtocol.Tests/Client/McpClientExtensionsTests.cs index 7c3e92f97..d5f70ebd2 100644 --- a/tests/ModelContextProtocol.Tests/Client/McpClientExtensionsTests.cs +++ b/tests/ModelContextProtocol.Tests/Client/McpClientExtensionsTests.cs @@ -171,4 +171,32 @@ public async Task GetPromptsAsync_HonorsJsonSerializerOptions() await Assert.ThrowsAsync(() => client.GetPromptAsync("Prompt", new Dictionary { ["i"] = 42 }, emptyOptions, cancellationToken: TestContext.Current.CancellationToken)); } + + [Fact] + public async Task WithName_ChangesToolName() + { + JsonSerializerOptions options = new(JsonSerializerOptions.Default); + IMcpClient client = await CreateMcpClientForServer(); + + var tool = (await client.ListToolsAsync(options, TestContext.Current.CancellationToken)).FirstOrDefault(); + var originalName = tool?.Name; + var renamedTool = tool?.WithName("RenamedTool"); + + Assert.NotNull(renamedTool); + Assert.Equal("RenamedTool", renamedTool.Name); + Assert.Equal(originalName, tool?.Name); + } + + [Fact] + public async Task WithDescription_ChangesToolDescription() + { + JsonSerializerOptions options = new(JsonSerializerOptions.Default); + IMcpClient client = await CreateMcpClientForServer(); + var tool = (await client.ListToolsAsync(options, TestContext.Current.CancellationToken)).FirstOrDefault(); + var originalDescription = tool?.Description; + var redescribedTool = tool?.WithDescription("ToolWithNewDescription"); + Assert.NotNull(redescribedTool); + Assert.Equal("ToolWithNewDescription", redescribedTool.Description); + Assert.Equal(originalDescription, tool?.Description); + } } \ No newline at end of file From fc22fc7b288ecac70b55101a428a85fff1786332 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Wed, 2 Apr 2025 14:00:25 -0700 Subject: [PATCH 12/12] Update tests/ModelContextProtocol.Tests/Client/McpClientExtensionsTests.cs Co-authored-by: Eirik Tsarpalis --- .../Client/McpClientExtensionsTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ModelContextProtocol.Tests/Client/McpClientExtensionsTests.cs b/tests/ModelContextProtocol.Tests/Client/McpClientExtensionsTests.cs index d5f70ebd2..02bd50d16 100644 --- a/tests/ModelContextProtocol.Tests/Client/McpClientExtensionsTests.cs +++ b/tests/ModelContextProtocol.Tests/Client/McpClientExtensionsTests.cs @@ -178,9 +178,9 @@ public async Task WithName_ChangesToolName() JsonSerializerOptions options = new(JsonSerializerOptions.Default); IMcpClient client = await CreateMcpClientForServer(); - var tool = (await client.ListToolsAsync(options, TestContext.Current.CancellationToken)).FirstOrDefault(); - var originalName = tool?.Name; - var renamedTool = tool?.WithName("RenamedTool"); + var tool = (await client.ListToolsAsync(options, TestContext.Current.CancellationToken)).First(); + var originalName = tool.Name; + var renamedTool = tool.WithName("RenamedTool"); Assert.NotNull(renamedTool); Assert.Equal("RenamedTool", renamedTool.Name);