csharp-sdk/tests/ModelContextProtocol.Tests/Client/McpClientMetaTests.cs

185 lines
No EOL
6.2 KiB
C#

using Microsoft.Extensions.DependencyInjection;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
using System.Text.Json.Nodes;
namespace ModelContextProtocol.Tests.Client;
public class McpClientMetaTests : ClientServerTestBase
{
private readonly TaskCompletionSource<JsonNode?> _initializeMeta = new();
public McpClientMetaTests(ITestOutputHelper outputHelper)
: base(outputHelper)
{
}
protected override void ConfigureServices(ServiceCollection services, IMcpServerBuilder mcpServerBuilder)
{
services.Configure<McpServerOptions>(o =>
{
o.ServerInfo = new Implementation
{
Name = "test-server",
Version = "1.0.0",
Description = "A test server for unit testing",
WebsiteUrl = "https://example.com",
};
o.ToolCollection = new ();
o.ResourceCollection = new ();
o.PromptCollection = new ();
});
// Capture the _meta the server receives on the initialize request so tests can
// assert that McpClientOptions.InitializeMeta is threaded through the handshake.
mcpServerBuilder.WithMessageFilters(filters =>
filters.AddIncomingFilter(next => async (context, cancellationToken) =>
{
if (context.JsonRpcMessage is JsonRpcRequest { Method: RequestMethods.Initialize } request)
{
_initializeMeta.TrySetResult(request.Params?["_meta"]);
}
await next(context, cancellationToken);
}));
}
[Fact]
public async Task InitializeMeta_IsSentToServer_WhenSet()
{
var clientOptions = new McpClientOptions
{
InitializeMeta = new JsonObject
{
{ "foo", "bar baz" }
}
};
await using McpClient client = await CreateMcpClientForServer(clientOptions);
var meta = await _initializeMeta.Task.WaitAsync(TestContext.Current.CancellationToken);
Assert.NotNull(meta);
Assert.Equal("bar baz", meta["foo"]?.ToString());
}
[Fact]
public async Task InitializeMeta_IsOmitted_WhenNotSet()
{
await using McpClient client = await CreateMcpClientForServer();
var meta = await _initializeMeta.Task.WaitAsync(TestContext.Current.CancellationToken);
Assert.Null(meta);
}
[Fact]
public async Task ToolCallWithMetaFields()
{
Server.ServerOptions.ToolCollection?.Add(McpServerTool.Create(
async (RequestContext<CallToolRequestParams> context) =>
{
// Access the foo property of _meta field from the request parameters
var metaFoo = context.Params.Meta?["foo"]?.ToString();
// Assert that the meta foo is correctly passed
Assert.NotNull(metaFoo);
return $"Meta foo is {metaFoo}";
},
new () { Name = "meta_tool" }));
await using McpClient client = await CreateMcpClientForServer();
var requestOptions = new RequestOptions()
{
Meta = new JsonObject()
{
{ "foo", "bar baz" }
}
};
var result = await client.CallToolAsync("meta_tool", options: requestOptions, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(result);
Assert.Null(result.IsError);
var textContent = result.Content.OfType<TextContentBlock>().FirstOrDefault();
Assert.NotNull(textContent);
Assert.Contains("bar baz", textContent.Text);
}
[Fact]
public async Task ResourceReadWithMetaFields()
{
Server.ServerOptions.ResourceCollection?.Add(McpServerResource.Create(
(RequestContext<ReadResourceRequestParams> context) =>
{
// Access the foo property of _meta field from the request parameters
var metaFoo = context.Params.Meta?["foo"]?.ToString();
// Assert that the meta foo is correctly passed
Assert.NotNull(metaFoo);
return $"Resource with Meta foo is {metaFoo}";
},
new () { UriTemplate = "test://meta_resource" }));
await using McpClient client = await CreateMcpClientForServer();
var requestOptions = new RequestOptions()
{
Meta = new JsonObject()
{
{ "foo", "bar baz" }
}
};
var result = await client.ReadResourceAsync("test://meta_resource", options: requestOptions, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(result);
var textContent = result.Contents.OfType<TextResourceContents>().FirstOrDefault();
Assert.NotNull(textContent);
Assert.Contains("bar baz", textContent.Text);
}
[Fact]
public async Task PromptGetWithMetaFields()
{
Server.ServerOptions.PromptCollection?.Add(McpServerPrompt.Create(
(RequestContext<GetPromptRequestParams> context) =>
{
// Access the foo property of _meta field from the request parameters
var metaFoo = context.Params.Meta?["foo"]?.ToString();
// Assert that the meta foo is correctly passed
Assert.NotNull(metaFoo);
return $"Prompt with Meta foo is {metaFoo}";
},
new () { Name = "meta_prompt" }));
await using McpClient client = await CreateMcpClientForServer();
var requestOptions = new RequestOptions()
{
Meta = new JsonObject()
{
{ "foo", "bar baz" }
}
};
var result = await client.GetPromptAsync("meta_prompt", options: requestOptions, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(result);
Assert.NotEmpty(result.Messages);
var message = result.Messages.First();
Assert.NotNull(message.Content);
var textContent = message.Content as TextContentBlock;
Assert.NotNull(textContent);
Assert.Contains("bar baz", textContent.Text);
}
}