From 186cb93630d4bf4a5c6c8880fc07084610ef06b1 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 17 Feb 2026 13:12:29 -0800 Subject: [PATCH] Update McpErrorCode XML docs and fix error code usage to align with MCP spec (#1291) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- docs/concepts/tasks/tasks.md | 4 +-- src/ModelContextProtocol.Core/McpErrorCode.cs | 27 ++++++++++++++----- .../Server/McpServerImpl.cs | 4 +-- .../McpServerTaskAugmentedValidationTests.cs | 4 +-- .../TaskCancellationIntegrationTests.cs | 4 +-- .../Server/ToolTaskSupportTests.cs | 4 +-- 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/docs/concepts/tasks/tasks.md b/docs/concepts/tasks/tasks.md index ee7ee83..9b67e11 100644 --- a/docs/concepts/tasks/tasks.md +++ b/docs/concepts/tasks/tasks.md @@ -424,8 +424,8 @@ Task operations may throw with these er | Error Code | Scenario | |------------|----------| -| `InvalidParams` | Invalid or nonexistent task ID | -| `InvalidRequest` | Tool with `taskSupport: forbidden` called with task metadata, or tool with `taskSupport: required` called without task metadata | +| `InvalidParams` | Invalid or nonexistent task ID or invalid cursor | +| `InvalidParams` | Tool with `taskSupport: forbidden` called with task metadata, or tool with `taskSupport: required` called without task metadata | | `InternalError` | Task execution failure or result unavailable | Example error handling: diff --git a/src/ModelContextProtocol.Core/McpErrorCode.cs b/src/ModelContextProtocol.Core/McpErrorCode.cs index c6610d6..33cd74a 100644 --- a/src/ModelContextProtocol.Core/McpErrorCode.cs +++ b/src/ModelContextProtocol.Core/McpErrorCode.cs @@ -39,10 +39,19 @@ public enum McpErrorCode InvalidRequest = -32600, /// - /// Indicates that the requested method does not exist or is not available on the server. + /// Indicates that the requested method does not exist or is not available. /// /// - /// This error is returned when the method name specified in the request cannot be found. + /// + /// In MCP, this error is returned when a request is made for a method that requires a capability + /// that has not been declared. This can occur in either direction: + /// + /// + /// A server returning this error when the client requests a capability it doesn't support + /// (for example, requesting completions when the completions capability was not advertised). + /// A client returning this error when the server requests a capability it doesn't support + /// (for example, requesting roots when the client did not declare the roots capability). + /// /// MethodNotFound = -32601, @@ -51,15 +60,19 @@ public enum McpErrorCode /// /// /// - /// This error is returned for protocol-level parameter issues, such as: + /// In MCP, this error is returned for protocol-level parameter validation failures in various contexts: /// /// - /// Malformed requests that fail to satisfy the request schema (for example, CallToolRequest) - /// Unknown or unrecognized primitive names (for example, tool, prompt, or resource names) - /// Missing required protocol-level parameters + /// Tools: Unknown tool name or invalid protocol-level tool arguments. + /// Prompts: Unknown prompt name or missing required protocol-level arguments. + /// Pagination: Invalid or expired cursor values. + /// Logging: Invalid log level. + /// Tasks: Invalid or nonexistent task ID or invalid cursor. + /// Elicitation: Server requests an elicitation mode not declared in client capabilities. + /// Sampling: Missing tool result or tool results mixed with other content. /// /// - /// Note: Input validation errors within tool/prompt/resource arguments should be reported as execution errors + /// Note: Application-layer validation errors within tool/prompt/resource arguments should be reported as execution errors /// (for example, via ) rather than as protocol errors, allowing language /// models to receive error feedback and self-correct. /// diff --git a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs index 04f3294..7dfc0f0 100644 --- a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs +++ b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs @@ -591,7 +591,7 @@ internal sealed partial class McpServerImpl : McpServer { throw new McpProtocolException( $"Tool '{tool.ProtocolTool.Name}' does not support task-augmented execution.", - McpErrorCode.MethodNotFound); + McpErrorCode.InvalidParams); } // Task augmentation requested - return CreateTaskResult @@ -604,7 +604,7 @@ internal sealed partial class McpServerImpl : McpServer throw new McpProtocolException( $"Tool '{tool.ProtocolTool.Name}' requires task-augmented execution. " + "Include a 'task' parameter with the request.", - McpErrorCode.MethodNotFound); + McpErrorCode.InvalidParams); } // Normal synchronous execution diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerTaskAugmentedValidationTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerTaskAugmentedValidationTests.cs index 33655f9..b7734d7 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerTaskAugmentedValidationTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerTaskAugmentedValidationTests.cs @@ -100,7 +100,7 @@ public class McpServerTaskAugmentedValidationTests : LoggedTest TestContext.Current.CancellationToken)); Assert.Contains("does not support task-augmented execution", exception.Message, StringComparison.OrdinalIgnoreCase); - Assert.Equal(McpErrorCode.MethodNotFound, exception.ErrorCode); + Assert.Equal(McpErrorCode.InvalidParams, exception.ErrorCode); } [Fact] @@ -227,7 +227,7 @@ public class McpServerTaskAugmentedValidationTests : LoggedTest TestContext.Current.CancellationToken)); Assert.Contains("requires task-augmented execution", exception.Message, StringComparison.OrdinalIgnoreCase); - Assert.Equal(McpErrorCode.MethodNotFound, exception.ErrorCode); + Assert.Equal(McpErrorCode.InvalidParams, exception.ErrorCode); } [Fact] diff --git a/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs b/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs index 7367b53..cc075a6 100644 --- a/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs @@ -460,7 +460,7 @@ public class TerminalTaskStatusTransitionTests : ClientServerTestBase Assert.Equal(McpTaskStatus.Completed, taskStatus.Status); - // Act - Try to cancel a completed task + // Act - Try to cancel a completed task (should be idempotent) var cancelResult = await client.CancelTaskAsync(taskId, cancellationToken: TestContext.Current.CancellationToken); // Assert - Status should still be completed (not cancelled) @@ -500,7 +500,7 @@ public class TerminalTaskStatusTransitionTests : ClientServerTestBase Assert.Equal(McpTaskStatus.Failed, taskStatus.Status); - // Act - Try to cancel a failed task + // Act - Try to cancel a failed task (should be idempotent) var cancelResult = await client.CancelTaskAsync(taskId, cancellationToken: TestContext.Current.CancellationToken); // Assert - Status should still be failed diff --git a/tests/ModelContextProtocol.Tests/Server/ToolTaskSupportTests.cs b/tests/ModelContextProtocol.Tests/Server/ToolTaskSupportTests.cs index 99c6035..25db2b3 100644 --- a/tests/ModelContextProtocol.Tests/Server/ToolTaskSupportTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/ToolTaskSupportTests.cs @@ -526,8 +526,8 @@ public class ToolTaskSupportTests : LoggedTest arguments: new Dictionary { ["input"] = "test" }, cancellationToken: TestContext.Current.CancellationToken).AsTask()); - // The server returns MethodNotFound because direct invocation is not allowed for required-task tools - Assert.Equal(McpErrorCode.MethodNotFound, exception.ErrorCode); + // The server returns InvalidParams because direct invocation is not allowed for required-task tools + Assert.Equal(McpErrorCode.InvalidParams, exception.ErrorCode); Assert.Contains("task", exception.Message, StringComparison.OrdinalIgnoreCase); }