Title
McpClientOptions: no way to set _meta on the initialize request — InitializeRequestParams.Meta is never populated
Summary
InitializeRequestParams correctly inherits Meta (JsonObject?, [JsonPropertyName("_meta")]) from RequestParams, in full alignment with the MCP 2025-11-25 spec. However, McpClientImpl.ConnectAsync constructs InitializeRequestParams without ever reading from McpClientOptions, so there is no caller-accessible path to populate Meta. The type supports it; the public API does not expose it.
Package and version
- Package:
ModelContextProtocol
- Version:
1.3.0
- Target framework:
.NET 10.0
Spec alignment
The MCP 2025-11-25 schema defines:
export interface RequestParams {
_meta?: {
progressToken?: ProgressToken;
[key: string]: unknown;
};
}
export interface InitializeRequestParams extends RequestParams {
protocolVersion: string;
capabilities: ClientCapabilities;
clientInfo: Implementation;
}
InitializeRequestParams inherits _meta from RequestParams. The C# SDK correctly models this:
// RequestParams (SDK)
[JsonPropertyName("_meta")]
public JsonObject? Meta { get; set; }
// InitializeRequestParams inherits Meta from RequestParams
The type is spec-compliant. The gap is that no caller can reach it.
Root cause
McpClientImpl.ConnectAsync (~line 546) hard-codes the params with no extension point:
var initializeResponse = await SendRequestAsync(
RequestMethods.Initialize,
new InitializeRequestParams
{
ProtocolVersion = requestProtocol,
Capabilities = _options.Capabilities ?? new ClientCapabilities(),
ClientInfo = _options.ClientInfo ?? DefaultImplementation,
// Meta is never set — McpClientOptions has no InitializeMeta property
},
...);
McpClientOptions has no property that feeds into InitializeRequestParams.Meta.
Impact
Any use case that requires passing bootstrap data or auth credentials in initialize._meta is blocked through the normal McpClient.CreateAsync path. The spec and the SDK type both support it; only the public API is missing the hook.
Concrete example: a downstream MCP server that validates gateway identity at startup needs the connecting client to include an auth token in initialize._meta. Because McpClientOptions provides no way to set it, a workaround using a custom IClientTransport wrapper that writes the token to the subprocess stdin before the MCP handshake was required — significant complexity that a single property on McpClientOptions would eliminate.
Proposed fix
Add an InitializeMeta property to McpClientOptions and thread it through ConnectAsync:
// McpClientOptions — new property:
public JsonObject? InitializeMeta { get; init; }
// McpClientImpl.ConnectAsync — use it:
new InitializeRequestParams
{
ProtocolVersion = requestProtocol,
Capabilities = _options.Capabilities ?? new ClientCapabilities(),
ClientInfo = _options.ClientInfo ?? DefaultImplementation,
Meta = _options.InitializeMeta,
}
The fix is minimal: InitializeRequestParams.Meta already accepts JsonObject? — there is nothing to change in the protocol layer, only in the options-to-params plumbing.
Workaround
Use a custom IClientTransport wrapper to send out-of-band data before the MCP handshake (e.g. write a bootstrap line to the subprocess stdin for stdio transports). This is non-trivial, transport-specific, and couples the auth mechanism to the transport layer in ways the SDK was designed to abstract.
Related
Title
McpClientOptions: no way to set_metaon theinitializerequest —InitializeRequestParams.Metais never populatedSummary
InitializeRequestParamscorrectly inheritsMeta(JsonObject?,[JsonPropertyName("_meta")]) fromRequestParams, in full alignment with the MCP 2025-11-25 spec. However,McpClientImpl.ConnectAsyncconstructsInitializeRequestParamswithout ever reading fromMcpClientOptions, so there is no caller-accessible path to populateMeta. The type supports it; the public API does not expose it.Package and version
ModelContextProtocol1.3.0.NET 10.0Spec alignment
The MCP 2025-11-25 schema defines:
InitializeRequestParamsinherits_metafromRequestParams. The C# SDK correctly models this:The type is spec-compliant. The gap is that no caller can reach it.
Root cause
McpClientImpl.ConnectAsync(~line 546) hard-codes the params with no extension point:McpClientOptionshas no property that feeds intoInitializeRequestParams.Meta.Impact
Any use case that requires passing bootstrap data or auth credentials in
initialize._metais blocked through the normalMcpClient.CreateAsyncpath. The spec and the SDK type both support it; only the public API is missing the hook.Concrete example: a downstream MCP server that validates gateway identity at startup needs the connecting client to include an auth token in
initialize._meta. BecauseMcpClientOptionsprovides no way to set it, a workaround using a customIClientTransportwrapper that writes the token to the subprocess stdin before the MCP handshake was required — significant complexity that a single property onMcpClientOptionswould eliminate.Proposed fix
Add an
InitializeMetaproperty toMcpClientOptionsand thread it throughConnectAsync:The fix is minimal:
InitializeRequestParams.Metaalready acceptsJsonObject?— there is nothing to change in the protocol layer, only in the options-to-params plumbing.Workaround
Use a custom
IClientTransportwrapper to send out-of-band data before the MCP handshake (e.g. write a bootstrap line to the subprocess stdin for stdio transports). This is non-trivial, transport-specific, and couples the auth mechanism to the transport layer in ways the SDK was designed to abstract.Related
_metafield not serialized in HTTP transport - blocks ChatGPT Apps SDK #959 — "_metafield not serialized in HTTP transport - blocks ChatGPT Apps SDK" (closed): A prior_metaserialization bug affecting server-side tool metadata in HTTP responses. Different layer (serialization of outbound tool metadata vs. client-side injection into initialize params), but confirms the maintainers are actively engaged with_metaacross the SDK surface.RunSessionHandler (MCPEXP002): omitting`server.RunAsync(ct) silently hangs all MCP requests indefinitely with no diagnostic #1592 — "RunSessionHandler silent hang" (open): The workaround that made this gap impactful — a custom stdio transport bootstrap was needed precisely because
_metaon initialize was unreachable throughMcpClientOptions.