From af6fcff595138891b00ae560afbcea9d21370802 Mon Sep 17 00:00:00 2001 From: Aditya Singh <60082699+adityasingh2400@users.noreply.github.com> Date: Fri, 5 Jun 2026 16:52:31 -0700 Subject: [PATCH] Add McpClientOptions.InitializeMeta to set _meta on the initialize request (#1599) --- .../Client/McpClientImpl.cs | 1 + .../Client/McpClientOptions.cs | 16 +++++++ .../Client/McpClientMetaTests.cs | 44 +++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/src/ModelContextProtocol.Core/Client/McpClientImpl.cs b/src/ModelContextProtocol.Core/Client/McpClientImpl.cs index e6ab3aa..bc58794 100644 --- a/src/ModelContextProtocol.Core/Client/McpClientImpl.cs +++ b/src/ModelContextProtocol.Core/Client/McpClientImpl.cs @@ -679,6 +679,7 @@ internal sealed partial class McpClientImpl : McpClient ProtocolVersion = requestProtocol, Capabilities = _options.Capabilities ?? new ClientCapabilities(), ClientInfo = _options.ClientInfo ?? DefaultImplementation, + Meta = _options.InitializeMeta, }, McpJsonUtilities.JsonContext.Default.InitializeRequestParams, McpJsonUtilities.JsonContext.Default.InitializeResult, diff --git a/src/ModelContextProtocol.Core/Client/McpClientOptions.cs b/src/ModelContextProtocol.Core/Client/McpClientOptions.cs index 6d91f5b..f84b848 100644 --- a/src/ModelContextProtocol.Core/Client/McpClientOptions.cs +++ b/src/ModelContextProtocol.Core/Client/McpClientOptions.cs @@ -1,5 +1,6 @@ using ModelContextProtocol.Protocol; using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Nodes; namespace ModelContextProtocol.Client; @@ -31,6 +32,21 @@ public sealed class McpClientOptions /// public ClientCapabilities? Capabilities { get; set; } + /// + /// Gets or sets the metadata to include in the _meta field of the request. + /// + /// + /// + /// When set, this value is sent as on the during the initialization handshake. + /// This allows passing implementation-specific data to the server alongside the standard initialize parameters, + /// such as authentication context a server validates before completing the handshake. + /// + /// + /// When , no _meta field is sent. + /// + /// + public JsonObject? InitializeMeta { get; set; } + /// /// Gets or sets the protocol version to request from the server, using a date-based versioning scheme. /// diff --git a/tests/ModelContextProtocol.Tests/Client/McpClientMetaTests.cs b/tests/ModelContextProtocol.Tests/Client/McpClientMetaTests.cs index 863d8e6..7e67eb4 100644 --- a/tests/ModelContextProtocol.Tests/Client/McpClientMetaTests.cs +++ b/tests/ModelContextProtocol.Tests/Client/McpClientMetaTests.cs @@ -8,6 +8,8 @@ namespace ModelContextProtocol.Tests.Client; public class McpClientMetaTests : ClientServerTestBase { + private readonly TaskCompletionSource _initializeMeta = new(); + public McpClientMetaTests(ITestOutputHelper outputHelper) : base(outputHelper) { @@ -28,6 +30,48 @@ public class McpClientMetaTests : ClientServerTestBase 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]