Skip to content

Commit d76bc16

Browse files
authored
Add ResourceNotFound error code (-32002) (#1062)
1 parent 4808ca0 commit d76bc16

File tree

8 files changed

+36
-26
lines changed

8 files changed

+36
-26
lines changed

src/ModelContextProtocol.Core/McpErrorCode.cs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,29 @@ namespace ModelContextProtocol;
66
public enum McpErrorCode
77
{
88
/// <summary>
9-
/// Indicates that the JSON received could not be parsed.
9+
/// Indicates that the requested resource could not be found.
1010
/// </summary>
1111
/// <remarks>
12-
/// This error occurs when the input contains malformed JSON or incorrect syntax.
12+
/// This error should be used when a resource URI does not match any available resource on the server.
13+
/// It allows clients to distinguish between missing resources and other types of errors.
1314
/// </remarks>
14-
ParseError = -32700,
15+
ResourceNotFound = -32002,
16+
17+
/// <summary>
18+
/// Indicates that URL-mode elicitation is required to complete the requested operation.
19+
/// </summary>
20+
/// <remarks>
21+
/// <para>
22+
/// This error is returned when a server operation requires additional user input through URL-mode elicitation
23+
/// before it can proceed. The error data must include the `data.elicitations` payload describing the pending
24+
/// elicitation(s) for the client to present to the user.
25+
/// </para>
26+
/// <para>
27+
/// Common scenarios include OAuth authorization and other out-of-band flows that cannot be completed inside
28+
/// the MCP client.
29+
/// </para>
30+
/// </remarks>
31+
UrlElicitationRequired = -32042,
1532

1633
/// <summary>
1734
/// Indicates that the JSON payload does not conform to the expected Request object structure.
@@ -58,18 +75,10 @@ public enum McpErrorCode
5875
InternalError = -32603,
5976

6077
/// <summary>
61-
/// Indicates that URL-mode elicitation is required to complete the requested operation.
78+
/// Indicates that the JSON received could not be parsed.
6279
/// </summary>
6380
/// <remarks>
64-
/// <para>
65-
/// This error is returned when a server operation requires additional user input through URL-mode elicitation
66-
/// before it can proceed. The error data must include the `data.elicitations` payload describing the pending
67-
/// elicitation(s) for the client to present to the user.
68-
/// </para>
69-
/// <para>
70-
/// Common scenarios include OAuth authorization and other out-of-band flows that cannot be completed inside
71-
/// the MCP client.
72-
/// </para>
81+
/// This error occurs when the input contains malformed JSON or incorrect syntax.
7382
/// </remarks>
74-
UrlElicitationRequired = -32042,
83+
ParseError = -32700,
7584
}

src/ModelContextProtocol.Core/Server/McpServerImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ subscribeHandler is null && unsubscribeHandler is null && resources is null &&
273273

274274
listResourcesHandler ??= (static async (_, __) => new ListResourcesResult());
275275
listResourceTemplatesHandler ??= (static async (_, __) => new ListResourceTemplatesResult());
276-
readResourceHandler ??= (static async (request, _) => throw new McpProtocolException($"Unknown resource URI: '{request.Params?.Uri}'", McpErrorCode.InvalidParams));
276+
readResourceHandler ??= (static async (request, _) => throw new McpProtocolException($"Unknown resource URI: '{request.Params?.Uri}'", McpErrorCode.ResourceNotFound));
277277
subscribeHandler ??= (static async (_, __) => new EmptyResult());
278278
unsubscribeHandler ??= (static async (_, __) => new EmptyResult());
279279
var listChanged = resourcesCapability?.ListChanged;

tests/ModelContextProtocol.TestServer/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ private static void ConfigureResources(McpServerOptions options)
434434
}
435435

436436
ResourceContents contents = resourceContents.FirstOrDefault(r => r.Uri == request.Params.Uri)
437-
?? throw new McpProtocolException($"Resource not found: '{request.Params.Uri}'", McpErrorCode.InvalidParams);
437+
?? throw new McpProtocolException($"Resource not found: '{request.Params.Uri}'", McpErrorCode.ResourceNotFound);
438438

439439
return new ReadResourceResult
440440
{

tests/ModelContextProtocol.TestSseServer/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ static CreateMessageRequestParams CreateRequestSamplingParams(string context, st
273273
}
274274

275275
ResourceContents? contents = resourceContents.FirstOrDefault(r => r.Uri == request.Params.Uri) ??
276-
throw new McpProtocolException($"Resource not found: '{request.Params.Uri}'", McpErrorCode.InvalidParams);
276+
throw new McpProtocolException($"Resource not found: '{request.Params.Uri}'", McpErrorCode.ResourceNotFound);
277277

278278
return new ReadResourceResult
279279
{

tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsResourcesTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ protected override void ConfigureServices(ServiceCollection services, IMcpServer
108108
};
109109
}
110110

111-
throw new McpProtocolException($"Resource not found: {request.Params?.Uri}");
111+
throw new McpProtocolException($"Resource not found: {request.Params?.Uri}", McpErrorCode.ResourceNotFound);
112112
})
113113
.WithResources<SimpleResources>();
114114
}
@@ -249,6 +249,7 @@ public async Task Throws_Exception_On_Unknown_Resource()
249249
cancellationToken: TestContext.Current.CancellationToken));
250250

251251
Assert.Contains("Resource not found", e.Message);
252+
Assert.Equal(McpErrorCode.ResourceNotFound, e.ErrorCode);
252253
}
253254

254255
[Fact]

tests/ModelContextProtocol.Tests/Configuration/McpServerResourceRoutingTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public async Task MultipleTemplatedResources_MatchesCorrectResource()
3636
Assert.Equal("params: a, b, c", ((TextResourceContents)paramsResult.Contents[0]).Text);
3737

3838
var mcpEx = await Assert.ThrowsAsync<McpProtocolException>(async () => await client.ReadResourceAsync("test://params{?a1,a2,a3}", null, TestContext.Current.CancellationToken));
39-
Assert.Equal(McpErrorCode.InvalidParams, mcpEx.ErrorCode);
39+
Assert.Equal(McpErrorCode.ResourceNotFound, mcpEx.ErrorCode);
4040
Assert.Equal("Request failed (remote): Unknown resource URI: 'test://params{?a1,a2,a3}'", mcpEx.Message);
4141
}
4242
}

tests/ModelContextProtocol.Tests/McpProtocolExceptionDataTests.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ protected override void ConfigureServices(ServiceCollection services, IMcpServer
3333
switch (toolName)
3434
{
3535
case "throw_with_serializable_data":
36-
throw new McpProtocolException("Resource not found", (McpErrorCode)(-32002))
36+
throw new McpProtocolException("Resource not found", McpErrorCode.ResourceNotFound)
3737
{
3838
Data =
3939
{
@@ -43,7 +43,7 @@ protected override void ConfigureServices(ServiceCollection services, IMcpServer
4343
};
4444

4545
case "throw_with_nonserializable_data":
46-
throw new McpProtocolException("Resource not found", (McpErrorCode)(-32002))
46+
throw new McpProtocolException("Resource not found", McpErrorCode.ResourceNotFound)
4747
{
4848
Data =
4949
{
@@ -55,7 +55,7 @@ protected override void ConfigureServices(ServiceCollection services, IMcpServer
5555
};
5656

5757
case "throw_with_only_nonserializable_data":
58-
throw new McpProtocolException("Resource not found", (McpErrorCode)(-32002))
58+
throw new McpProtocolException("Resource not found", McpErrorCode.ResourceNotFound)
5959
{
6060
Data =
6161
{
@@ -79,7 +79,7 @@ public async Task Exception_With_Serializable_Data_Propagates_To_Client()
7979
await client.CallToolAsync("throw_with_serializable_data", cancellationToken: TestContext.Current.CancellationToken));
8080

8181
Assert.Equal("Request failed (remote): Resource not found", exception.Message);
82-
Assert.Equal((McpErrorCode)(-32002), exception.ErrorCode);
82+
Assert.Equal(McpErrorCode.ResourceNotFound, exception.ErrorCode);
8383

8484
// Verify the data was propagated to the exception
8585
// The Data collection should contain the expected keys
@@ -113,7 +113,7 @@ public async Task Exception_With_NonSerializable_Data_Still_Propagates_Error_To_
113113
await client.CallToolAsync("throw_with_nonserializable_data", cancellationToken: TestContext.Current.CancellationToken));
114114

115115
Assert.Equal("Request failed (remote): Resource not found", exception.Message);
116-
Assert.Equal((McpErrorCode)(-32002), exception.ErrorCode);
116+
Assert.Equal(McpErrorCode.ResourceNotFound, exception.ErrorCode);
117117

118118
// Verify that only the serializable data was propagated (non-serializable was filtered out)
119119
var hasUri = false;
@@ -142,7 +142,7 @@ public async Task Exception_With_Only_NonSerializable_Data_Still_Propagates_Erro
142142
await client.CallToolAsync("throw_with_only_nonserializable_data", cancellationToken: TestContext.Current.CancellationToken));
143143

144144
Assert.Equal("Request failed (remote): Resource not found", exception.Message);
145-
Assert.Equal((McpErrorCode)(-32002), exception.ErrorCode);
145+
Assert.Equal(McpErrorCode.ResourceNotFound, exception.ErrorCode);
146146

147147
// When all data is non-serializable, the Data collection should be empty
148148
// (the server's ConvertExceptionData returns null when no serializable data exists)

tests/ModelContextProtocol.Tests/Server/McpServerTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ await transport.SendMessageAsync(
681681
public async Task Can_Handle_Call_Tool_Requests_With_McpProtocolException_And_Data()
682682
{
683683
const string ErrorMessage = "Resource not found";
684-
const McpErrorCode ErrorCode = (McpErrorCode)(-32002);
684+
const McpErrorCode ErrorCode = McpErrorCode.ResourceNotFound;
685685
const string ResourceUri = "file:///path/to/resource";
686686

687687
await using var transport = new TestServerTransport();

0 commit comments

Comments
 (0)