csharp-sdk/tests/ModelContextProtocol.Tests/Protocol/ElicitationTests.cs
2025-12-05 00:03:16 -08:00

150 lines
No EOL
6.6 KiB
C#

using Microsoft.Extensions.DependencyInjection;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
using System.Text.Json;
namespace ModelContextProtocol.Tests.Configuration;
public partial class ElicitationTests : ClientServerTestBase
{
public ElicitationTests(ITestOutputHelper testOutputHelper)
: base(testOutputHelper)
{
}
protected override void ConfigureServices(ServiceCollection services, IMcpServerBuilder mcpServerBuilder)
{
mcpServerBuilder.WithCallToolHandler(async (request, cancellationToken) =>
{
Assert.Equal("TestElicitation", request.Params?.Name);
var result = await request.Server.ElicitAsync(
new()
{
Mode = "form",
Message = "Please provide more information.",
RequestedSchema = new()
{
Properties = new Dictionary<string, ElicitRequestParams.PrimitiveSchemaDefinition>()
{
["prop1"] = new ElicitRequestParams.StringSchema
{
Title = "title1",
MinLength = 1,
MaxLength = 100,
},
["prop2"] = new ElicitRequestParams.NumberSchema
{
Description = "description2",
Minimum = 0,
Maximum = 1000,
},
["prop3"] = new ElicitRequestParams.BooleanSchema
{
Title = "title3",
Description = "description4",
Default = true,
},
["prop4"] = new ElicitRequestParams.TitledSingleSelectEnumSchema
{
OneOf =
[
new ElicitRequestParams.EnumSchemaOption { Const = "option1", Title = "Name1" },
new ElicitRequestParams.EnumSchemaOption { Const = "option2", Title = "Name2" },
new ElicitRequestParams.EnumSchemaOption { Const = "option3", Title = "Name3" },
]
},
},
},
},
CancellationToken.None);
Assert.Equal("accept", result.Action);
return new CallToolResult
{
Content = [new TextContentBlock { Text = "success" }],
};
});
}
[Fact]
public async Task Can_Elicit_Information()
{
await using McpClient client = await CreateMcpClientForServer(new McpClientOptions
{
Handlers = new McpClientHandlers()
{
ElicitationHandler = async (request, cancellationtoken) =>
{
Assert.NotNull(request);
Assert.Equal("form", request.Mode);
Assert.Equal("Please provide more information.", request.Message);
Assert.NotNull(request.RequestedSchema);
Assert.Equal(4, request.RequestedSchema.Properties.Count);
foreach (var entry in request.RequestedSchema.Properties)
{
switch (entry.Key)
{
case "prop1":
var primitiveString = Assert.IsType<ElicitRequestParams.StringSchema>(entry.Value);
Assert.Equal("title1", primitiveString.Title);
Assert.Equal(1, primitiveString.MinLength);
Assert.Equal(100, primitiveString.MaxLength);
break;
case "prop2":
var primitiveNumber = Assert.IsType<ElicitRequestParams.NumberSchema>(entry.Value);
Assert.Equal("description2", primitiveNumber.Description);
Assert.Equal(0, primitiveNumber.Minimum);
Assert.Equal(1000, primitiveNumber.Maximum);
break;
case "prop3":
var primitiveBool = Assert.IsType<ElicitRequestParams.BooleanSchema>(entry.Value);
Assert.Equal("title3", primitiveBool.Title);
Assert.Equal("description4", primitiveBool.Description);
Assert.True(primitiveBool.Default);
break;
case "prop4":
var primitiveEnum = Assert.IsType<ElicitRequestParams.TitledSingleSelectEnumSchema>(entry.Value);
Assert.Equal(["option1", "option2", "option3"], primitiveEnum.OneOf.Select(e => e.Const));
Assert.Equal(["Name1", "Name2", "Name3"], primitiveEnum.OneOf.Select(e => e.Title));
break;
default:
Assert.Fail($"Unknown property: {entry.Key}");
break;
}
}
return new ElicitResult
{
Action = "accept",
Content = new Dictionary<string, JsonElement>
{
["prop1"] = JsonElement.Parse("""
"string result"
"""),
["prop2"] = JsonElement.Parse("""
42
"""),
["prop3"] = JsonElement.Parse("""
true
"""),
["prop4"] = JsonElement.Parse("""
"option2"
"""),
},
};
}
}
});
var result = await client.CallToolAsync("TestElicitation", cancellationToken: TestContext.Current.CancellationToken);
Assert.Equal("success", (result.Content[0] as TextContentBlock)?.Text);
}
}