22using ModelContextProtocol . Protocol ;
33using System . Collections . ObjectModel ;
44using System . Text . Json ;
5+ using System . Text . Json . Nodes ;
56
67namespace ModelContextProtocol . Client ;
78
@@ -36,6 +37,7 @@ public sealed class McpClientTool : AIFunction
3637 private readonly string _name ;
3738 private readonly string _description ;
3839 private readonly IProgress < ProgressNotificationValue > ? _progress ;
40+ private readonly JsonObject ? _meta ;
3941
4042 /// <summary>
4143 /// Initializes a new instance of the <see cref="McpClientTool"/> class.
@@ -73,6 +75,7 @@ public McpClientTool(
7375 _name = tool . Name ;
7476 _description = tool . Description ?? string . Empty ;
7577 _progress = null ;
78+ _meta = null ;
7679 }
7780
7881 internal McpClientTool (
@@ -81,14 +84,16 @@ internal McpClientTool(
8184 JsonSerializerOptions serializerOptions ,
8285 string ? name = null ,
8386 string ? description = null ,
84- IProgress < ProgressNotificationValue > ? progress = null )
87+ IProgress < ProgressNotificationValue > ? progress = null ,
88+ JsonObject ? meta = null )
8589 {
8690 _client = client ;
8791 ProtocolTool = tool ;
8892 JsonSerializerOptions = serializerOptions ;
8993 _name = name ?? tool . Name ;
9094 _description = description ?? tool . Description ?? string . Empty ;
9195 _progress = progress ;
96+ _meta = meta ;
9297 }
9398
9499 /// <summary>
@@ -196,15 +201,38 @@ public ValueTask<CallToolResult> CallAsync(
196201 IReadOnlyDictionary < string , object ? > ? arguments = null ,
197202 IProgress < ProgressNotificationValue > ? progress = null ,
198203 RequestOptions ? options = null ,
199- CancellationToken cancellationToken = default ) =>
200- _client . CallToolAsync (
204+ CancellationToken cancellationToken = default )
205+ {
206+ // If there's any metadata provided with WithMeta, we can't just pass along the options as-is,
207+ // and instead need to create new options that merges in _meta.
208+ if ( _meta is { } meta )
209+ {
210+ // Create a new RequestOptions, as we're going to need to store a new JsonObject for Meta (either
211+ // _meta or _meta+options.Meta), and we don't want to mutate the user's options object.
212+ RequestOptions newOptions = options ? . Clone ( ) ?? new ( ) ;
213+
214+ // If we also have newOptions.Meta, merge that with _meta into a new JsonObject, preferring
215+ // the objects from newOptions.Meta in case of conflicts.
216+ if ( newOptions . Meta is { } newOptionsMeta )
217+ {
218+ meta = ( JsonObject ) meta . DeepClone ( ) ;
219+ foreach ( var p in newOptionsMeta )
220+ {
221+ meta [ p . Key ] = p . Value ? . DeepClone ( ) ;
222+ }
223+ }
224+
225+ newOptions . Meta = meta ;
226+ options = newOptions ;
227+ }
228+
229+ return _client . CallToolAsync (
201230 ProtocolTool . Name ,
202231 arguments ,
203232 progress ,
204- options ?? new RequestOptions ( ) {
205- JsonSerializerOptions = JsonSerializerOptions
206- } ,
233+ options ,
207234 cancellationToken ) ;
235+ }
208236
209237 /// <summary>
210238 /// Creates a new instance of the tool but modified to return the specified name from its <see cref="Name"/> property.
@@ -232,7 +260,7 @@ public ValueTask<CallToolResult> CallAsync(
232260 /// </remarks>
233261 /// <returns>A new instance of <see cref="McpClientTool"/> with the provided name.</returns>
234262 public McpClientTool WithName ( string name ) =>
235- new ( _client , ProtocolTool , JsonSerializerOptions , name , _description , _progress ) ;
263+ new ( _client , ProtocolTool , JsonSerializerOptions , name , _description , _progress , _meta ) ;
236264
237265 /// <summary>
238266 /// Creates a new instance of the tool but modified to return the specified description from its <see cref="Description"/> property.
@@ -256,7 +284,7 @@ public McpClientTool WithName(string name) =>
256284 /// </remarks>
257285 /// <returns>A new instance of <see cref="McpClientTool"/> with the provided description.</returns>
258286 public McpClientTool WithDescription ( string description ) =>
259- new ( _client , ProtocolTool , JsonSerializerOptions , _name , description , _progress ) ;
287+ new ( _client , ProtocolTool , JsonSerializerOptions , _name , description , _progress , _meta ) ;
260288
261289 /// <summary>
262290 /// Creates a new instance of the tool but modified to report progress via the specified <see cref="IProgress{T}"/>.
@@ -280,6 +308,35 @@ public McpClientTool WithProgress(IProgress<ProgressNotificationValue> progress)
280308 {
281309 Throw . IfNull ( progress ) ;
282310
283- return new McpClientTool ( _client , ProtocolTool , JsonSerializerOptions , _name , _description , progress ) ;
311+ return new McpClientTool ( _client , ProtocolTool , JsonSerializerOptions , _name , _description , progress , _meta ) ;
284312 }
313+
314+ /// <summary>
315+ /// Creates a new instance of the tool but modified to include the specified metadata in tool call requests.
316+ /// </summary>
317+ /// <param name="meta">
318+ /// The metadata to include in tool call requests. This will be serialized as the <c>_meta</c> field
319+ /// in the JSON-RPC request parameters.
320+ /// </param>
321+ /// <remarks>
322+ /// <para>
323+ /// Adding metadata to the tool allows you to pass additional protocol-level information with each tool call.
324+ /// This can be useful for tracing, logging, or passing context information to the server.
325+ /// </para>
326+ /// <para>
327+ /// Only one metadata object can be specified at a time. Calling <see cref="WithMeta"/> again
328+ /// will overwrite any previously specified metadata object. If passed <see langword="null"/>,
329+ /// any previously supplied metadata will be removed.
330+ /// </para>
331+ /// <para>
332+ /// The metadata is passed through to the server as-is, merged with any protocol-level metadata
333+ /// such as progress tokens when <see cref="WithProgress"/> is also used. If a <see cref="RequestOptions"/>
334+ /// is passed to <see cref="CallAsync"/>, the metadata from both <paramref name="meta"/> and its
335+ /// <see cref="RequestOptions"/> will be merged, preferring values from the <see cref="RequestOptions"/> in
336+ /// case of conflicts.
337+ /// </para>
338+ /// </remarks>
339+ /// <returns>A new instance of <see cref="McpClientTool"/>, configured with the provided metadata.</returns>
340+ public McpClientTool WithMeta ( JsonObject ? meta ) =>
341+ new McpClientTool ( _client , ProtocolTool , JsonSerializerOptions , _name , _description , _progress , meta ) ;
285342}
0 commit comments