Remove obsolete APIs from codebase and standardize MCP diagnostic IDs (#985)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: MackinnonBuck <10456961+MackinnonBuck@users.noreply.github.com>
Co-authored-by: eiriktsarpalis <2813363+eiriktsarpalis@users.noreply.github.com>
Co-authored-by: Mackinnon Buck <mackinnon.buck@gmail.com>
Co-authored-by: jeffhandley <1031940+jeffhandley@users.noreply.github.com>
Co-authored-by: Jeff Handley <jeffhandley@users.noreply.github.com>
This commit is contained in:
Copilot 2025-12-02 10:28:46 -08:00 • committed by GitHub
commit 136755f2be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 663 additions and 2674 deletions

View file

@ -1,50 +0,0 @@
using ModelContextProtocol.Protocol;
using System.ComponentModel;
namespace ModelContextProtocol.Client;
/// <summary>
/// Represents an instance of a Model Context Protocol (MCP) client that connects to and communicates with an MCP server.
/// </summary>
[Obsolete($"Use {nameof(McpClient)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public interface IMcpClient : IMcpEndpoint
{
/// <summary>
/// Gets the capabilities supported by the connected server.
/// </summary>
/// <exception cref="InvalidOperationException">The client is not connected.</exception>
ServerCapabilities ServerCapabilities { get; }
/// <summary>
/// Gets the implementation information of the connected server.
/// </summary>
/// <remarks>
/// <para>
/// This property provides identification details about the connected server, including its name and version.
/// It is populated during the initialization handshake and is available after a successful connection.
/// </para>
/// <para>
/// This information can be useful for logging, debugging, compatibility checks, and displaying server
/// information to users.
/// </para>
/// </remarks>
/// <exception cref="InvalidOperationException">The client is not connected.</exception>
Implementation ServerInfo { get; }
/// <summary>
/// Gets any instructions describing how to use the connected server and its features.
/// </summary>
/// <remarks>
/// <para>
/// This property contains instructions provided by the server during initialization that explain
/// how to effectively use its capabilities. These instructions can include details about available
/// tools, expected input formats, limitations, or any other helpful information.
/// </para>
/// <para>
/// This can be used by clients to improve an LLM's understanding of available tools, prompts, and resources.
/// It can be thought of like a "hint" to the model and may be added to a system prompt.
/// </para>
/// </remarks>
string? ServerInstructions { get; }
}

View file

@ -10,9 +10,7 @@ namespace ModelContextProtocol.Client;
/// <summary>
/// Represents an instance of a Model Context Protocol (MCP) client session that connects to and communicates with an MCP server.
/// </summary>
#pragma warning disable CS0618 // Type or member is obsolete
public abstract partial class McpClient : McpSession, IMcpClient
#pragma warning restore CS0618 // Type or member is obsolete
public abstract partial class McpClient : McpSession
{
/// <summary>Creates an <see cref="McpClient"/>, connecting it to the specified server.</summary>
/// <param name="clientTransport">The transport instance used to communicate with the server.</param>

View file

@ -5,9 +5,7 @@ namespace ModelContextProtocol.Client;
/// <summary>
/// Represents an instance of a Model Context Protocol (MCP) client session that connects to and communicates with an MCP server.
/// </summary>
#pragma warning disable CS0618 // Type or member is obsolete
public abstract partial class McpClient : McpSession, IMcpClient
#pragma warning restore CS0618 // Type or member is obsolete
public abstract partial class McpClient : McpSession
{
/// <summary>
/// Gets the capabilities supported by the connected server.

View file

@ -1,608 +0,0 @@
using Microsoft.Extensions.AI;
using ModelContextProtocol.Protocol;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Text.Json;
namespace ModelContextProtocol.Client;
/// <summary>
/// Provides extension methods for interacting with an <see cref="McpClient"/>.
/// </summary>
/// <remarks>
/// This class contains extension methods that simplify common operations with an MCP client,
/// such as pinging a server, listing and working with tools, prompts, and resources, and
/// managing subscriptions to resources.
/// </remarks>
public static class McpClientExtensions
{
/// <summary>
/// Sends a ping request to verify server connectivity.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task that completes when the ping is successful.</returns>
/// <remarks>
/// <para>
/// This method is used to check if the MCP server is online and responding to requests.
/// It can be useful for health checking, ensuring the connection is established, or verifying
/// that the client has proper authorization to communicate with the server.
/// </para>
/// <para>
/// The ping operation is lightweight and does not require any parameters. A successful completion
/// of the task indicates that the server is operational and accessible.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="McpException">The server cannot be reached or returned an error response.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.PingAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task PingAsync(this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).PingAsync(cancellationToken);
/// <summary>
/// Retrieves a list of available tools from the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="serializerOptions">The serializer options governing tool parameter serialization. If null, the default options are used.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A list of all available tools as <see cref="McpClientTool"/> instances.</returns>
/// <remarks>
/// <para>
/// This method fetches all available tools from the MCP server and returns them as a complete list.
/// It automatically handles pagination with cursors if the server responds with only a portion per request.
/// </para>
/// <para>
/// For servers with a large number of tools and that responds with paginated responses, consider using
/// <see cref="EnumerateToolsAsync"/> instead, because it streams tools as they arrive rather than loading them all at once.
/// </para>
/// <para>
/// The serializer options provided are flowed to each <see cref="McpClientTool"/> and will be used
/// when invoking tools in order to serialize any parameters.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// // Get all tools available on the server
/// var tools = await mcpClient.ListToolsAsync();
///
/// // Use tools with an AI client
/// ChatOptions chatOptions = new()
/// {
/// Tools = [.. tools]
/// };
///
/// await foreach (var update in chatClient.GetStreamingResponseAsync(userMessage, chatOptions))
/// {
/// Console.Write(update);
/// }
/// </code>
/// </example>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.ListToolsAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<IList<McpClientTool>> ListToolsAsync(
this IMcpClient client,
JsonSerializerOptions? serializerOptions = null,
CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ListToolsAsync(serializerOptions, cancellationToken);
/// <summary>
/// Creates an enumerable for asynchronously enumerating all available tools from the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="serializerOptions">The serializer options governing tool parameter serialization. If null, the default options are used.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>An asynchronous sequence of all available tools as <see cref="McpClientTool"/> instances.</returns>
/// <remarks>
/// <para>
/// This method uses asynchronous enumeration to retrieve tools from the server, which allows processing tools
/// as they arrive rather than waiting for all tools to be retrieved. The method automatically handles pagination
/// with cursors if the server responds with tools split across multiple responses.
/// </para>
/// <para>
/// The serializer options provided are flowed to each <see cref="McpClientTool"/> and will be used
/// when invoking tools to serialize any parameters.
/// </para>
/// <para>
/// Every iteration through the returned <see cref="IAsyncEnumerable{McpClientTool}"/>
/// will result in re-querying the server and yielding the sequence of available tools.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// // Enumerate all tools available on the server
/// await foreach (var tool in client.EnumerateToolsAsync())
/// {
/// Console.WriteLine($"Tool: {tool.Name}");
/// }
/// </code>
/// </example>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.EnumerateToolsAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static IAsyncEnumerable<McpClientTool> EnumerateToolsAsync(
this IMcpClient client,
JsonSerializerOptions? serializerOptions = null,
CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).EnumerateToolsAsync(serializerOptions, cancellationToken);
/// <summary>
/// Retrieves a list of available prompts from the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A list of all available prompts as <see cref="McpClientPrompt"/> instances.</returns>
/// <remarks>
/// <para>
/// This method fetches all available prompts from the MCP server and returns them as a complete list.
/// It automatically handles pagination with cursors if the server responds with only a portion per request.
/// </para>
/// <para>
/// For servers with a large number of prompts and that responds with paginated responses, consider using
/// <see cref="EnumeratePromptsAsync"/> instead, as it streams prompts as they arrive rather than loading them all at once.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.ListPromptsAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<IList<McpClientPrompt>> ListPromptsAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ListPromptsAsync(cancellationToken);
/// <summary>
/// Creates an enumerable for asynchronously enumerating all available prompts from the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>An asynchronous sequence of all available prompts as <see cref="McpClientPrompt"/> instances.</returns>
/// <remarks>
/// <para>
/// This method uses asynchronous enumeration to retrieve prompts from the server, which allows processing prompts
/// as they arrive rather than waiting for all prompts to be retrieved. The method automatically handles pagination
/// with cursors if the server responds with prompts split across multiple responses.
/// </para>
/// <para>
/// Every iteration through the returned <see cref="IAsyncEnumerable{McpClientPrompt}"/>
/// will result in re-querying the server and yielding the sequence of available prompts.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// // Enumerate all prompts available on the server
/// await foreach (var prompt in client.EnumeratePromptsAsync())
/// {
/// Console.WriteLine($"Prompt: {prompt.Name}");
/// }
/// </code>
/// </example>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.EnumeratePromptsAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static IAsyncEnumerable<McpClientPrompt> EnumeratePromptsAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).EnumeratePromptsAsync(cancellationToken);
/// <summary>
/// Retrieves a specific prompt from the MCP server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="name">The name of the prompt to retrieve.</param>
/// <param name="arguments">Optional arguments for the prompt. Keys are parameter names, and values are the argument values.</param>
/// <param name="serializerOptions">The serialization options governing argument serialization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task containing the prompt's result with content and messages.</returns>
/// <remarks>
/// <para>
/// This method sends a request to the MCP server to create the specified prompt with the provided arguments.
/// The server will process the arguments and return a prompt containing messages or other content.
/// </para>
/// <para>
/// Arguments are serialized into JSON and passed to the server, where they may be used to customize the
/// prompt's behavior or content. Each prompt may have different argument requirements.
/// </para>
/// <para>
/// The returned <see cref="GetPromptResult"/> contains a collection of <see cref="PromptMessage"/> objects,
/// which can be converted to <see cref="ChatMessage"/> objects using the <see cref="AIContentExtensions.ToChatMessages"/> method.
/// </para>
/// </remarks>
/// <exception cref="McpException">Thrown when the prompt does not exist, when required arguments are missing, or when the server encounters an error processing the prompt.</exception>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.GetPromptAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<GetPromptResult> GetPromptAsync(
this IMcpClient client,
string name,
IReadOnlyDictionary<string, object?>? arguments = null,
JsonSerializerOptions? serializerOptions = null,
CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).GetPromptAsync(name, arguments, serializerOptions, cancellationToken);
/// <summary>
/// Retrieves a list of available resource templates from the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A list of all available resource templates as <see cref="ResourceTemplate"/> instances.</returns>
/// <remarks>
/// <para>
/// This method fetches all available resource templates from the MCP server and returns them as a complete list.
/// It automatically handles pagination with cursors if the server responds with only a portion per request.
/// </para>
/// <para>
/// For servers with a large number of resource templates and that responds with paginated responses, consider using
/// <see cref="EnumerateResourceTemplatesAsync"/> instead, as it streams templates as they arrive rather than loading them all at once.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.ListResourceTemplatesAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<IList<McpClientResourceTemplate>> ListResourceTemplatesAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ListResourceTemplatesAsync(cancellationToken);
/// <summary>
/// Creates an enumerable for asynchronously enumerating all available resource templates from the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>An asynchronous sequence of all available resource templates as <see cref="ResourceTemplate"/> instances.</returns>
/// <remarks>
/// <para>
/// This method uses asynchronous enumeration to retrieve resource templates from the server, which allows processing templates
/// as they arrive rather than waiting for all templates to be retrieved. The method automatically handles pagination
/// with cursors if the server responds with templates split across multiple responses.
/// </para>
/// <para>
/// Every iteration through the returned <see cref="IAsyncEnumerable{McpClientResourceTemplate}"/>
/// will result in re-querying the server and yielding the sequence of available resource templates.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// // Enumerate all resource templates available on the server
/// await foreach (var template in client.EnumerateResourceTemplatesAsync())
/// {
/// Console.WriteLine($"Template: {template.Name}");
/// }
/// </code>
/// </example>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.EnumerateResourceTemplatesAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static IAsyncEnumerable<McpClientResourceTemplate> EnumerateResourceTemplatesAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).EnumerateResourceTemplatesAsync(cancellationToken);
/// <summary>
/// Retrieves a list of available resources from the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A list of all available resources as <see cref="Resource"/> instances.</returns>
/// <remarks>
/// <para>
/// This method fetches all available resources from the MCP server and returns them as a complete list.
/// It automatically handles pagination with cursors if the server responds with only a portion per request.
/// </para>
/// <para>
/// For servers with a large number of resources and that responds with paginated responses, consider using
/// <see cref="EnumerateResourcesAsync"/> instead, as it streams resources as they arrive rather than loading them all at once.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// // Get all resources available on the server
/// var resources = await client.ListResourcesAsync();
///
/// // Display information about each resource
/// foreach (var resource in resources)
/// {
/// Console.WriteLine($"Resource URI: {resource.Uri}");
/// }
/// </code>
/// </example>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.ListResourcesAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<IList<McpClientResource>> ListResourcesAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ListResourcesAsync(cancellationToken);
/// <summary>
/// Creates an enumerable for asynchronously enumerating all available resources from the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>An asynchronous sequence of all available resources as <see cref="Resource"/> instances.</returns>
/// <remarks>
/// <para>
/// This method uses asynchronous enumeration to retrieve resources from the server, which allows processing resources
/// as they arrive rather than waiting for all resources to be retrieved. The method automatically handles pagination
/// with cursors if the server responds with resources split across multiple responses.
/// </para>
/// <para>
/// Every iteration through the returned <see cref="IAsyncEnumerable{McpClientResource}"/>
/// will result in re-querying the server and yielding the sequence of available resources.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// // Enumerate all resources available on the server
/// await foreach (var resource in client.EnumerateResourcesAsync())
/// {
/// Console.WriteLine($"Resource URI: {resource.Uri}");
/// }
/// </code>
/// </example>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.EnumerateResourcesAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static IAsyncEnumerable<McpClientResource> EnumerateResourcesAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).EnumerateResourcesAsync(cancellationToken);
/// <summary>
/// Reads a resource from the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="uri">The uri of the resource.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="uri"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException"><paramref name="uri"/> is empty or composed entirely of whitespace.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.ReadResourceAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<ReadResourceResult> ReadResourceAsync(
this IMcpClient client, string uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ReadResourceAsync(uri, cancellationToken);
/// <summary>
/// Reads a resource from the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="uri">The uri of the resource.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="uri"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.ReadResourceAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<ReadResourceResult> ReadResourceAsync(
this IMcpClient client, Uri uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ReadResourceAsync(uri, cancellationToken);
/// <summary>
/// Reads a resource from the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="uriTemplate">The uri template of the resource.</param>
/// <param name="arguments">Arguments to use to format <paramref name="uriTemplate"/>.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="uriTemplate"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException"><paramref name="uriTemplate"/> is empty or composed entirely of whitespace.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.ReadResourceAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<ReadResourceResult> ReadResourceAsync(
this IMcpClient client, string uriTemplate, IReadOnlyDictionary<string, object?> arguments, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).ReadResourceAsync(uriTemplate, arguments, cancellationToken);
/// <summary>
/// Requests completion suggestions for a prompt argument or resource reference.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="reference">The reference object specifying the type and optional URI or name.</param>
/// <param name="argumentName">The name of the argument for which completions are requested.</param>
/// <param name="argumentValue">The current value of the argument, used to filter relevant completions.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A <see cref="CompleteResult"/> containing completion suggestions.</returns>
/// <remarks>
/// <para>
/// This method allows clients to request auto-completion suggestions for arguments in a prompt template
/// or for resource references.
/// </para>
/// <para>
/// When working with prompt references, the server will return suggestions for the specified argument
/// that match or begin with the current argument value. This is useful for implementing intelligent
/// auto-completion in user interfaces.
/// </para>
/// <para>
/// When working with resource references, the server will return suggestions relevant to the specified
/// resource URI.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="reference"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="argumentName"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException"><paramref name="argumentName"/> is empty or composed entirely of whitespace.</exception>
/// <exception cref="McpException">The server returned an error response.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.CompleteAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<CompleteResult> CompleteAsync(this IMcpClient client, Reference reference, string argumentName, string argumentValue, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).CompleteAsync(reference, argumentName, argumentValue, cancellationToken);
/// <summary>
/// Subscribes to a resource on the server to receive notifications when it changes.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="uri">The URI of the resource to which to subscribe.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
/// <remarks>
/// <para>
/// This method allows the client to register interest in a specific resource identified by its URI.
/// When the resource changes, the server will send notifications to the client, enabling real-time
/// updates without polling.
/// </para>
/// <para>
/// The subscription remains active until explicitly unsubscribed using <see cref="M:UnsubscribeFromResourceAsync"/>
/// or until the client disconnects from the server.
/// </para>
/// <para>
/// To handle resource change notifications, register an event handler for the appropriate notification events,
/// such as with <see cref="IMcpEndpoint.RegisterNotificationHandler"/>.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="uri"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException"><paramref name="uri"/> is empty or composed entirely of whitespace.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.SubscribeToResourceAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task SubscribeToResourceAsync(this IMcpClient client, string uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).SubscribeToResourceAsync(uri, cancellationToken);
/// <summary>
/// Subscribes to a resource on the server to receive notifications when it changes.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="uri">The URI of the resource to which to subscribe.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
/// <remarks>
/// <para>
/// This method allows the client to register interest in a specific resource identified by its URI.
/// When the resource changes, the server will send notifications to the client, enabling real-time
/// updates without polling.
/// </para>
/// <para>
/// The subscription remains active until explicitly unsubscribed using <see cref="M:UnsubscribeFromResourceAsync"/>
/// or until the client disconnects from the server.
/// </para>
/// <para>
/// To handle resource change notifications, register an event handler for the appropriate notification events,
/// such as with <see cref="IMcpEndpoint.RegisterNotificationHandler"/>.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="uri"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.SubscribeToResourceAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task SubscribeToResourceAsync(this IMcpClient client, Uri uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).SubscribeToResourceAsync(uri, cancellationToken);
/// <summary>
/// Unsubscribes from a resource on the server to stop receiving notifications about its changes.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="uri">The URI of the resource to unsubscribe from.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
/// <remarks>
/// <para>
/// This method cancels a previous subscription to a resource, stopping the client from receiving
/// notifications when that resource changes.
/// </para>
/// <para>
/// The unsubscribe operation is idempotent, meaning it can be called multiple times for the same
/// resource without causing errors, even if there is no active subscription.
/// </para>
/// <para>
/// Due to the nature of the MCP protocol, it is possible the client may receive notifications after
/// unsubscribing if those notifications were issued by the server prior to the unsubscribe request being received.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="uri"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException"><paramref name="uri"/> is empty or composed entirely of whitespace.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.UnsubscribeFromResourceAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task UnsubscribeFromResourceAsync(this IMcpClient client, string uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).UnsubscribeFromResourceAsync(uri, cancellationToken);
/// <summary>
/// Unsubscribes from a resource on the server to stop receiving notifications about its changes.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="uri">The URI of the resource to unsubscribe from.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
/// <remarks>
/// <para>
/// This method cancels a previous subscription to a resource, stopping the client from receiving
/// notifications when that resource changes.
/// </para>
/// <para>
/// The unsubscribe operation is idempotent, meaning it can be called multiple times for the same
/// resource without causing errors, even if there is no active subscription.
/// </para>
/// <para>
/// Due to the nature of the MCP protocol, it is possible the client may receive notifications after
/// unsubscribing if those notifications were issued by the server prior to the unsubscribe request being received.
/// </para>
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="uri"/> is <see langword="null"/>.</exception>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.UnsubscribeFromResourceAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static Task UnsubscribeFromResourceAsync(this IMcpClient client, Uri uri, CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).UnsubscribeFromResourceAsync(uri, cancellationToken);
/// <summary>
/// Invokes a tool on the server.
/// </summary>
/// <param name="client">The client instance used to communicate with the MCP server.</param>
/// <param name="toolName">The name of the tool to call on the server..</param>
/// <param name="arguments">An optional dictionary of arguments to pass to the tool. Each key represents a parameter name,
/// and its associated value represents the argument value.
/// </param>
/// <param name="progress">
/// An optional <see cref="IProgress{T}"/> to have progress notifications reported to it. Setting this to a non-<see langword="null"/>
/// value will result in a progress token being included in the call, and any resulting progress notifications during the operation
/// routed to this instance.
/// </param>
/// <param name="serializerOptions">
/// The JSON serialization options governing argument serialization. If <see langword="null"/>, the default serialization options are used.
/// </param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>
/// A task containing the <see cref="CallToolResult"/> from the tool execution. The response includes
/// the tool's output content, which may be structured data, text, or an error message.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="client"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="toolName"/> is <see langword="null"/>.</exception>
/// <exception cref="McpException">The server could not find the requested tool, or the server encountered an error while processing the request.</exception>
/// <example>
/// <code>
/// // Call a simple echo tool with a string argument
/// var result = await client.CallToolAsync(
/// "echo",
/// new Dictionary&lt;string, object?&gt;
/// {
/// ["message"] = "Hello MCP!"
/// });
/// </code>
/// </example>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.CallToolAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static ValueTask<CallToolResult> CallToolAsync(
this IMcpClient client,
string toolName,
IReadOnlyDictionary<string, object?>? arguments = null,
IProgress<ProgressNotificationValue>? progress = null,
JsonSerializerOptions? serializerOptions = null,
CancellationToken cancellationToken = default)
=> AsClientOrThrow(client).CallToolAsync(toolName, arguments, progress, serializerOptions, cancellationToken);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#pragma warning disable CS0618 // Type or member is obsolete
private static McpClient AsClientOrThrow(IMcpClient client, [CallerMemberName] string memberName = "")
#pragma warning restore CS0618 // Type or member is obsolete
{
if (client is not McpClient mcpClient)
{
ThrowInvalidEndpointType(memberName);
}
return mcpClient;
[DoesNotReturn]
[MethodImpl(MethodImplOptions.NoInlining)]
static void ThrowInvalidEndpointType(string memberName)
=> throw new InvalidOperationException(
$"Only arguments assignable to '{nameof(McpClient)}' are supported. " +
$"Prefer using '{nameof(McpClient)}.{memberName}' instead, as " +
$"'{nameof(McpClientExtensions)}.{memberName}' is obsolete and will be " +
$"removed in the future.");
}
}

View file

@ -1,35 +0,0 @@
using Microsoft.Extensions.Logging;
using System.ComponentModel;
namespace ModelContextProtocol.Client;
/// <summary>
/// Provides factory methods for creating Model Context Protocol (MCP) clients.
/// </summary>
/// <remarks>
/// This factory class is the primary way to instantiate <see cref="IMcpClient"/> instances
/// that connect to MCP servers. It handles the creation and connection
/// of appropriate implementations through the supplied transport.
/// </remarks>
[Obsolete($"Use {nameof(McpClient)}.{nameof(McpClient.CreateAsync)} instead. This member will be removed in a subsequent release.")] // See: https://github.com/modelcontextprotocol/csharp-sdk/issues/774
[EditorBrowsable(EditorBrowsableState.Never)]
public static partial class McpClientFactory
{
/// <summary>Creates an <see cref="IMcpClient"/>, connecting it to the specified server.</summary>
/// <param name="clientTransport">The transport instance used to communicate with the server.</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="loggerFactory">A logger factory for creating loggers for clients.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>An <see cref="IMcpClient"/> that's connected to the specified server.</returns>
/// <exception cref="ArgumentNullException"><paramref name="clientTransport"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="clientOptions"/> is <see langword="null"/>.</exception>
public static async Task<IMcpClient> CreateAsync(
IClientTransport clientTransport,
McpClientOptions? clientOptions = null,
ILoggerFactory? loggerFactory = null,
CancellationToken cancellationToken = default)
=> await McpClient.CreateAsync(clientTransport, clientOptions, loggerFactory, cancellationToken);
}

View file

@ -36,7 +36,7 @@ public class McpClientHandlers
/// </para>
/// <para>
/// Handlers provided via <see cref="NotificationHandlers"/> will be registered with the client for the lifetime of the client.
/// For transient handlers, you can use <see cref="IMcpEndpoint.RegisterNotificationHandler"/> to register a handler that can
/// For transient handlers, you can use <see cref="McpSession.RegisterNotificationHandler"/> to register a handler that can
/// then be unregistered by disposing of the <see cref="IAsyncDisposable"/> returned from the method.
/// </para>
/// </remarks>

View file

@ -58,12 +58,10 @@ internal sealed partial class McpClientImpl : McpClient
{
McpClientHandlers handlers = options.Handlers;
#pragma warning disable CS0618 // Type or member is obsolete
var notificationHandlersFromOptions = handlers.NotificationHandlers ?? options.Capabilities?.NotificationHandlers;
var samplingHandler = handlers.SamplingHandler ?? options.Capabilities?.Sampling?.SamplingHandler;
var rootsHandler = handlers.RootsHandler ?? options.Capabilities?.Roots?.RootsHandler;
var elicitationHandler = handlers.ElicitationHandler ?? options.Capabilities?.Elicitation?.ElicitationHandler;
#pragma warning restore CS0618 // Type or member is obsolete
var notificationHandlersFromOptions = handlers.NotificationHandlers;
var samplingHandler = handlers.SamplingHandler;
var rootsHandler = handlers.RootsHandler;
var elicitationHandler = handlers.ElicitationHandler;
if (notificationHandlersFromOptions is not null)
{