diff --git a/src/ModelContextProtocol/Client/IMcpClient.cs b/src/ModelContextProtocol/Client/IMcpClient.cs
index 357ce384..7e85b9d9 100644
--- a/src/ModelContextProtocol/Client/IMcpClient.cs
+++ b/src/ModelContextProtocol/Client/IMcpClient.cs
@@ -8,19 +8,21 @@ namespace ModelContextProtocol.Client;
public interface IMcpClient : IMcpEndpoint
{
///
- /// Gets the capabilities supported by the server.
+ /// Gets the capabilities supported by the connected server.
///
- ServerCapabilities? ServerCapabilities { get; }
+ ServerCapabilities ServerCapabilities { get; }
///
- /// Gets the version and implementation information of the server.
+ /// Gets the implementation information of the connected server.
///
- Implementation? ServerInfo { get; }
+ Implementation ServerInfo { get; }
///
- /// Instructions describing how to use the server and its features.
- /// This can be used by clients to improve the LLM's understanding of available tools, resources, etc.
- /// It can be thought of like a "hint" to the model. For example, this information MAY be added to the system prompt.
+ /// Gets any instructions describing how to use the connected server and its features.
///
+ ///
+ /// 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.
+ ///
string? ServerInstructions { get; }
}
\ No newline at end of file
diff --git a/src/ModelContextProtocol/Client/McpClient.cs b/src/ModelContextProtocol/Client/McpClient.cs
index cf27a6b5..a38edf6d 100644
--- a/src/ModelContextProtocol/Client/McpClient.cs
+++ b/src/ModelContextProtocol/Client/McpClient.cs
@@ -18,6 +18,10 @@ internal sealed class McpClient : McpEndpoint, IMcpClient
private ITransport? _sessionTransport;
private CancellationTokenSource? _connectCts;
+ private ServerCapabilities? _serverCapabilities;
+ private Implementation? _serverInfo;
+ private string? _serverInstructions;
+
///
/// Initializes a new instance of the class.
///
@@ -66,13 +70,13 @@ public McpClient(IClientTransport clientTransport, McpClientOptions options, Mcp
}
///
- public ServerCapabilities? ServerCapabilities { get; private set; }
+ public ServerCapabilities ServerCapabilities => _serverCapabilities ?? throw new InvalidOperationException("The client is not connected.");
///
- public Implementation? ServerInfo { get; private set; }
+ public Implementation ServerInfo => _serverInfo ?? throw new InvalidOperationException("The client is not connected.");
///
- public string? ServerInstructions { get; private set; }
+ public string? ServerInstructions => _serverInstructions;
///
public override string EndpointName { get; }
@@ -112,15 +116,15 @@ public async Task ConnectAsync(CancellationToken cancellationToken = default)
capabilities: JsonSerializer.Serialize(initializeResponse.Capabilities, McpJsonUtilities.JsonContext.Default.ServerCapabilities),
serverInfo: JsonSerializer.Serialize(initializeResponse.ServerInfo, McpJsonUtilities.JsonContext.Default.Implementation));
- ServerCapabilities = initializeResponse.Capabilities;
- ServerInfo = initializeResponse.ServerInfo;
- ServerInstructions = initializeResponse.Instructions;
+ _serverCapabilities = initializeResponse.Capabilities;
+ _serverInfo = initializeResponse.ServerInfo;
+ _serverInstructions = initializeResponse.Instructions;
// Validate protocol version
if (initializeResponse.ProtocolVersion != _options.ProtocolVersion)
{
_logger.ServerProtocolVersionMismatch(EndpointName, _options.ProtocolVersion, initializeResponse.ProtocolVersion);
- throw new McpClientException($"Server protocol version mismatch. Expected {_options.ProtocolVersion}, got {initializeResponse.ProtocolVersion}");
+ throw new McpException($"Server protocol version mismatch. Expected {_options.ProtocolVersion}, got {initializeResponse.ProtocolVersion}");
}
// Send initialized notification
@@ -128,10 +132,10 @@ await SendMessageAsync(
new JsonRpcNotification { Method = NotificationMethods.InitializedNotification },
initializationCts.Token).ConfigureAwait(false);
}
- catch (OperationCanceledException) when (initializationCts.IsCancellationRequested)
+ catch (OperationCanceledException oce) when (initializationCts.IsCancellationRequested)
{
_logger.ClientInitializationTimeout(EndpointName);
- throw new McpClientException("Initialization timed out");
+ throw new McpException("Initialization timed out", oce);
}
}
catch (Exception e)
diff --git a/src/ModelContextProtocol/Client/McpClientException.cs b/src/ModelContextProtocol/Client/McpClientException.cs
deleted file mode 100644
index 8f19862c..00000000
--- a/src/ModelContextProtocol/Client/McpClientException.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-namespace ModelContextProtocol.Client;
-
-///
-/// Represents errors that occur in the MCP client.
-///
-public class McpClientException : Exception
-{
- ///
- /// Gets the error code if this exception was caused by a JSON-RPC error response.
- ///
- public int? ErrorCode { get; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- public McpClientException()
- {
- }
-
- ///
- /// Initializes a new instance of the class with a specified error message.
- ///
- /// The message that describes the error.
- public McpClientException(string message) : base(message)
- {
- }
-
- ///
- /// Initializes a new instance of the class with a specified error message and error code.
- ///
- /// The message that describes the error.
- /// The error code associated with the JSON-RPC error response.
- public McpClientException(string message, int errorCode) : base(message)
- {
- ErrorCode = errorCode;
- }
-
- ///
- /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
- ///
- /// The message that describes the error.
- /// The exception that is the cause of the current exception, or a null reference if no inner exception is specified.
- public McpClientException(string message, Exception innerException) : base(message, innerException)
- {
- }
-}
\ No newline at end of file
diff --git a/src/ModelContextProtocol/Client/McpClientExtensions.cs b/src/ModelContextProtocol/Client/McpClientExtensions.cs
index c98f7619..37ffb135 100644
--- a/src/ModelContextProtocol/Client/McpClientExtensions.cs
+++ b/src/ModelContextProtocol/Client/McpClientExtensions.cs
@@ -15,7 +15,7 @@ public static class McpClientExtensions
/// Sends a ping request to verify server connectivity.
///
/// The client.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A task that completes when the ping is successful.
public static Task PingAsync(this IMcpClient client, CancellationToken cancellationToken = default)
{
@@ -34,7 +34,7 @@ public static Task PingAsync(this IMcpClient client, CancellationToken cancellat
///
/// The client.
/// The serializer options governing tool parameter serialization.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A list of all available tools.
public static async Task> ListToolsAsync(
this IMcpClient client,
@@ -75,7 +75,7 @@ public static async Task> ListToolsAsync(
///
/// The client.
/// The serializer options governing tool parameter serialization.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// An asynchronous sequence of all available tools.
///
/// Every iteration through the returned
@@ -115,7 +115,7 @@ public static async IAsyncEnumerable EnumerateToolsAsync(
/// Retrieves a list of available prompts from the server.
///
/// The client.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A list of all available prompts.
public static async Task> ListPromptsAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
@@ -150,7 +150,7 @@ public static async Task> ListPromptsAsync(
/// Creates an enumerable for asynchronously enumerating all available prompts from the server.
///
/// The client.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// An asynchronous sequence of all available prompts.
///
/// Every iteration through the returned
@@ -188,7 +188,7 @@ public static async IAsyncEnumerable EnumeratePromptsAsync(
/// The name of the prompt to retrieve
/// Optional arguments for the prompt
/// The serialization options governing argument serialization.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A task containing the prompt's content and messages.
public static Task GetPromptAsync(
this IMcpClient client,
@@ -216,7 +216,7 @@ public static Task GetPromptAsync(
/// Retrieves a list of available resource templates from the server.
///
/// The client.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A list of all available resource templates.
public static async Task> ListResourceTemplatesAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
@@ -255,7 +255,7 @@ public static async Task> ListResourceTemplatesAsync(
/// Creates an enumerable for asynchronously enumerating all available resource templates from the server.
///
/// The client.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// An asynchronous sequence of all available resource templates.
///
/// Every iteration through the returned
@@ -290,7 +290,7 @@ public static async IAsyncEnumerable EnumerateResourceTemplate
/// Retrieves a list of available resources from the server.
///
/// The client.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A list of all available resources.
public static async Task> ListResourcesAsync(
this IMcpClient client, CancellationToken cancellationToken = default)
@@ -329,7 +329,7 @@ public static async Task> ListResourcesAsync(
/// Creates an enumerable for asynchronously enumerating all available resources from the server.
///
/// The client.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// An asynchronous sequence of all available resources.
///
/// Every iteration through the returned
@@ -365,7 +365,7 @@ public static async IAsyncEnumerable EnumerateResourcesAsync(
///
/// The client.
/// The uri of the resource.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
public static Task ReadResourceAsync(
this IMcpClient client, string uri, CancellationToken cancellationToken = default)
{
@@ -387,7 +387,7 @@ public static Task ReadResourceAsync(
/// A resource (uri) or prompt (name) reference
/// Name of argument. Must be non-null and non-empty.
/// Value of argument. Must be non-null.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
public static Task GetCompletionAsync(this IMcpClient client, Reference reference, string argumentName, string argumentValue, CancellationToken cancellationToken = default)
{
Throw.IfNull(client);
@@ -416,7 +416,7 @@ public static Task GetCompletionAsync(this IMcpClient client, Re
///
/// The client.
/// The uri of the resource.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
public static Task SubscribeToResourceAsync(this IMcpClient client, string uri, CancellationToken cancellationToken = default)
{
Throw.IfNull(client);
@@ -435,7 +435,7 @@ public static Task SubscribeToResourceAsync(this IMcpClient client, string uri,
///
/// The client.
/// The uri of the resource.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
public static Task UnsubscribeFromResourceAsync(this IMcpClient client, string uri, CancellationToken cancellationToken = default)
{
Throw.IfNull(client);
@@ -456,7 +456,7 @@ public static Task UnsubscribeFromResourceAsync(this IMcpClient client, string u
/// The name of the tool to call.
/// Optional arguments for the tool.
/// The serialization options governing argument serialization.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A task containing the tool's response.
public static Task CallToolAsync(
this IMcpClient client,
@@ -622,7 +622,7 @@ internal static CreateMessageResult ToCreateMessageResult(this ChatResponse chat
///
/// The client.
/// The minimum log level of messages to be generated.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
public static Task SetLoggingLevel(this IMcpClient client, LoggingLevel level, CancellationToken cancellationToken = default)
{
Throw.IfNull(client);
diff --git a/src/ModelContextProtocol/Client/McpClientFactory.cs b/src/ModelContextProtocol/Client/McpClientFactory.cs
index 97c2371f..c1bb3770 100644
--- a/src/ModelContextProtocol/Client/McpClientFactory.cs
+++ b/src/ModelContextProtocol/Client/McpClientFactory.cs
@@ -37,7 +37,7 @@ private static McpClientOptions CreateDefaultClientOptions()
///
/// An optional factory method which returns transport implementations based on a server configuration.
/// A logger factory for creating loggers for clients.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// An that's connected to the specified server.
/// is .
/// is .
diff --git a/src/ModelContextProtocol/Client/McpClientPrompt.cs b/src/ModelContextProtocol/Client/McpClientPrompt.cs
index 71d6a4e6..4d4329db 100644
--- a/src/ModelContextProtocol/Client/McpClientPrompt.cs
+++ b/src/ModelContextProtocol/Client/McpClientPrompt.cs
@@ -22,7 +22,7 @@ internal McpClientPrompt(IMcpClient client, Prompt prompt)
///
/// Optional arguments for the prompt
/// The serialization options governing argument serialization.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A task containing the prompt's content and messages.
public async ValueTask GetAsync(
IEnumerable>? arguments = null,
diff --git a/src/ModelContextProtocol/IMcpEndpoint.cs b/src/ModelContextProtocol/IMcpEndpoint.cs
index 6643e02a..a053ad64 100644
--- a/src/ModelContextProtocol/IMcpEndpoint.cs
+++ b/src/ModelContextProtocol/IMcpEndpoint.cs
@@ -7,13 +7,13 @@ public interface IMcpEndpoint : IAsyncDisposable
{
/// Sends a JSON-RPC request to the connected endpoint.
/// The JSON-RPC request to send.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A task containing the client's response.
Task SendRequestAsync(JsonRpcRequest request, CancellationToken cancellationToken = default);
/// Sends a message to the connected endpoint.
/// The message.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
Task SendMessageAsync(IJsonRpcMessage message, CancellationToken cancellationToken = default);
///
diff --git a/src/ModelContextProtocol/McpEndpointExtensions.cs b/src/ModelContextProtocol/McpEndpointExtensions.cs
index d2a6a952..b099019e 100644
--- a/src/ModelContextProtocol/McpEndpointExtensions.cs
+++ b/src/ModelContextProtocol/McpEndpointExtensions.cs
@@ -20,7 +20,7 @@ public static class McpEndpointExtensions
/// Object representing the request parameters.
/// The request id for the request.
/// The options governing request serialization.
- /// A token to cancel the operation.
+ /// 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 Task SendRequestAsync(
this IMcpEndpoint endpoint,
@@ -50,7 +50,7 @@ public static Task SendRequestAsync(
/// The type information for request parameter serialization.
/// The type information for request parameter deserialization.
/// The request id for the request.
- /// A token to cancel the operation.
+ /// 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 Task SendRequestAsync(
this IMcpEndpoint endpoint,
@@ -87,7 +87,7 @@ internal static async Task SendRequestAsync(
///
/// The client.
/// The notification method name.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
public static Task SendNotificationAsync(this IMcpEndpoint client, string method, CancellationToken cancellationToken = default)
{
Throw.IfNull(client);
@@ -102,7 +102,7 @@ public static Task SendNotificationAsync(this IMcpEndpoint client, string method
/// The JSON-RPC method name to invoke.
/// Object representing the request parameters.
/// The options governing request serialization.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
public static Task SendNotificationAsync(
this IMcpEndpoint endpoint,
string method,
@@ -124,7 +124,7 @@ public static Task SendNotificationAsync(
/// The JSON-RPC method name to invoke.
/// Object representing the request parameters.
/// The type information for request parameter serialization.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
internal static Task SendNotificationAsync(
this IMcpEndpoint endpoint,
string method,
@@ -144,7 +144,7 @@ internal static Task SendNotificationAsync(
/// The endpoint issuing the notification.
/// The identifying the operation.
/// The progress update to send.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A task representing the completion of the operation.
/// is .
public static Task NotifyProgressAsync(
diff --git a/src/ModelContextProtocol/McpException.cs b/src/ModelContextProtocol/McpException.cs
new file mode 100644
index 00000000..3fea1128
--- /dev/null
+++ b/src/ModelContextProtocol/McpException.cs
@@ -0,0 +1,56 @@
+namespace ModelContextProtocol;
+
+///
+/// An exception that is thrown when an MCP configuration or protocol error occurs.
+///
+public class McpException : Exception
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public McpException()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error message.
+ ///
+ /// The message that describes the error.
+ public McpException(string message) : base(message)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The message that describes the error.
+ /// The exception that is the cause of the current exception, or a null reference if no inner exception is specified.
+ public McpException(string message, Exception? innerException) : base(message, innerException)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The message that describes the error.
+ /// A JSON-RPC error code, if this exception represents a JSON-RPC error.
+ public McpException(string message, int? errorCode) : this(message, null, errorCode)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
+ ///
+ /// The message that describes the error.
+ /// The exception that is the cause of the current exception, or a null reference if no inner exception is specified.
+ /// A JSON-RPC error code, if this exception represents a JSON-RPC error.
+ public McpException(string message, Exception? innerException, int? errorCode) : base(message, innerException)
+ {
+ ErrorCode = errorCode;
+ }
+
+ ///
+ /// Gets the error code if this exception was caused by a JSON-RPC error response.
+ ///
+ public int? ErrorCode { get; }
+}
\ No newline at end of file
diff --git a/src/ModelContextProtocol/Protocol/Transport/IClientTransport.cs b/src/ModelContextProtocol/Protocol/Transport/IClientTransport.cs
index c68f6cef..48ec1dbb 100644
--- a/src/ModelContextProtocol/Protocol/Transport/IClientTransport.cs
+++ b/src/ModelContextProtocol/Protocol/Transport/IClientTransport.cs
@@ -8,7 +8,7 @@ public interface IClientTransport
///
/// Asynchronously establishes a transport session with an MCP server and returns an interface for the duplex JSON-RPC message stream.
///
- /// Token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// Returns an interface for the duplex JSON-RPC message stream.
Task ConnectAsync(CancellationToken cancellationToken = default);
}
diff --git a/src/ModelContextProtocol/Protocol/Transport/ITransport.cs b/src/ModelContextProtocol/Protocol/Transport/ITransport.cs
index cb4fcc36..76174212 100644
--- a/src/ModelContextProtocol/Protocol/Transport/ITransport.cs
+++ b/src/ModelContextProtocol/Protocol/Transport/ITransport.cs
@@ -22,6 +22,6 @@ public interface ITransport : IAsyncDisposable
/// Sends a message through the transport.
///
/// The message to send.
- /// Token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
Task SendMessageAsync(IJsonRpcMessage message, CancellationToken cancellationToken = default);
}
diff --git a/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs b/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs
index d4e39c8a..de1cb711 100644
--- a/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs
+++ b/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs
@@ -28,7 +28,7 @@ public sealed class SseResponseStreamTransport(Stream sseResponseStream, string
/// Starts the transport and writes the JSON-RPC messages sent via
/// to the SSE response stream until cancelled or disposed.
///
- /// A token to cancel writing to the SSE response stream.
+ /// The to monitor for cancellation requests. The default is .
/// A task representing the send loop that writes JSON-RPC messages to the SSE response stream.
public Task RunAsync(CancellationToken cancellationToken)
{
@@ -84,7 +84,7 @@ public async Task SendMessageAsync(IJsonRpcMessage message, CancellationToken ca
/// Handles incoming JSON-RPC messages received on the /message endpoint.
///
/// The JSON-RPC message received.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A task representing the potentially asynchronous operation to buffer or process the JSON-RPC message.
/// Thrown when there is an attempt to process a message before calling .
public async Task OnMessageReceivedAsync(IJsonRpcMessage message, CancellationToken cancellationToken)
diff --git a/src/ModelContextProtocol/Protocol/Transport/TransportBase.cs b/src/ModelContextProtocol/Protocol/Transport/TransportBase.cs
index 35576168..75a9a9b5 100644
--- a/src/ModelContextProtocol/Protocol/Transport/TransportBase.cs
+++ b/src/ModelContextProtocol/Protocol/Transport/TransportBase.cs
@@ -45,7 +45,7 @@ protected TransportBase(ILoggerFactory? loggerFactory)
/// Writes a message to the message channel.
///
/// The message to write.
- /// Token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
protected async Task WriteMessageAsync(IJsonRpcMessage message, CancellationToken cancellationToken = default)
{
if (!_isConnected)
diff --git a/src/ModelContextProtocol/Server/McpServer.cs b/src/ModelContextProtocol/Server/McpServer.cs
index 499f2efa..764736e2 100644
--- a/src/ModelContextProtocol/Server/McpServer.cs
+++ b/src/ModelContextProtocol/Server/McpServer.cs
@@ -25,7 +25,7 @@ internal sealed class McpServer : McpEndpoint, IMcpServer
/// Make sure to accurately reflect exactly what capabilities the server supports and does not support.
/// Logger factory to use for logging
/// Optional service provider to use for dependency injection
- ///
+ /// The server was incorrectly configured.
public McpServer(ITransport transport, McpServerOptions options, ILoggerFactory? loggerFactory, IServiceProvider? serviceProvider)
: base(loggerFactory)
{
@@ -185,7 +185,7 @@ private void SetResourcesHandler(McpServerOptions options)
if ((listResourcesHandler is not { } && listResourceTemplatesHandler is not { }) ||
resourcesCapability.ReadResourceHandler is not { } readResourceHandler)
{
- throw new McpServerException("Resources capability was enabled, but ListResources and/or ReadResource handlers were not specified.");
+ throw new McpException("Resources capability was enabled, but ListResources and/or ReadResource handlers were not specified.");
}
listResourcesHandler ??= (static (_, _) => Task.FromResult(new ListResourcesResult()));
@@ -218,7 +218,7 @@ private void SetResourcesHandler(McpServerOptions options)
var unsubscribeHandler = resourcesCapability.UnsubscribeFromResourcesHandler;
if (subscribeHandler is null || unsubscribeHandler is null)
{
- throw new McpServerException("Resources capability was enabled with subscribe support, but SubscribeToResources and/or UnsubscribeFromResources handlers were not specified.");
+ throw new McpException("Resources capability was enabled with subscribe support, but SubscribeToResources and/or UnsubscribeFromResources handlers were not specified.");
}
SetRequestHandler(
@@ -243,7 +243,7 @@ private void SetPromptsHandler(McpServerOptions options)
if (listPromptsHandler is null != getPromptHandler is null)
{
- throw new McpServerException("ListPrompts and GetPrompt handlers should be specified together.");
+ throw new McpException("ListPrompts and GetPrompt handlers should be specified together.");
}
// Handle prompts provided via DI.
@@ -276,7 +276,7 @@ await originalListPromptsHandler(request, cancellationToken).ConfigureAwait(fals
return originalGetPromptHandler(request, cancellationToken);
}
- throw new McpServerException($"Unknown prompt '{request.Params?.Name}'");
+ throw new McpException($"Unknown prompt '{request.Params?.Name}'");
}
return prompt.GetAsync(request, cancellationToken);
@@ -310,7 +310,7 @@ await originalListPromptsHandler(request, cancellationToken).ConfigureAwait(fals
// Make sure the handlers are provided if the capability is enabled.
if (listPromptsHandler is null || getPromptHandler is null)
{
- throw new McpServerException("ListPrompts and/or GetPrompt handlers were not specified but the Prompts capability was enabled.");
+ throw new McpException("ListPrompts and/or GetPrompt handlers were not specified but the Prompts capability was enabled.");
}
}
@@ -336,7 +336,7 @@ private void SetToolsHandler(McpServerOptions options)
if (listToolsHandler is null != callToolHandler is null)
{
- throw new McpServerException("ListTools and CallTool handlers should be specified together.");
+ throw new McpException("ListTools and CallTool handlers should be specified together.");
}
// Handle tools provided via DI.
@@ -369,7 +369,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
return originalCallToolHandler(request, cancellationToken);
}
- throw new McpServerException($"Unknown tool '{request.Params?.Name}'");
+ throw new McpException($"Unknown tool '{request.Params?.Name}'");
}
return tool.InvokeAsync(request, cancellationToken);
@@ -403,7 +403,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false)
// Make sure the handlers are provided if the capability is enabled.
if (listToolsHandler is null || callToolHandler is null)
{
- throw new McpServerException("ListTools and/or CallTool handlers were not specified but the Tools capability was enabled.");
+ throw new McpException("ListTools and/or CallTool handlers were not specified but the Tools capability was enabled.");
}
}
@@ -429,7 +429,7 @@ private void SetSetLoggingLevelHandler(McpServerOptions options)
if (loggingCapability.SetLoggingLevelHandler is not { } setLoggingLevelHandler)
{
- throw new McpServerException("Logging capability was enabled, but SetLoggingLevelHandler was not specified.");
+ throw new McpException("Logging capability was enabled, but SetLoggingLevelHandler was not specified.");
}
SetRequestHandler(
diff --git a/src/ModelContextProtocol/Server/McpServerException.cs b/src/ModelContextProtocol/Server/McpServerException.cs
deleted file mode 100644
index 7d6a6c0a..00000000
--- a/src/ModelContextProtocol/Server/McpServerException.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using ModelContextProtocol.Client;
-
-namespace ModelContextProtocol.Server;
-
-///
-/// Represents errors that occur in the MCP server.
-///
-public class McpServerException : Exception
-{
- ///
- /// Gets the error code if this exception was caused by a JSON-RPC error response.
- ///
- public int? ErrorCode { get; }
-
- ///
- /// Initializes a new instance of the class with a specified error message.
- ///
- public McpServerException()
- {
- }
-
- ///
- /// Initializes a new instance of the class with a specified error message.
- ///
- /// The message that describes the error.
- public McpServerException(string message) : base(message)
- {
- }
-
- ///
- /// Initializes a new instance of the class with a specified error message and error code.
- ///
- /// The message that describes the error.
- /// The error code associated with the JSON-RPC error response.
- public McpServerException(string message, int errorCode) : base(message)
- {
- ErrorCode = errorCode;
- }
-
- ///
- /// Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
- ///
- /// The message that describes the error.
- /// The exception that is the cause of the current exception, or a null reference if no inner exception is specified.
- public McpServerException(string message, Exception innerException) : base(message, innerException)
- {
- }
-}
\ No newline at end of file
diff --git a/src/ModelContextProtocol/Server/McpServerExtensions.cs b/src/ModelContextProtocol/Server/McpServerExtensions.cs
index 9b160d4c..b59992c9 100644
--- a/src/ModelContextProtocol/Server/McpServerExtensions.cs
+++ b/src/ModelContextProtocol/Server/McpServerExtensions.cs
@@ -41,7 +41,7 @@ public static Task RequestSamplingAsync(
/// The server issueing the request.
/// The messages to send as part of the request.
/// The options to use for the request.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A task containing the response from the client.
/// is .
/// is .
diff --git a/src/ModelContextProtocol/Shared/McpSession.cs b/src/ModelContextProtocol/Shared/McpSession.cs
index d5e4f930..dae92686 100644
--- a/src/ModelContextProtocol/Shared/McpSession.cs
+++ b/src/ModelContextProtocol/Shared/McpSession.cs
@@ -1,6 +1,5 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
-using ModelContextProtocol.Client;
using ModelContextProtocol.Logging;
using ModelContextProtocol.Protocol.Messages;
using ModelContextProtocol.Protocol.Transport;
@@ -147,7 +146,7 @@ await _transport.SendMessageAsync(new JsonRpcError
JsonRpc = "2.0",
Error = new JsonRpcErrorDetail
{
- Code = (ex as McpServerException)?.ErrorCode ?? ErrorCodes.InternalError,
+ Code = (ex as McpException)?.ErrorCode ?? ErrorCodes.InternalError,
Message = ex.Message
}
}, cancellationToken).ConfigureAwait(false);
@@ -298,7 +297,7 @@ private async Task HandleRequest(JsonRpcRequest request, CancellationToken cance
if (!_requestHandlers.TryGetValue(request.Method, out var handler))
{
_logger.NoHandlerFoundForRequest(EndpointName, request.Method);
- throw new McpServerException("The method does not exist or is not available.", ErrorCodes.MethodNotFound);
+ throw new McpException("The method does not exist or is not available.", ErrorCodes.MethodNotFound);
}
_logger.RequestHandlerCalled(EndpointName, request.Method);
@@ -318,14 +317,14 @@ await _transport.SendMessageAsync(new JsonRpcResponse
/// Use this method for custom requests or those not yet covered explicitly by the endpoint implementation.
///
/// The JSON-RPC request to send.
- /// A token to cancel the operation.
+ /// The to monitor for cancellation requests. The default is .
/// A task containing the server's response.
public async Task SendRequestAsync(JsonRpcRequest request, CancellationToken cancellationToken)
{
if (!_transport.IsConnected)
{
_logger.EndpointNotConnected(EndpointName);
- throw new McpClientException("Transport is not connected");
+ throw new McpException("Transport is not connected");
}
Histogram durationMetric = _isServer ? s_serverRequestDuration : s_clientRequestDuration;
@@ -372,7 +371,7 @@ public async Task SendRequestAsync(JsonRpcRequest request, Canc
if (response is JsonRpcError error)
{
_logger.RequestFailed(EndpointName, request.Method, error.Error.Message, error.Error.Code);
- throw new McpClientException($"Request failed (server side): {error.Error.Message}", error.Error.Code);
+ throw new McpException($"Request failed (server side): {error.Error.Message}", error.Error.Code);
}
if (response is JsonRpcResponse success)
@@ -384,7 +383,7 @@ public async Task SendRequestAsync(JsonRpcRequest request, Canc
// Unexpected response type
_logger.RequestInvalidResponseType(EndpointName, request.Method);
- throw new McpClientException("Invalid response type");
+ throw new McpException("Invalid response type");
}
catch (Exception ex) when (addTags)
{
@@ -405,7 +404,7 @@ public async Task SendMessageAsync(IJsonRpcMessage message, CancellationToken ca
if (!_transport.IsConnected)
{
_logger.ClientNotConnected(EndpointName);
- throw new McpClientException("Transport is not connected");
+ throw new McpException("Transport is not connected");
}
Histogram durationMetric = _isServer ? s_serverRequestDuration : s_clientRequestDuration;
@@ -529,8 +528,7 @@ private static void AddExceptionTags(ref TagList tags, Exception e)
{
tags.Add("error.type", e.GetType().FullName);
tags.Add("rpc.jsonrpc.error_code",
- (e as McpClientException)?.ErrorCode is int clientError ? clientError :
- (e as McpServerException)?.ErrorCode is int serverError ? serverError :
+ (e as McpException)?.ErrorCode is int errorCode ? errorCode :
e is JsonException ? ErrorCodes.ParseError :
ErrorCodes.InternalError);
}
diff --git a/tests/ModelContextProtocol.TestServer/Program.cs b/tests/ModelContextProtocol.TestServer/Program.cs
index 6e5655a3..830a042a 100644
--- a/tests/ModelContextProtocol.TestServer/Program.cs
+++ b/tests/ModelContextProtocol.TestServer/Program.cs
@@ -164,7 +164,7 @@ private static ToolsCapability ConfigureTools()
{
if (request.Params?.Arguments is null || !request.Params.Arguments.TryGetValue("message", out var message))
{
- throw new McpServerException("Missing required argument 'message'");
+ throw new McpException("Missing required argument 'message'");
}
return new CallToolResponse()
{
@@ -177,7 +177,7 @@ private static ToolsCapability ConfigureTools()
!request.Params.Arguments.TryGetValue("prompt", out var prompt) ||
!request.Params.Arguments.TryGetValue("maxTokens", out var maxTokens))
{
- throw new McpServerException("Missing required arguments 'prompt' and 'maxTokens'");
+ throw new McpException("Missing required arguments 'prompt' and 'maxTokens'");
}
var sampleResult = await request.Server.RequestSamplingAsync(CreateRequestSamplingParams(prompt.ToString(), "sampleLLM", Convert.ToInt32(maxTokens.GetRawText())),
cancellationToken);
@@ -189,7 +189,7 @@ private static ToolsCapability ConfigureTools()
}
else
{
- throw new McpServerException($"Unknown tool: {request.Params?.Name}");
+ throw new McpException($"Unknown tool: {request.Params?.Name}");
}
}
};
@@ -283,7 +283,7 @@ private static PromptsCapability ConfigurePrompts()
}
else
{
- throw new McpServerException($"Unknown prompt: {request.Params?.Name}");
+ throw new McpException($"Unknown prompt: {request.Params?.Name}");
}
return Task.FromResult(new GetPromptResult()
@@ -304,7 +304,7 @@ private static LoggingCapability ConfigureLogging()
{
if (request.Params?.Level is null)
{
- throw new McpServerException("Missing required argument 'level'");
+ throw new McpException("Missing required argument 'level'");
}
_minimumLoggingLevel = request.Params.Level;
@@ -384,9 +384,9 @@ private static ResourcesCapability ConfigureResources()
var startIndexAsString = Encoding.UTF8.GetString(Convert.FromBase64String(request.Params.Cursor));
startIndex = Convert.ToInt32(startIndexAsString);
}
- catch
+ catch (Exception e)
{
- throw new McpServerException("Invalid cursor");
+ throw new McpException("Invalid cursor.", e);
}
}
@@ -408,7 +408,7 @@ private static ResourcesCapability ConfigureResources()
{
if (request.Params?.Uri is null)
{
- throw new McpServerException("Missing required argument 'uri'");
+ throw new McpException("Missing required argument 'uri'");
}
if (request.Params.Uri.StartsWith("test://dynamic/resource/"))
@@ -416,7 +416,7 @@ private static ResourcesCapability ConfigureResources()
var id = request.Params.Uri.Split('/').LastOrDefault();
if (string.IsNullOrEmpty(id))
{
- throw new McpServerException("Invalid resource URI");
+ throw new McpException("Invalid resource URI");
}
return Task.FromResult(new ReadResourceResult()
{
@@ -432,7 +432,7 @@ private static ResourcesCapability ConfigureResources()
}
ResourceContents contents = resourceContents.FirstOrDefault(r => r.Uri == request.Params.Uri)
- ?? throw new McpServerException("Resource not found");
+ ?? throw new McpException("Resource not found");
return Task.FromResult(new ReadResourceResult()
{
@@ -444,12 +444,12 @@ private static ResourcesCapability ConfigureResources()
{
if (request?.Params?.Uri is null)
{
- throw new McpServerException("Missing required argument 'uri'");
+ throw new McpException("Missing required argument 'uri'");
}
if (!request.Params.Uri.StartsWith("test://static/resource/")
&& !request.Params.Uri.StartsWith("test://dynamic/resource/"))
{
- throw new McpServerException("Invalid resource URI");
+ throw new McpException("Invalid resource URI");
}
_subscribedResources.TryAdd(request.Params.Uri, true);
@@ -461,12 +461,12 @@ private static ResourcesCapability ConfigureResources()
{
if (request?.Params?.Uri is null)
{
- throw new McpServerException("Missing required argument 'uri'");
+ throw new McpException("Missing required argument 'uri'");
}
if (!request.Params.Uri.StartsWith("test://static/resource/")
&& !request.Params.Uri.StartsWith("test://dynamic/resource/"))
{
- throw new McpServerException("Invalid resource URI");
+ throw new McpException("Invalid resource URI");
}
_subscribedResources.Remove(request.Params.Uri, out _);
@@ -511,7 +511,7 @@ private static Func, CancellationToken, Ta
return Task.FromResult(new CompleteResult() { Completion = new() { Values = values, HasMore = false, Total = values.Length } });
}
- throw new McpServerException($"Unknown reference type: {request.Params?.Ref.Type}");
+ throw new McpException($"Unknown reference type: {request.Params?.Ref.Type}");
};
}
diff --git a/tests/ModelContextProtocol.TestSseServer/Program.cs b/tests/ModelContextProtocol.TestSseServer/Program.cs
index d5a24c99..e4bd996b 100644
--- a/tests/ModelContextProtocol.TestSseServer/Program.cs
+++ b/tests/ModelContextProtocol.TestSseServer/Program.cs
@@ -154,13 +154,13 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st
{
if (request.Params is null)
{
- throw new McpServerException("Missing required parameter 'name'");
+ throw new McpException("Missing required parameter 'name'");
}
if (request.Params.Name == "echo")
{
if (request.Params.Arguments is null || !request.Params.Arguments.TryGetValue("message", out var message))
{
- throw new McpServerException("Missing required argument 'message'");
+ throw new McpException("Missing required argument 'message'");
}
return new CallToolResponse()
{
@@ -173,7 +173,7 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st
!request.Params.Arguments.TryGetValue("prompt", out var prompt) ||
!request.Params.Arguments.TryGetValue("maxTokens", out var maxTokens))
{
- throw new McpServerException("Missing required arguments 'prompt' and 'maxTokens'");
+ throw new McpException("Missing required arguments 'prompt' and 'maxTokens'");
}
var sampleResult = await request.Server.RequestSamplingAsync(CreateRequestSamplingParams(prompt.ToString(), "sampleLLM", Convert.ToInt32(maxTokens.ToString())),
cancellationToken);
@@ -185,7 +185,7 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st
}
else
{
- throw new McpServerException($"Unknown tool: {request.Params.Name}");
+ throw new McpException($"Unknown tool: {request.Params.Name}");
}
}
},
@@ -219,7 +219,7 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st
}
catch
{
- throw new McpServerException("Invalid cursor");
+ throw new McpException("Invalid cursor");
}
}
@@ -240,7 +240,7 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st
{
if (request.Params?.Uri is null)
{
- throw new McpServerException("Missing required argument 'uri'");
+ throw new McpException("Missing required argument 'uri'");
}
if (request.Params.Uri.StartsWith("test://dynamic/resource/"))
@@ -248,7 +248,7 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st
var id = request.Params.Uri.Split('/').LastOrDefault();
if (string.IsNullOrEmpty(id))
{
- throw new McpServerException("Invalid resource URI");
+ throw new McpException("Invalid resource URI");
}
return Task.FromResult(new ReadResourceResult()
{
@@ -264,7 +264,7 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st
}
ResourceContents? contents = resourceContents.FirstOrDefault(r => r.Uri == request.Params.Uri) ??
- throw new McpServerException("Resource not found");
+ throw new McpException("Resource not found");
return Task.FromResult(new ReadResourceResult()
{
@@ -311,7 +311,7 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st
{
if (request.Params is null)
{
- throw new McpServerException("Missing required parameter 'name'");
+ throw new McpException("Missing required parameter 'name'");
}
List messages = new();
if (request.Params.Name == "simple_prompt")
@@ -361,7 +361,7 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st
}
else
{
- throw new McpServerException($"Unknown prompt: {request.Params.Name}");
+ throw new McpException($"Unknown prompt: {request.Params.Name}");
}
return Task.FromResult(new GetPromptResult()
diff --git a/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs b/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs
index a6d0a9b6..705a0779 100644
--- a/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs
+++ b/tests/ModelContextProtocol.Tests/ClientIntegrationTests.cs
@@ -175,7 +175,7 @@ public async Task GetPrompt_NonExistent_ThrowsException(string clientId)
// act
await using var client = await _fixture.CreateClientAsync(clientId);
- await Assert.ThrowsAsync(() =>
+ await Assert.ThrowsAsync(() =>
client.GetPromptAsync("non_existent_prompt", null, cancellationToken: TestContext.Current.CancellationToken));
}
diff --git a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsPromptsTests.cs b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsPromptsTests.cs
index 26d834b9..bbbbb05d 100644
--- a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsPromptsTests.cs
+++ b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsPromptsTests.cs
@@ -217,7 +217,7 @@ public async Task Throws_When_Prompt_Fails()
{
IMcpClient client = await CreateMcpClientForServer();
- await Assert.ThrowsAsync(async () => await client.GetPromptAsync(
+ await Assert.ThrowsAsync(async () => await client.GetPromptAsync(
nameof(SimplePrompts.ThrowsException),
cancellationToken: TestContext.Current.CancellationToken));
}
@@ -227,7 +227,7 @@ public async Task Throws_Exception_On_Unknown_Prompt()
{
IMcpClient client = await CreateMcpClientForServer();
- var e = await Assert.ThrowsAsync(async () => await client.GetPromptAsync(
+ var e = await Assert.ThrowsAsync(async () => await client.GetPromptAsync(
"NotRegisteredPrompt",
cancellationToken: TestContext.Current.CancellationToken));
@@ -239,7 +239,7 @@ public async Task Throws_Exception_Missing_Parameter()
{
IMcpClient client = await CreateMcpClientForServer();
- var e = await Assert.ThrowsAsync(async () => await client.GetPromptAsync(
+ var e = await Assert.ThrowsAsync(async () => await client.GetPromptAsync(
nameof(SimplePrompts.ReturnsChatMessages),
cancellationToken: TestContext.Current.CancellationToken));
diff --git a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs
index 3c8981b6..79ae117f 100644
--- a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs
+++ b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs
@@ -435,7 +435,7 @@ public async Task Throws_Exception_On_Unknown_Tool()
{
IMcpClient client = await CreateMcpClientForServer();
- var e = await Assert.ThrowsAsync(async () => await client.CallToolAsync(
+ var e = await Assert.ThrowsAsync(async () => await client.CallToolAsync(
"NotRegisteredTool",
cancellationToken: TestContext.Current.CancellationToken));
diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs
index ff946333..1c7e6613 100644
--- a/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs
+++ b/tests/ModelContextProtocol.Tests/Server/McpServerResourceTests.cs
@@ -95,6 +95,6 @@ public void CreatingReadHandlerWithNoListHandlerFails()
});
});
var sp = services.BuildServiceProvider();
- Assert.Throws(() => sp.GetRequiredService());
+ Assert.Throws(() => sp.GetRequiredService());
}
}
diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs
index e0a4a6e4..619dcfde 100644
--- a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs
+++ b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs
@@ -95,7 +95,7 @@ public async Task RunAsync_Should_Throw_InvalidOperationException_If_Already_Run
}
[Fact]
- public async Task RequestSamplingAsync_Should_Throw_McpServerException_If_Client_Does_Not_Support_Sampling()
+ public async Task RequestSamplingAsync_Should_Throw_McpException_If_Client_Does_Not_Support_Sampling()
{
// Arrange
await using var transport = new TestServerTransport();
@@ -131,7 +131,7 @@ public async Task RequestSamplingAsync_Should_SendRequest()
}
[Fact]
- public async Task RequestRootsAsync_Should_Throw_McpServerException_If_Client_Does_Not_Support_Roots()
+ public async Task RequestRootsAsync_Should_Throw_McpException_If_Client_Does_Not_Support_Roots()
{
// Arrange
await using var transport = new TestServerTransport();
@@ -523,7 +523,7 @@ private async Task Throws_Exception_If_No_Handler_Assigned(ServerCapabilities se
await using var transport = new TestServerTransport();
var options = CreateOptions(serverCapabilities);
- Assert.Throws(() => McpServerFactory.Create(transport, options, LoggerFactory));
+ Assert.Throws(() => McpServerFactory.Create(transport, options, LoggerFactory));
}
[Fact]
diff --git a/tests/ModelContextProtocol.Tests/SseServerIntegrationTests.cs b/tests/ModelContextProtocol.Tests/SseServerIntegrationTests.cs
index b73a9c06..070bfd1c 100644
--- a/tests/ModelContextProtocol.Tests/SseServerIntegrationTests.cs
+++ b/tests/ModelContextProtocol.Tests/SseServerIntegrationTests.cs
@@ -209,7 +209,7 @@ public async Task GetPrompt_Sse_NonExistent_ThrowsException()
// act
await using var client = await GetClientAsync();
- await Assert.ThrowsAsync(() =>
+ await Assert.ThrowsAsync(() =>
client.GetPromptAsync("non_existent_prompt", null, cancellationToken: TestContext.Current.CancellationToken));
}