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()
{