Skip to content

Commit 3d5a1d6

Browse files
committed
Add error handling for unsupported elicitation types #630
Introduce exception handling in `McpServerExtensions.cs` for unsupported types. Add a test case in `ElicitationTypedTests.cs` to verify exception throwing for unsupported types. Define a new `UnsupportedForm` class with nested properties and include JSON serialization attributes for proper handling.
1 parent 86ecb95 commit 3d5a1d6

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed

src/ModelContextProtocol.Core/Server/McpServerExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ private static ElicitRequestParams.RequestSchema BuildRequestSchema<T>(JsonSeria
315315

316316
if (typeInfo.Kind != JsonTypeInfoKind.None)
317317
{
318-
return null;
318+
throw new McpException($"Type '{type.FullName}' is not supported for elicitation requests.");
319319
}
320320

321321
var jsonElement = AIJsonUtilities.CreateJsonSchema(underlyingType, serializerOptions: serializerOptions);

tests/ModelContextProtocol.Tests/Protocol/ElicitationTypedTests.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,19 @@ protected override void ConfigureServices(ServiceCollection services, IMcpServer
4848
Assert.Equal(90210, result.Content!.ZipCode);
4949
Assert.False(result.Content!.IsAdmin);
5050
}
51+
else if (request.Params!.Name == "TestElicitationUnsupportedType")
52+
{
53+
await request.Server.ElicitAsync<UnsupportedForm>(
54+
message: "Please provide more information.",
55+
serializerOptions: ElicitationUnsupportedJsonContext.Default.Options,
56+
cancellationToken: CancellationToken.None);
57+
58+
// Should be unreachable
59+
return new CallToolResult
60+
{
61+
Content = [new TextContentBlock { Text = "unexpected" }],
62+
};
63+
}
5164
else
5265
{
5366
Assert.Fail($"Unexpected tool name: {request.Params!.Name}");
@@ -200,6 +213,31 @@ public async Task Elicit_Typed_Respects_NamingPolicy()
200213
Assert.Equal("success", (result.Content[0] as TextContentBlock)?.Text);
201214
}
202215

216+
[Fact]
217+
public async Task Elicit_Typed_With_Unsupported_Property_Type_Throws()
218+
{
219+
await using IMcpClient client = await CreateMcpClientForServer(new McpClientOptions
220+
{
221+
Capabilities = new()
222+
{
223+
Elicitation = new()
224+
{
225+
// Handler should never be invoked because the exception occurs before the request is sent.
226+
ElicitationHandler = async (req, ct) =>
227+
{
228+
Assert.Fail("Elicitation handler should not be called for unsupported schema test.");
229+
return new ElicitResult { Action = "cancel" };
230+
},
231+
},
232+
},
233+
});
234+
235+
var ex = await Assert.ThrowsAsync<McpException>(async() =>
236+
await client.CallToolAsync("TestElicitationUnsupportedType", cancellationToken: TestContext.Current.CancellationToken));
237+
238+
Assert.Contains(typeof(UnsupportedForm.Nested).FullName!, ex.Message);
239+
}
240+
203241
[JsonConverter(typeof(CustomizableJsonStringEnumConverter<SampleRole>))]
204242

205243
public enum SampleRole
@@ -236,4 +274,19 @@ internal partial class ElicitationTypedDefaultJsonContext : JsonSerializerContex
236274
[JsonSerializable(typeof(CamelForm))]
237275
[JsonSerializable(typeof(JsonElement))]
238276
internal partial class ElicitationTypedCamelJsonContext : JsonSerializerContext;
277+
278+
public sealed class UnsupportedForm
279+
{
280+
public string? Name { get; set; }
281+
public Nested? NestedProperty { get; set; } // Triggers unsupported (complex object)
282+
public sealed class Nested
283+
{
284+
public string? Value { get; set; }
285+
}
286+
}
287+
288+
[JsonSerializable(typeof(UnsupportedForm))]
289+
[JsonSerializable(typeof(UnsupportedForm.Nested))]
290+
[JsonSerializable(typeof(JsonElement))]
291+
internal partial class ElicitationUnsupportedJsonContext : JsonSerializerContext;
239292
}

0 commit comments

Comments
 (0)