Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/concepts/tasks/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -424,8 +424,8 @@ Task operations may throw <xref:ModelContextProtocol.McpException> 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:
Expand Down
27 changes: 20 additions & 7 deletions src/ModelContextProtocol.Core/McpErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,19 @@ public enum McpErrorCode
InvalidRequest = -32600,

/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// This error is returned when the method name specified in the request cannot be found.
/// <para>
/// 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:
/// </para>
/// <list type="bullet">
/// <item><description>A server returning this error when the client requests a capability it doesn't support
/// (for example, requesting completions when the <c>completions</c> capability was not advertised).</description></item>
/// <item><description>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 <c>roots</c> capability).</description></item>
/// </list>
/// </remarks>
MethodNotFound = -32601,

Expand All @@ -51,15 +60,19 @@ public enum McpErrorCode
/// </summary>
/// <remarks>
/// <para>
/// 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:
/// </para>
/// <list type="bullet">
/// <item><description>Malformed requests that fail to satisfy the request schema (for example, CallToolRequest)</description></item>
/// <item><description>Unknown or unrecognized primitive names (for example, tool, prompt, or resource names)</description></item>
/// <item><description>Missing required protocol-level parameters</description></item>
/// <item><description><b>Tools</b>: Unknown tool name or invalid protocol-level tool arguments.</description></item>
/// <item><description><b>Prompts</b>: Unknown prompt name or missing required protocol-level arguments.</description></item>
/// <item><description><b>Pagination</b>: Invalid or expired cursor values.</description></item>
/// <item><description><b>Logging</b>: Invalid log level.</description></item>
/// <item><description><b>Tasks</b>: Invalid or nonexistent task ID or invalid cursor.</description></item>
/// <item><description><b>Elicitation</b>: Server requests an elicitation mode not declared in client capabilities.</description></item>
/// <item><description><b>Sampling</b>: Missing tool result or tool results mixed with other content.</description></item>
/// </list>
/// <para>
/// 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 <see cref="Protocol.CallToolResult.IsError"/>) rather than as protocol errors, allowing language
/// models to receive error feedback and self-correct.
/// </para>
Expand Down
4 changes: 2 additions & 2 deletions src/ModelContextProtocol.Core/Server/McpServerImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -526,8 +526,8 @@ public async Task SyncTool_WithRequiredTaskSupport_CannotBeCalledDirectly()
arguments: new Dictionary<string, object?> { ["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);
}

Expand Down
Loading