using ModelContextProtocol.Client; using ModelContextProtocol.Protocol.Messages; using ModelContextProtocol.Server; using ModelContextProtocol.Utils; using ModelContextProtocol.Utils.Json; using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Serialization.Metadata; namespace ModelContextProtocol; /// /// Provides extension methods for interacting with an . /// /// /// /// This class provides strongly-typed methods for working with the Model Context Protocol (MCP) endpoints, /// simplifying JSON-RPC communication by handling serialization and deserialization of parameters and results. /// /// /// These extension methods are designed to be used with both client () and /// server () implementations of the interface. /// /// public static class McpEndpointExtensions { /// /// Sends a JSON-RPC request and attempts to deserialize the result to . /// /// The type of the request parameters to serialize from. /// The type of the result to deserialize to. /// The MCP client or server instance. /// The JSON-RPC method name to invoke. /// Object representing the request parameters. /// The request id for the request. /// The options governing request serialization. /// The to monitor for cancellation requests. The default is . /// A task that represents the asynchronous operation. The task result contains the deserialized result. public static ValueTask SendRequestAsync( this IMcpEndpoint endpoint, string method, TParameters parameters, JsonSerializerOptions? serializerOptions = null, RequestId requestId = default, CancellationToken cancellationToken = default) where TResult : notnull { serializerOptions ??= McpJsonUtilities.DefaultOptions; serializerOptions.MakeReadOnly(); JsonTypeInfo paramsTypeInfo = serializerOptions.GetTypeInfo(); JsonTypeInfo resultTypeInfo = serializerOptions.GetTypeInfo(); return SendRequestAsync(endpoint, method, parameters, paramsTypeInfo, resultTypeInfo, requestId, cancellationToken); } /// /// Sends a JSON-RPC request and attempts to deserialize the result to . /// /// The type of the request parameters to serialize from. /// The type of the result to deserialize to. /// The MCP client or server instance. /// The JSON-RPC method name to invoke. /// Object representing the request parameters. /// The type information for request parameter serialization. /// The type information for request parameter deserialization. /// The request id for the request. /// The to monitor for cancellation requests. The default is . /// A task that represents the asynchronous operation. The task result contains the deserialized result. internal static async ValueTask SendRequestAsync( this IMcpEndpoint endpoint, string method, TParameters parameters, JsonTypeInfo parametersTypeInfo, JsonTypeInfo resultTypeInfo, RequestId requestId = default, CancellationToken cancellationToken = default) where TResult : notnull { Throw.IfNull(endpoint); Throw.IfNullOrWhiteSpace(method); Throw.IfNull(parametersTypeInfo); Throw.IfNull(resultTypeInfo); JsonRpcRequest jsonRpcRequest = new() { Id = requestId, Method = method, Params = JsonSerializer.SerializeToNode(parameters, parametersTypeInfo), }; JsonRpcResponse response = await endpoint.SendRequestAsync(jsonRpcRequest, cancellationToken).ConfigureAwait(false); return JsonSerializer.Deserialize(response.Result, resultTypeInfo) ?? throw new JsonException("Unexpected JSON result in response."); } /// /// Sends a parameterless notification to the connected endpoint. /// /// The MCP client or server instance. /// The notification method name. /// The to monitor for cancellation requests. The default is . /// A task that represents the asynchronous send operation. /// /// /// This method sends a notification without any parameters. Notifications are one-way messages /// that don't expect a response. They are commonly used for events, status updates, or to signal /// changes in state. /// /// public static Task SendNotificationAsync(this IMcpEndpoint client, string method, CancellationToken cancellationToken = default) { Throw.IfNull(client); Throw.IfNullOrWhiteSpace(method); return client.SendMessageAsync(new JsonRpcNotification { Method = method }, cancellationToken); } /// /// Sends a notification with parameters to the connected endpoint. /// /// The type of the notification parameters to serialize. /// The MCP client or server instance. /// The JSON-RPC method name for the notification. /// Object representing the notification parameters. /// The options governing parameter serialization. If null, default options are used. /// The to monitor for cancellation requests. The default is . /// A task that represents the asynchronous send operation. /// /// /// This method sends a notification with parameters to the connected endpoint. Notifications are one-way /// messages that don't expect a response, commonly used for events, status updates, or signaling changes. /// /// /// The parameters object is serialized to JSON according to the provided serializer options or the default /// options if none are specified. /// /// /// The Model Context Protocol defines several standard notification methods in , /// but custom methods can also be used for application-specific notifications. /// /// public static Task SendNotificationAsync( this IMcpEndpoint endpoint, string method, TParameters parameters, JsonSerializerOptions? serializerOptions = null, CancellationToken cancellationToken = default) { serializerOptions ??= McpJsonUtilities.DefaultOptions; serializerOptions.MakeReadOnly(); JsonTypeInfo parametersTypeInfo = serializerOptions.GetTypeInfo(); return SendNotificationAsync(endpoint, method, parameters, parametersTypeInfo, cancellationToken); } /// /// Sends a notification to the server with parameters. /// /// The MCP client or server instance. /// The JSON-RPC method name to invoke. /// Object representing the request parameters. /// The type information for request parameter serialization. /// The to monitor for cancellation requests. The default is . internal static Task SendNotificationAsync( this IMcpEndpoint endpoint, string method, TParameters parameters, JsonTypeInfo parametersTypeInfo, CancellationToken cancellationToken = default) { Throw.IfNull(endpoint); Throw.IfNullOrWhiteSpace(method); Throw.IfNull(parametersTypeInfo); JsonNode? parametersJson = JsonSerializer.SerializeToNode(parameters, parametersTypeInfo); return endpoint.SendMessageAsync(new JsonRpcNotification { Method = method, Params = parametersJson }, cancellationToken); } /// /// Notifies the connected endpoint of progress for a long-running operation. /// /// The endpoint issuing the notification. /// The identifying the operation for which progress is being reported. /// The progress update to send, containing information such as percentage complete or status message. /// The to monitor for cancellation requests. The default is . /// A task representing the completion of the notification operation (not the operation being tracked). /// is . /// /// /// This method sends a progress notification to the connected endpoint using the Model Context Protocol's /// standardized progress notification format. Progress updates are identified by a /// that allows the recipient to correlate multiple updates with a specific long-running operation. /// /// /// Progress notifications are sent asynchronously and don't block the operation from continuing. /// /// public static Task NotifyProgressAsync( this IMcpEndpoint endpoint, ProgressToken progressToken, ProgressNotificationValue progress, CancellationToken cancellationToken = default) { Throw.IfNull(endpoint); return endpoint.SendNotificationAsync( NotificationMethods.ProgressNotification, new ProgressNotification { ProgressToken = progressToken, Progress = progress, }, McpJsonUtilities.JsonContext.Default.ProgressNotification, cancellationToken); } }