Add public constructors to McpClient types for reusing cached definitions (#938)

* Initial plan

* Add public constructor to McpClientTool for reusing tool definitions

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>

* Fix McpClientTool constructor per review feedback

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>

* Add public constructors for McpClientPrompt, McpClientResource, and McpClientResourceTemplate

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
This commit is contained in:
Copilot 2025-11-06 13:59:17 -05:00 • committed by GitHub
commit b90f17bccb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 785 additions and 3 deletions

View file

@ -22,8 +22,30 @@ public sealed class McpClientPrompt
{
private readonly McpClient _client;
internal McpClientPrompt(McpClient client, Prompt prompt)
/// <summary>
/// Initializes a new instance of the <see cref="McpClientPrompt"/> class.
/// </summary>
/// <param name="client">The <see cref="McpClient"/> instance to use for invoking the prompt.</param>
/// <param name="prompt">The protocol <see cref="Prompt"/> definition describing the prompt's metadata.</param>
/// <remarks>
/// <para>
/// This constructor enables reusing cached prompt definitions across different <see cref="McpClient"/> instances
/// without needing to call <see cref="McpClient.ListPromptsAsync"/> on every reconnect. This is particularly useful
/// in scenarios where prompt definitions are stable and network round-trips should be minimized.
/// </para>
/// <para>
/// The provided <paramref name="prompt"/> must represent a prompt that is actually available on the server
/// associated with the <paramref name="client"/>. Attempting to invoke a prompt that doesn't exist on the
/// server will result in an <see cref="McpException"/>.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="prompt"/> is <see langword="null"/>.</exception>
public McpClientPrompt(McpClient client, Prompt prompt)
{
Throw.IfNull(client);
Throw.IfNull(prompt);
_client = client;
ProtocolPrompt = prompt;
}

View file

@ -17,8 +17,30 @@ public sealed class McpClientResource
{
private readonly McpClient _client;
internal McpClientResource(McpClient client, Resource resource)
/// <summary>
/// Initializes a new instance of the <see cref="McpClientResource"/> class.
/// </summary>
/// <param name="client">The <see cref="McpClient"/> instance to use for reading the resource.</param>
/// <param name="resource">The protocol <see cref="Resource"/> definition describing the resource's metadata.</param>
/// <remarks>
/// <para>
/// This constructor enables reusing cached resource definitions across different <see cref="McpClient"/> instances
/// without needing to call <see cref="McpClient.ListResourcesAsync"/> on every reconnect. This is particularly useful
/// in scenarios where resource definitions are stable and network round-trips should be minimized.
/// </para>
/// <para>
/// The provided <paramref name="resource"/> must represent a resource that is actually available on the server
/// associated with the <paramref name="client"/>. Attempting to read a resource that doesn't exist on the
/// server will result in an <see cref="McpException"/>.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="resource"/> is <see langword="null"/>.</exception>
public McpClientResource(McpClient client, Resource resource)
{
Throw.IfNull(client);
Throw.IfNull(resource);
_client = client;
ProtocolResource = resource;
}

View file

@ -17,8 +17,30 @@ public sealed class McpClientResourceTemplate
{
private readonly McpClient _client;
internal McpClientResourceTemplate(McpClient client, ResourceTemplate resourceTemplate)
/// <summary>
/// Initializes a new instance of the <see cref="McpClientResourceTemplate"/> class.
/// </summary>
/// <param name="client">The <see cref="McpClient"/> instance to use for reading the resource template.</param>
/// <param name="resourceTemplate">The protocol <see cref="ResourceTemplate"/> definition describing the resource template's metadata.</param>
/// <remarks>
/// <para>
/// This constructor enables reusing cached resource template definitions across different <see cref="McpClient"/> instances
/// without needing to call <see cref="McpClient.ListResourceTemplatesAsync"/> on every reconnect. This is particularly useful
/// in scenarios where resource template definitions are stable and network round-trips should be minimized.
/// </para>
/// <para>
/// The provided <paramref name="resourceTemplate"/> must represent a resource template that is actually available on the server
/// associated with the <paramref name="client"/>. Attempting to read a resource template that doesn't exist on the
/// server will result in an <see cref="McpException"/>.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="resourceTemplate"/> is <see langword="null"/>.</exception>
public McpClientResourceTemplate(McpClient client, ResourceTemplate resourceTemplate)
{
Throw.IfNull(client);
Throw.IfNull(resourceTemplate);
_client = client;
ProtocolResourceTemplate = resourceTemplate;
}

View file

@ -37,6 +37,45 @@ public sealed class McpClientTool : AIFunction
private readonly string _description;
private readonly IProgress<ProgressNotificationValue>? _progress;
/// <summary>
/// Initializes a new instance of the <see cref="McpClientTool"/> class.
/// </summary>
/// <param name="client">The <see cref="McpClient"/> instance to use for invoking the tool.</param>
/// <param name="tool">The protocol <see cref="Tool"/> definition describing the tool's metadata and schema.</param>
/// <param name="serializerOptions">
/// The JSON serialization options governing argument serialization. If <see langword="null"/>,
/// <see cref="McpJsonUtilities.DefaultOptions"/> will be used.
/// </param>
/// <remarks>
/// <para>
/// This constructor enables reusing cached tool definitions across different <see cref="McpClient"/> instances
/// without needing to call <see cref="McpClient.ListToolsAsync"/> on every reconnect. This is particularly useful
/// in scenarios where tool definitions are stable and network round-trips should be minimized.
/// </para>
/// <para>
/// The provided <paramref name="tool"/> must represent a tool that is actually available on the server
/// associated with the <paramref name="client"/>. Attempting to invoke a tool that doesn't exist on the
/// server will result in an <see cref="McpException"/>.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="tool"/> is <see langword="null"/>.</exception>
public McpClientTool(
McpClient client,
Tool tool,
JsonSerializerOptions? serializerOptions = null)
{
Throw.IfNull(client);
Throw.IfNull(tool);
_client = client;
ProtocolTool = tool;
JsonSerializerOptions = serializerOptions ?? McpJsonUtilities.DefaultOptions;
_name = tool.Name;
_description = tool.Description ?? string.Empty;
_progress = null;
}
internal McpClientTool(
McpClient client,
Tool tool,