Clean up and add more comments (#2)
This commit is contained in:
parent
79af38cf21
commit
9a244f5770
5 changed files with 349 additions and 653 deletions
|
|
@ -5,6 +5,8 @@ using McpDotNet.Protocol.Messages;
|
|||
|
||||
/// <summary>
|
||||
/// Represents an instance of the MCP client connecting to a specific server.
|
||||
/// Use PingAsync, ListToolsAsync and CallToolAsync instead of SendRequestAsync for common operations.
|
||||
/// SendRequestAsync is provided for custom request and those not yet covered explicitly by the client.
|
||||
/// </summary>
|
||||
public interface IMcpClient : IAsyncDisposable
|
||||
{
|
||||
|
|
@ -14,44 +16,58 @@ public interface IMcpClient : IAsyncDisposable
|
|||
bool IsInitialized { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the capabilities that the server supports.
|
||||
/// Gets the capabilities supported by the server.
|
||||
/// </summary>
|
||||
ServerCapabilities? ServerCapabilities { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version information of the server.
|
||||
/// Gets the version and implementation information of the server.
|
||||
/// </summary>
|
||||
Implementation? ServerInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the server.
|
||||
/// Establishes a connection to the server.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
Task ConnectAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// A simple ping to the server to check if it is alive. Task completes when the ping is successful.
|
||||
/// Sends a ping request to verify server connectivity.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
||||
/// <returns>A task that completes when the ping is successful.</returns>
|
||||
Task PingAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Queries the server for a list of tools that are available (if any)
|
||||
/// Retrieves a list of available tools from the server.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
||||
/// <returns>A task containing the server's response with tool information.</returns>
|
||||
Task<ListToolsResponse> ListToolsAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Calls a tool on the server.
|
||||
/// Invokes a tool on the server with optional arguments.
|
||||
/// </summary>
|
||||
/// <param name="toolName">The name of the tool as given when listing tool definitions.</param>
|
||||
/// <param name="arguments">Arguments for the tool (if any)</param>
|
||||
/// <param name="toolName">The name of the tool to call.</param>
|
||||
/// <param name="arguments">Optional arguments for the tool.</param>
|
||||
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
||||
/// <returns>A task containing the tool's response.</returns>
|
||||
Task<CallToolResponse> CallToolAsync(string toolName, Dictionary<string, object>? arguments = null, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// A generic method to send a request to the server and get a response.
|
||||
/// Sends a generic JSON-RPC request to the server.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The expected response type.</typeparam>
|
||||
/// <param name="request">The JSON-RPC request to send.</param>
|
||||
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
||||
/// <returns>A task containing the server's response.</returns>
|
||||
Task<T> SendRequestAsync<T>(JsonRpcRequest request, CancellationToken cancellationToken) where T : class;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a handler for a specific notification method.
|
||||
/// Registers a handler for server notifications of a specific method.
|
||||
/// </summary>
|
||||
/// <param name="method">The notification method to handle.</param>
|
||||
/// <param name="handler">The async handler function to process notifications.</param>
|
||||
void OnNotification(string method, Func<JsonRpcNotification, Task> handler);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
// Client/McpClientOptions.cs
|
||||
namespace McpDotNet.Client;
|
||||
namespace McpDotNet.Client;
|
||||
|
||||
using McpDotNet.Protocol.Types;
|
||||
using McpDotNet.Protocol.Transport;
|
||||
|
|
@ -9,10 +8,8 @@ using System.Diagnostics;
|
|||
using System.Text.Json;
|
||||
using McpDotNet.Utils.Json;
|
||||
|
||||
/// <summary>
|
||||
/// Main MCP client implementation that handles protocol lifecycle and message routing.
|
||||
/// </summary>
|
||||
public class McpClient : IMcpClient
|
||||
/// </inheritdoc>
|
||||
internal class McpClient : IMcpClient
|
||||
{
|
||||
private readonly IMcpTransport _transport;
|
||||
private readonly McpClientOptions _options;
|
||||
|
|
@ -24,21 +21,20 @@ public class McpClient : IMcpClient
|
|||
private CancellationTokenSource? _cts;
|
||||
private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions().ConfigureForMcp();
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the client is connected and initialized.
|
||||
/// </summary>
|
||||
/// </inheritdoc>
|
||||
public bool IsInitialized => _isInitialized;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the server's capabilities after initialization.
|
||||
/// </summary>
|
||||
/// </inheritdoc>
|
||||
public ServerCapabilities? ServerCapabilities { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets information about the server implementation after initialization.
|
||||
/// </summary>
|
||||
/// </inheritdoc>
|
||||
public Implementation? ServerInfo { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="McpClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="transport">An MCP transport implementation.</param>
|
||||
/// <param name="options">Options for the client, defining protocol version and capabilities.</param>
|
||||
public McpClient(IMcpTransport transport, McpClientOptions options)
|
||||
{
|
||||
_transport = transport;
|
||||
|
|
@ -48,9 +44,7 @@ public class McpClient : IMcpClient
|
|||
_nextRequestId = 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the server and performs the initialization sequence.
|
||||
/// </summary>
|
||||
/// </inheritdoc>
|
||||
public async Task ConnectAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_isInitialized)
|
||||
|
|
@ -128,6 +122,7 @@ public class McpClient : IMcpClient
|
|||
}
|
||||
}
|
||||
|
||||
/// </inheritdoc>
|
||||
public async Task PingAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await SendRequestAsync<dynamic>(
|
||||
|
|
@ -139,6 +134,7 @@ public class McpClient : IMcpClient
|
|||
).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// </inheritdoc>
|
||||
public async Task<ListToolsResponse> ListToolsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return await SendRequestAsync<ListToolsResponse>(
|
||||
|
|
@ -151,6 +147,7 @@ public class McpClient : IMcpClient
|
|||
).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// </inheritdoc>
|
||||
public async Task<CallToolResponse> CallToolAsync(string toolName, Dictionary<string, object>? arguments = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
|
@ -218,6 +215,7 @@ public class McpClient : IMcpClient
|
|||
}
|
||||
}
|
||||
|
||||
/// </inheritdoc>
|
||||
public async Task<T> SendRequestAsync<T>(JsonRpcRequest request, CancellationToken cancellationToken) where T : class
|
||||
{
|
||||
if (!_transport.IsConnected)
|
||||
|
|
@ -275,9 +273,7 @@ public class McpClient : IMcpClient
|
|||
await _transport.SendMessageAsync(notification, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a handler for notifications of a specific method.
|
||||
/// </summary>
|
||||
/// </inheritdoc>
|
||||
public void OnNotification(string method, Func<JsonRpcNotification,Task> handler)
|
||||
{
|
||||
var handlers = _notificationHandlers.GetOrAdd(method, _ => new());
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
// Client/McpClientOptions.cs
|
||||
namespace McpDotNet.Client;
|
||||
namespace McpDotNet.Client;
|
||||
|
||||
/// <summary>
|
||||
/// Represents errors that occur in the MCP client.
|
||||
|
|
@ -11,15 +10,29 @@ public class McpClientException : Exception
|
|||
/// </summary>
|
||||
public int? ErrorCode { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="McpClientException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public McpClientException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="McpClientException"/> class with a specified error message and error code.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
/// <param name="errorCode">The error code associated with the JSON-RPC error response.</param>
|
||||
public McpClientException(string message, int errorCode) : base(message)
|
||||
{
|
||||
ErrorCode = errorCode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="McpClientException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public McpClientException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
// Client/McpClientFactory.cs
|
||||
namespace McpDotNet.Client;
|
||||
namespace McpDotNet.Client;
|
||||
|
||||
using McpDotNet.Configuration;
|
||||
using McpDotNet.Protocol.Transport;
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating MCP clients based on configuration.
|
||||
/// Factory for creating MCP clients based on configuration. It caches clients for reuse, so it is safe to call GetClientAsync multiple times.
|
||||
/// Call GetClientAsync to get a client for a specific server (by ID), which will create a new client and connect if it doesn't already exist.
|
||||
/// All server configurations must be passed in the constructor.
|
||||
/// Capabilities (as defined in client options) are shared across all clients, as the client host can always decide not to use certain capabilities.
|
||||
/// </summary>
|
||||
public class McpClientFactory
|
||||
{
|
||||
|
|
@ -15,6 +17,15 @@ public class McpClientFactory
|
|||
private readonly Func<McpServerConfig, IMcpTransport> _transportFactoryMethod;
|
||||
private readonly Func<IMcpTransport, McpClientOptions, IMcpClient> _clientFactoryMethod;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="McpClientFactory"/> class.
|
||||
/// It is not necessary to pass factory methods for creating transports and clients, as default implementations are provided.
|
||||
/// Custom factory methods can be provided for mocking or to use custom transport or client implementations.
|
||||
/// </summary>
|
||||
/// <param name="serverConfigs">Configuration objects for each server the factory should support.</param>
|
||||
/// <param name="clientOptions">A configuration object which specifies client capabilities and protocol version.</param>
|
||||
/// <param name="transportFactoryMethod">An optional factory method which returns transport implementations based on a server configuration.</param>
|
||||
/// <param name="clientFactoryMethod">An optional factory method which creates a client based on client options and transport implementation. </param>
|
||||
public McpClientFactory(
|
||||
IEnumerable<McpServerConfig> serverConfigs,
|
||||
McpClientOptions clientOptions,
|
||||
|
|
@ -28,8 +39,12 @@ public class McpClientFactory
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or creates a client for the specified server.
|
||||
/// Gets or creates a client for the specified server. The first time a server is requested, a new client is created and connected.
|
||||
/// Note that this will often spawn the server process during connection, so in some cases you want to call this method only when needed.
|
||||
/// In other cases, you may want to call it ahead of time to ensure the server is ready when needed, as it may take some time to start up.
|
||||
/// </summary>
|
||||
/// <param name="serverId">The ID of the server to connect to. It must have been passed in the serverConfigs when constructing the factory.</param>
|
||||
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
||||
public async Task<IMcpClient> GetClientAsync(string serverId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!_serverConfigs.TryGetValue(serverId, out var config))
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
// Client/McpClientOptions.cs
|
||||
using McpDotNet.Protocol.Types;
|
||||
|
||||
namespace McpDotNet.Client;
|
||||
|
||||
using global::McpDotNet.Protocol.Types;
|
||||
|
||||
/// <summary>
|
||||
/// Configuration options for the MCP client.
|
||||
/// Configuration options for the MCP client. This is passed to servers during the initialization sequence, letting them know about the client's capabilities and
|
||||
/// protocol version.
|
||||
/// <see href="https://spec.modelcontextprotocol.io/specification/basic/lifecycle/">See the protocol specification for details on capability negotiation</see>
|
||||
/// </summary>
|
||||
public record McpClientOptions
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue