Align error handling documentation with SEP-1303 (#967)
* Initial plan * Update documentation to clarify error handling per SEP-1303 - Updated McpErrorCode.InvalidParams documentation to clarify it's for protocol-level errors (malformed requests, unknown primitives) - Updated CallToolResult documentation to distinguish between tool execution errors and protocol errors - Updated McpProtocolException documentation to emphasize it's only for protocol-level errors - Added test to verify input validation errors are returned as tool execution errors (IsError=true) - Implementation already correctly handles input validation as tool execution errors per SEP-1303 Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
This commit is contained in:
parent
54576033eb
commit
4b241e7ddc
4 changed files with 81 additions and 16 deletions
|
|
@ -30,12 +30,22 @@ public enum McpErrorCode
|
|||
MethodNotFound = -32601,
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that one or more parameters provided in the request are invalid.
|
||||
/// Indicates that the request parameters are invalid at the protocol level.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// <para>
|
||||
/// This error is returned for protocol-level parameter issues, such as:
|
||||
/// </para>
|
||||
/// <list type="bullet">
|
||||
/// <item><description>Malformed requests that fail to satisfy the request schema (e.g., CallToolRequest)</description></item>
|
||||
/// <item><description>Unknown or unrecognized primitive names (e.g., tool, prompt, or resource names)</description></item>
|
||||
/// <item><description>Missing required protocol-level parameters</description></item>
|
||||
/// </list>
|
||||
/// <para>
|
||||
/// Note: Input validation errors within tool/prompt/resource arguments should be reported as execution errors
|
||||
/// (e.g., via <see cref="Protocol.CallToolResult.IsError"/>) rather than as protocol errors, allowing language
|
||||
/// models to receive error feedback and self-correct.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
InvalidParams = -32602,
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,25 @@
|
|||
namespace ModelContextProtocol;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// <para>
|
||||
/// 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.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Tool execution errors (including input validation errors, API failures, and business logic errors)
|
||||
/// should be returned in the result object with <c>IsError</c> set to <see langword="true"/>, allowing
|
||||
/// language models to see error details and self-correct. Only protocol-level issues should throw
|
||||
/// <see cref="McpProtocolException"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <see cref="Exception.Message"/> or <see cref="ErrorCode"/> from a <see cref="McpProtocolException"/> 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.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public sealed class McpProtocolException : McpException
|
||||
{
|
||||
|
|
@ -65,7 +76,7 @@ public sealed class McpProtocolException : McpException
|
|||
/// <item><description>-32700: Parse error - Invalid JSON received</description></item>
|
||||
/// <item><description>-32600: Invalid request - The JSON is not a valid Request object</description></item>
|
||||
/// <item><description>-32601: Method not found - The method does not exist or is not available</description></item>
|
||||
/// <item><description>-32602: Invalid params - Invalid method parameters</description></item>
|
||||
/// <item><description>-32602: Invalid params - Malformed request or unknown primitive name (tool/prompt/resource)</description></item>
|
||||
/// <item><description>-32603: Internal error - Internal JSON-RPC error</description></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
|
|
|
|||
|
|
@ -8,13 +8,14 @@ namespace ModelContextProtocol.Protocol;
|
|||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Any errors that originate from the tool should be reported inside the result
|
||||
/// object, with <see cref="IsError"/> set to true, rather than as a <see cref="JsonRpcError"/>.
|
||||
/// Tool execution errors (including input validation errors, API failures, and business logic errors)
|
||||
/// should be reported inside the result object with <see cref="IsError"/> set to <see langword="true"/>,
|
||||
/// rather than as a <see cref="JsonRpcError"/>. This allows language models to see error details
|
||||
/// and potentially self-correct in subsequent requests.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// 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 cref="McpErrorCode"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// See the <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/">schema</see> for details.
|
||||
|
|
@ -38,10 +39,18 @@ public sealed class CallToolResult : Result
|
|||
/// Gets or sets an indication of whether the tool call was unsuccessful.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// When set to <see langword="true"/>, it signifies that the tool execution failed.
|
||||
/// Tool errors are reported with this property set to <see langword="true"/> and details in the <see cref="Content"/>
|
||||
/// 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 <see langword="true"/> and details in the <see cref="Content"/>
|
||||
/// property, rather than as protocol-level errors.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// 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 <see cref="Content"/> can explain the issue, enabling the model to retry
|
||||
/// with corrected parameters.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[JsonPropertyName("isError")]
|
||||
public bool? IsError { get; set; }
|
||||
|
|
|
|||
|
|
@ -591,6 +591,41 @@ public class McpServerTests : LoggedTest
|
|||
});
|
||||
}
|
||||
|
||||
[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<CallToolResult>(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<TextContentBlock>(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()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue