Allow override of name and description of McpClientTool (#165)
This commit is contained in:
parent
9302466041
commit
4ecb6bc240
2 changed files with 61 additions and 3 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
using ModelContextProtocol.Protocol.Types;
|
using ModelContextProtocol.Protocol.Types;
|
||||||
using ModelContextProtocol.Utils.Json;
|
using ModelContextProtocol.Utils.Json;
|
||||||
|
using ModelContextProtocol.Utils;
|
||||||
using Microsoft.Extensions.AI;
|
using Microsoft.Extensions.AI;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
|
|
@ -9,22 +10,51 @@ namespace ModelContextProtocol.Client;
|
||||||
public sealed class McpClientTool : AIFunction
|
public sealed class McpClientTool : AIFunction
|
||||||
{
|
{
|
||||||
private readonly IMcpClient _client;
|
private readonly IMcpClient _client;
|
||||||
|
private readonly string _name;
|
||||||
|
private readonly string _description;
|
||||||
|
|
||||||
internal McpClientTool(IMcpClient client, Tool tool, JsonSerializerOptions serializerOptions)
|
internal McpClientTool(IMcpClient client, Tool tool, JsonSerializerOptions serializerOptions, string? name = null, string? description = null)
|
||||||
{
|
{
|
||||||
_client = client;
|
_client = client;
|
||||||
ProtocolTool = tool;
|
ProtocolTool = tool;
|
||||||
JsonSerializerOptions = serializerOptions;
|
JsonSerializerOptions = serializerOptions;
|
||||||
|
_name = name ?? tool.Name;
|
||||||
|
_description = description ?? tool.Description ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The model-facing name to give the tool.</param>
|
||||||
|
/// <returns>Copy of this McpClientTool with the provided name</returns>
|
||||||
|
public McpClientTool WithName(string name)
|
||||||
|
{
|
||||||
|
return new McpClientTool(_client, ProtocolTool, JsonSerializerOptions, name, _description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="description">The description to give the tool.</param>
|
||||||
|
/// <returns>Copy of this McpClientTool with the provided description</returns>
|
||||||
|
public McpClientTool WithDescription(string description)
|
||||||
|
{
|
||||||
|
return new McpClientTool(_client, ProtocolTool, JsonSerializerOptions, _name, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Gets the protocol <see cref="Tool"/> type for this instance.</summary>
|
/// <summary>Gets the protocol <see cref="Tool"/> type for this instance.</summary>
|
||||||
public Tool ProtocolTool { get; }
|
public Tool ProtocolTool { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string Name => ProtocolTool.Name;
|
public override string Name => _name;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string Description => ProtocolTool.Description ?? string.Empty;
|
public override string Description => _description;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override JsonElement JsonSchema => ProtocolTool.InputSchema;
|
public override JsonElement JsonSchema => ProtocolTool.InputSchema;
|
||||||
|
|
|
||||||
|
|
@ -171,4 +171,32 @@ public class McpClientExtensionsTests : LoggedTest
|
||||||
|
|
||||||
await Assert.ThrowsAsync<NotSupportedException>(() => client.GetPromptAsync("Prompt", new Dictionary<string, object?> { ["i"] = 42 }, emptyOptions, cancellationToken: TestContext.Current.CancellationToken));
|
await Assert.ThrowsAsync<NotSupportedException>(() => client.GetPromptAsync("Prompt", new Dictionary<string, object?> { ["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)).First();
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue