diff --git a/src/ModelContextProtocol.Core/McpErrorCode.cs b/src/ModelContextProtocol.Core/McpErrorCode.cs index f6cf4f516..11d03ebd9 100644 --- a/src/ModelContextProtocol.Core/McpErrorCode.cs +++ b/src/ModelContextProtocol.Core/McpErrorCode.cs @@ -30,12 +30,22 @@ public enum McpErrorCode MethodNotFound = -32601, /// - /// Indicates that one or more parameters provided in the request are invalid. + /// Indicates that the request parameters are invalid at the protocol level. /// /// - /// This error is returned when the parameters do not match the expected method signature or constraints. - /// This includes cases where required parameters are missing or not understood, such as when a name for - /// a tool or prompt is not recognized. + /// + /// This error is returned for protocol-level parameter issues, such as: + /// + /// + /// Malformed requests that fail to satisfy the request schema (e.g., CallToolRequest) + /// Unknown or unrecognized primitive names (e.g., tool, prompt, or resource names) + /// Missing required protocol-level parameters + /// + /// + /// Note: Input validation errors within tool/prompt/resource arguments should be reported as execution errors + /// (e.g., via ) rather than as protocol errors, allowing language + /// models to receive error feedback and self-correct. + /// /// InvalidParams = -32602, diff --git a/src/ModelContextProtocol.Core/McpProtocolException.cs b/src/ModelContextProtocol.Core/McpProtocolException.cs index d6bc7b632..c6e6ba0f3 100644 --- a/src/ModelContextProtocol.Core/McpProtocolException.cs +++ b/src/ModelContextProtocol.Core/McpProtocolException.cs @@ -1,14 +1,25 @@ namespace ModelContextProtocol; /// -/// Represents an exception that is thrown when an Model Context Protocol (MCP) error occurs. +/// Represents an exception that is thrown when a Model Context Protocol (MCP) protocol-level error occurs. /// /// -/// This exception is used to represent failures to do with protocol-level concerns, such as invalid JSON-RPC requests, -/// invalid parameters, or internal errors. It is not intended to be used for application-level errors. +/// +/// This exception is used to represent failures related to protocol-level concerns, such as malformed +/// JSON-RPC requests, unknown methods, unknown primitive names (tools/prompts/resources), or internal +/// server errors. It is not intended to be used for tool execution errors, including input validation failures. +/// +/// +/// Tool execution errors (including input validation errors, API failures, and business logic errors) +/// should be returned in the result object with IsError set to , allowing +/// language models to see error details and self-correct. Only protocol-level issues should throw +/// . +/// +/// /// or from a may be /// propagated to the remote endpoint; sensitive information should not be included. If sensitive details need /// to be included, a different exception type should be used. +/// /// public sealed class McpProtocolException : McpException { @@ -65,7 +76,7 @@ public McpProtocolException(string message, Exception? innerException, McpErrorC /// -32700: Parse error - Invalid JSON received /// -32600: Invalid request - The JSON is not a valid Request object /// -32601: Method not found - The method does not exist or is not available - /// -32602: Invalid params - Invalid method parameters + /// -32602: Invalid params - Malformed request or unknown primitive name (tool/prompt/resource) /// -32603: Internal error - Internal JSON-RPC error /// /// diff --git a/src/ModelContextProtocol.Core/Protocol/CallToolResult.cs b/src/ModelContextProtocol.Core/Protocol/CallToolResult.cs index 5d4750aa2..39ec265bb 100644 --- a/src/ModelContextProtocol.Core/Protocol/CallToolResult.cs +++ b/src/ModelContextProtocol.Core/Protocol/CallToolResult.cs @@ -8,13 +8,14 @@ namespace ModelContextProtocol.Protocol; /// /// /// -/// Any errors that originate from the tool should be reported inside the result -/// object, with set to true, rather than as a . +/// Tool execution errors (including input validation errors, API failures, and business logic errors) +/// should be reported inside the result object with set to , +/// rather than as a . This allows language models to see error details +/// and potentially self-correct in subsequent requests. /// /// -/// However, any errors in finding the tool, an error indicating that the -/// server does not support tool calls, or any other exceptional conditions, -/// should be reported as an MCP error response. +/// Protocol-level errors (such as unknown tool names, malformed requests that fail schema validation, +/// or server errors) should be reported as MCP protocol error responses using . /// /// /// See the schema for details. @@ -38,10 +39,18 @@ public sealed class CallToolResult : Result /// Gets or sets an indication of whether the tool call was unsuccessful. /// /// + /// /// When set to , it signifies that the tool execution failed. - /// Tool errors are reported with this property set to and details in the - /// property, rather than as protocol-level errors. This allows LLMs to see that an error occurred - /// and potentially self-correct in subsequent requests. + /// Tool execution errors (including input validation errors, API failures, and business logic errors) + /// are reported with this property set to and details in the + /// property, rather than as protocol-level errors. + /// + /// + /// This allows language models to receive detailed error feedback and potentially self-correct + /// in subsequent requests. For example, if a date parameter is in the wrong format or out of range, + /// the error message in can explain the issue, enabling the model to retry + /// with corrected parameters. + /// /// [JsonPropertyName("isError")] public bool? IsError { get; set; } diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs index fe1283ef9..810bcef48 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs @@ -591,6 +591,41 @@ await Can_Handle_Requests( }); } + [Fact] + public async Task Can_Handle_Call_Tool_Requests_With_InputValidationException() + { + // Test that input validation errors (like ArgumentException from JSON deserialization) + // are returned as tool execution errors (IsError=true) rather than protocol errors, per SEP-1303. + const string errorMessage = "Input validation failed: invalid date format"; + + await Can_Handle_Requests( + new ServerCapabilities + { + Tools = new() + }, + method: RequestMethods.ToolsCall, + configureOptions: options => + { + options.Handlers.CallToolHandler = async (request, ct) => + { + // Simulate an input validation error (like what would happen with wrong argument types) + throw new ArgumentException(errorMessage); + }; + options.Handlers.ListToolsHandler = (request, ct) => throw new NotImplementedException(); + }, + assertResult: (_, response) => + { + var result = JsonSerializer.Deserialize(response, McpJsonUtilities.DefaultOptions); + Assert.NotNull(result); + Assert.True(result.IsError, "Input validation errors should be returned as tool execution errors (IsError=true), not protocol errors"); + Assert.NotEmpty(result.Content); + var textContent = Assert.IsType(result.Content[0]); + // ArgumentException should result in a generic error message that doesn't expose the exception details + Assert.DoesNotContain(errorMessage, textContent.Text); + Assert.Contains("An error occurred", textContent.Text); + }); + } + [Fact] public async Task Can_Handle_Call_Tool_Requests_With_McpProtocolException() {