Skip to content

Commit 06aeb33

Browse files
committed
Use strong-typing of params in most remaining McpClientExtensions methods
1 parent f135355 commit 06aeb33

File tree

4 files changed

+44
-58
lines changed

4 files changed

+44
-58
lines changed

src/ModelContextProtocol/Client/McpClientExtensions.cs

Lines changed: 42 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static Task PingAsync(this IMcpClient client, CancellationToken cancellat
2222
Throw.IfNull(client);
2323

2424
return client.SendRequestAsync(
25-
RequestMethods.Ping,
25+
RequestMethods.Ping,
2626
parameters: null,
2727
McpJsonUtilities.JsonContext.Default.Object!,
2828
McpJsonUtilities.JsonContext.Default.Object,
@@ -51,9 +51,9 @@ public static async Task<IList<McpClientTool>> ListToolsAsync(
5151
do
5252
{
5353
var toolResults = await client.SendRequestAsync(
54-
RequestMethods.ToolsList,
55-
CreateCursorDictionary(cursor)!,
56-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
54+
RequestMethods.ToolsList,
55+
new() { Cursor = cursor },
56+
McpJsonUtilities.JsonContext.Default.ListToolsRequestParams,
5757
McpJsonUtilities.JsonContext.Default.ListToolsResult,
5858
cancellationToken: cancellationToken).ConfigureAwait(false);
5959

@@ -95,9 +95,9 @@ public static async IAsyncEnumerable<McpClientTool> EnumerateToolsAsync(
9595
do
9696
{
9797
var toolResults = await client.SendRequestAsync(
98-
RequestMethods.ToolsList,
99-
CreateCursorDictionary(cursor)!,
100-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
98+
RequestMethods.ToolsList,
99+
new() { Cursor = cursor },
100+
McpJsonUtilities.JsonContext.Default.ListToolsRequestParams,
101101
McpJsonUtilities.JsonContext.Default.ListToolsResult,
102102
cancellationToken: cancellationToken).ConfigureAwait(false);
103103

@@ -127,9 +127,9 @@ public static async Task<IList<McpClientPrompt>> ListPromptsAsync(
127127
do
128128
{
129129
var promptResults = await client.SendRequestAsync(
130-
RequestMethods.PromptsList,
131-
CreateCursorDictionary(cursor)!,
132-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
130+
RequestMethods.PromptsList,
131+
new() { Cursor = cursor },
132+
McpJsonUtilities.JsonContext.Default.ListPromptsRequestParams,
133133
McpJsonUtilities.JsonContext.Default.ListPromptsResult,
134134
cancellationToken: cancellationToken).ConfigureAwait(false);
135135

@@ -166,8 +166,8 @@ public static async IAsyncEnumerable<Prompt> EnumeratePromptsAsync(
166166
{
167167
var promptResults = await client.SendRequestAsync(
168168
RequestMethods.PromptsList,
169-
CreateCursorDictionary(cursor)!,
170-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
169+
new() { Cursor = cursor },
170+
McpJsonUtilities.JsonContext.Default.ListPromptsRequestParams,
171171
McpJsonUtilities.JsonContext.Default.ListPromptsResult,
172172
cancellationToken: cancellationToken).ConfigureAwait(false);
173173

@@ -202,12 +202,10 @@ public static Task<GetPromptResult> GetPromptAsync(
202202
serializerOptions ??= McpJsonUtilities.DefaultOptions;
203203
serializerOptions.MakeReadOnly();
204204

205-
var parametersTypeInfo = serializerOptions.GetTypeInfo<IReadOnlyDictionary<string, object?>>();
206-
207205
return client.SendRequestAsync(
208206
RequestMethods.PromptsGet,
209-
CreateParametersDictionary(name, arguments),
210-
parametersTypeInfo,
207+
new() { Name = name, Arguments = arguments },
208+
McpJsonUtilities.JsonContext.Default.GetPromptRequestParams,
211209
McpJsonUtilities.JsonContext.Default.GetPromptResult,
212210
cancellationToken: cancellationToken);
213211
}
@@ -229,9 +227,9 @@ public static async Task<IList<ResourceTemplate>> ListResourceTemplatesAsync(
229227
do
230228
{
231229
var templateResults = await client.SendRequestAsync(
232-
RequestMethods.ResourcesTemplatesList,
233-
CreateCursorDictionary(cursor)!,
234-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
230+
RequestMethods.ResourcesTemplatesList,
231+
new() { Cursor = cursor },
232+
McpJsonUtilities.JsonContext.Default.ListResourceTemplatesRequestParams,
235233
McpJsonUtilities.JsonContext.Default.ListResourceTemplatesResult,
236234
cancellationToken: cancellationToken).ConfigureAwait(false);
237235

@@ -270,9 +268,9 @@ public static async IAsyncEnumerable<ResourceTemplate> EnumerateResourceTemplate
270268
do
271269
{
272270
var templateResults = await client.SendRequestAsync(
273-
RequestMethods.ResourcesTemplatesList,
274-
CreateCursorDictionary(cursor)!,
275-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
271+
RequestMethods.ResourcesTemplatesList,
272+
new() { Cursor = cursor },
273+
McpJsonUtilities.JsonContext.Default.ListResourceTemplatesRequestParams,
276274
McpJsonUtilities.JsonContext.Default.ListResourceTemplatesResult,
277275
cancellationToken: cancellationToken).ConfigureAwait(false);
278276

@@ -303,9 +301,9 @@ public static async Task<IList<Resource>> ListResourcesAsync(
303301
do
304302
{
305303
var resourceResults = await client.SendRequestAsync(
306-
RequestMethods.ResourcesList,
307-
CreateCursorDictionary(cursor)!,
308-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
304+
RequestMethods.ResourcesList,
305+
new() { Cursor = cursor },
306+
McpJsonUtilities.JsonContext.Default.ListResourcesRequestParams,
309307
McpJsonUtilities.JsonContext.Default.ListResourcesResult,
310308
cancellationToken: cancellationToken).ConfigureAwait(false);
311309

@@ -344,9 +342,9 @@ public static async IAsyncEnumerable<Resource> EnumerateResourcesAsync(
344342
do
345343
{
346344
var resourceResults = await client.SendRequestAsync(
347-
RequestMethods.ResourcesList,
348-
CreateCursorDictionary(cursor)!,
349-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
345+
RequestMethods.ResourcesList,
346+
new() { Cursor = cursor },
347+
McpJsonUtilities.JsonContext.Default.ListResourcesRequestParams,
350348
McpJsonUtilities.JsonContext.Default.ListResourcesResult,
351349
cancellationToken: cancellationToken).ConfigureAwait(false);
352350

@@ -373,9 +371,9 @@ public static Task<ReadResourceResult> ReadResourceAsync(
373371
Throw.IfNullOrWhiteSpace(uri);
374372

375373
return client.SendRequestAsync(
376-
RequestMethods.ResourcesRead,
377-
new Dictionary<string, object> { ["uri"] = uri },
378-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
374+
RequestMethods.ResourcesRead,
375+
new() { Uri = uri },
376+
McpJsonUtilities.JsonContext.Default.ReadResourceRequestParams,
379377
McpJsonUtilities.JsonContext.Default.ReadResourceResult,
380378
cancellationToken: cancellationToken);
381379
}
@@ -400,13 +398,13 @@ public static Task<CompleteResult> GetCompletionAsync(this IMcpClient client, Re
400398
}
401399

402400
return client.SendRequestAsync(
403-
RequestMethods.CompletionComplete,
404-
new Dictionary<string, object>
401+
RequestMethods.CompletionComplete,
402+
new()
405403
{
406-
["ref"] = reference,
407-
["argument"] = new Argument { Name = argumentName, Value = argumentValue }
404+
Ref = reference,
405+
Argument = new Argument { Name = argumentName, Value = argumentValue }
408406
},
409-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
407+
McpJsonUtilities.JsonContext.Default.CompleteRequestParams,
410408
McpJsonUtilities.JsonContext.Default.CompleteResult,
411409
cancellationToken: cancellationToken);
412410
}
@@ -423,9 +421,9 @@ public static Task SubscribeToResourceAsync(this IMcpClient client, string uri,
423421
Throw.IfNullOrWhiteSpace(uri);
424422

425423
return client.SendRequestAsync(
426-
RequestMethods.ResourcesSubscribe,
427-
new Dictionary<string, object> { ["uri"] = uri },
428-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
424+
RequestMethods.ResourcesSubscribe,
425+
new() { Uri = uri },
426+
McpJsonUtilities.JsonContext.Default.SubscribeRequestParams,
429427
McpJsonUtilities.JsonContext.Default.EmptyResult,
430428
cancellationToken: cancellationToken);
431429
}
@@ -443,8 +441,8 @@ public static Task UnsubscribeFromResourceAsync(this IMcpClient client, string u
443441

444442
return client.SendRequestAsync(
445443
RequestMethods.ResourcesUnsubscribe,
446-
new Dictionary<string, object> { ["uri"] = uri },
447-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
444+
new() { Uri = uri },
445+
McpJsonUtilities.JsonContext.Default.UnsubscribeRequestParams,
448446
McpJsonUtilities.JsonContext.Default.EmptyResult,
449447
cancellationToken: cancellationToken);
450448
}
@@ -473,7 +471,7 @@ public static Task<CallToolResponse> CallToolAsync(
473471
var parametersTypeInfo = serializerOptions.GetTypeInfo<IReadOnlyDictionary<string, object?>>();
474472

475473
return client.SendRequestAsync(
476-
RequestMethods.ToolsCall,
474+
RequestMethods.ToolsCall,
477475
CreateParametersDictionary(toolName, arguments),
478476
parametersTypeInfo,
479477
McpJsonUtilities.JsonContext.Default.CallToolResponse,
@@ -629,15 +627,12 @@ public static Task SetLoggingLevel(this IMcpClient client, LoggingLevel level, C
629627

630628
return client.SendRequestAsync(
631629
RequestMethods.LoggingSetLevel,
632-
new Dictionary<string, object> { ["level"] = level },
633-
McpJsonUtilities.JsonContext.Default.DictionaryStringObject,
630+
new() { Level = level },
631+
McpJsonUtilities.JsonContext.Default.SetLevelRequestParams,
634632
McpJsonUtilities.JsonContext.Default.EmptyResult,
635633
cancellationToken: cancellationToken);
636634
}
637635

638-
private static Dictionary<string, object?>? CreateCursorDictionary(string? cursor) =>
639-
cursor != null ? new() { ["cursor"] = cursor } : null;
640-
641636
private static Dictionary<string, object?> CreateParametersDictionary(
642637
string nameParameter, IReadOnlyDictionary<string, object?>? arguments)
643638
{

src/ModelContextProtocol/Protocol/Types/CallToolRequestParams.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ public class CallToolRequestParams : RequestParams
1818
/// Optional arguments to pass to the tool.
1919
/// </summary>
2020
[System.Text.Json.Serialization.JsonPropertyName("arguments")]
21-
public Dictionary<string, JsonElement>? Arguments { get; init; }
21+
public IReadOnlyDictionary<string, JsonElement>? Arguments { get; init; }
2222
}

src/ModelContextProtocol/Protocol/Types/GetPromptRequestParams.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ public class GetPromptRequestParams : RequestParams
1616
/// Arguments to use for templating the prompt.
1717
/// </summary>
1818
[System.Text.Json.Serialization.JsonPropertyName("arguments")]
19-
public Dictionary<string, object>? Arguments { get; init; }
19+
public IReadOnlyDictionary<string, object?>? Arguments { get; init; }
2020
}

tests/ModelContextProtocol.Tests/Client/McpClientExtensionsTests.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -340,15 +340,6 @@ public async Task SendNotificationAsync_HonorsJsonSerializerOptions()
340340
await Assert.ThrowsAsync<NotSupportedException>(() => client.SendNotificationAsync("Method4", new { Value = 42 }, emptyOptions, cancellationToken: TestContext.Current.CancellationToken));
341341
}
342342

343-
[Fact]
344-
public async Task GetPromptsAsync_HonorsJsonSerializerOptions()
345-
{
346-
JsonSerializerOptions emptyOptions = new() { TypeInfoResolver = JsonTypeInfoResolver.Combine() };
347-
IMcpClient client = await CreateMcpClientForServer();
348-
349-
await Assert.ThrowsAsync<NotSupportedException>(() => client.GetPromptAsync("Prompt", new Dictionary<string, object?> { ["i"] = 42 }, emptyOptions, cancellationToken: TestContext.Current.CancellationToken));
350-
}
351-
352343
[Fact]
353344
public async Task WithName_ChangesToolName()
354345
{

0 commit comments

Comments
 (0)