diff --git a/docs/concepts/tasks/tasks.md b/docs/concepts/tasks/tasks.md index ee7ee8356..9b67e119b 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 c6610d6b5..33cd74a82 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 04f329437..7dfc0f09c 100644 --- a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs +++ b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs @@ -591,7 +591,7 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false) { 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 @@ await originalListToolsHandler(request, cancellationToken).ConfigureAwait(false) 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 33655f964..b7734d76e 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerTaskAugmentedValidationTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerTaskAugmentedValidationTests.cs @@ -100,7 +100,7 @@ await client.CallToolAsync( 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 @@ await client.CallToolAsync( 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 7367b5316..cc075a676 100644 --- a/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/TaskCancellationIntegrationTests.cs @@ -460,7 +460,7 @@ public async Task CompletedTask_CannotTransitionToOtherStatus() 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 async Task FailedTask_CannotTransitionToOtherStatus() 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 99c6035e6..25db2b330 100644 --- a/tests/ModelContextProtocol.Tests/Server/ToolTaskSupportTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/ToolTaskSupportTests.cs @@ -526,8 +526,8 @@ public async Task SyncTool_WithRequiredTaskSupport_CannotBeCalledDirectly() 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); }