Improve progress reporting (#145)
* Improve progress reporting - Enable injecting an `IProgress<>` into a tool call to report progress when the client has supplied a progress token - Add a custom type for ProgressToken and ProgressNotification to map to the schema - Simplify RequestId to match ProgressToken's shape - Serialize StdioClientTransport's SendMessageAsync implementation - Add strongly-typed names for all request methods - Change all request IDs created by McpJsonRpcEndpoint to include a guid for that endpoint * Address PR feedback
This commit is contained in:
parent
0294c574a6
commit
2c75acded8
2 changed files with 627 additions and 228 deletions
|
|
@ -42,7 +42,7 @@ internal sealed class McpClient : McpJsonRpcEndpoint, IMcpClient
|
|||
}
|
||||
|
||||
SetRequestHandler<CreateMessageRequestParams, CreateMessageResult>(
|
||||
"sampling/createMessage",
|
||||
RequestMethods.SamplingCreateMessage,
|
||||
(request, ct) => samplingHandler(request, ct));
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ internal sealed class McpClient : McpJsonRpcEndpoint, IMcpClient
|
|||
}
|
||||
|
||||
SetRequestHandler<ListRootsRequestParams, ListRootsResult>(
|
||||
"roots/list",
|
||||
RequestMethods.RootsList,
|
||||
(request, ct) => rootsHandler(request, ct));
|
||||
}
|
||||
}
|
||||
|
|
@ -89,21 +89,21 @@ internal sealed class McpClient : McpJsonRpcEndpoint, IMcpClient
|
|||
using var initializationCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
initializationCts.CancelAfter(_options.InitializationTimeout);
|
||||
|
||||
try
|
||||
{
|
||||
// Send initialize request
|
||||
var initializeResponse = await SendRequestAsync<InitializeResult>(
|
||||
new JsonRpcRequest
|
||||
try
|
||||
{
|
||||
// Send initialize request
|
||||
var initializeResponse = await SendRequestAsync<InitializeResult>(
|
||||
new JsonRpcRequest
|
||||
{
|
||||
Method = RequestMethods.Initialize,
|
||||
Params = new InitializeRequestParams()
|
||||
{
|
||||
Method = "initialize",
|
||||
Params = new InitializeRequestParams()
|
||||
{
|
||||
ProtocolVersion = _options.ProtocolVersion,
|
||||
Capabilities = _options.Capabilities ?? new ClientCapabilities(),
|
||||
ClientInfo = _options.ClientInfo,
|
||||
}
|
||||
},
|
||||
initializationCts.Token).ConfigureAwait(false);
|
||||
ProtocolVersion = _options.ProtocolVersion,
|
||||
Capabilities = _options.Capabilities ?? new ClientCapabilities(),
|
||||
ClientInfo = _options.ClientInfo
|
||||
}
|
||||
},
|
||||
initializationCts.Token).ConfigureAwait(false);
|
||||
|
||||
// Store server information
|
||||
_logger.ServerCapabilitiesReceived(EndpointName,
|
||||
|
|
@ -123,7 +123,7 @@ internal sealed class McpClient : McpJsonRpcEndpoint, IMcpClient
|
|||
|
||||
// Send initialized notification
|
||||
await SendMessageAsync(
|
||||
new JsonRpcNotification { Method = "notifications/initialized" },
|
||||
new JsonRpcNotification { Method = NotificationMethods.InitializedNotification },
|
||||
initializationCts.Token).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException) when (initializationCts.IsCancellationRequested)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public static class McpClientExtensions
|
|||
Throw.IfNull(client);
|
||||
|
||||
return client.SendRequestAsync<dynamic>(
|
||||
CreateRequest("ping", null),
|
||||
CreateRequest(RequestMethods.Ping, null),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +61,7 @@ public static class McpClientExtensions
|
|||
do
|
||||
{
|
||||
var toolResults = await client.SendRequestAsync<ListToolsResult>(
|
||||
CreateRequest("tools/list", CreateCursorDictionary(cursor)),
|
||||
CreateRequest(RequestMethods.ToolsList, CreateCursorDictionary(cursor)),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
tools ??= new List<McpClientTool>(toolResults.Tools.Count);
|
||||
|
|
@ -96,7 +96,7 @@ public static class McpClientExtensions
|
|||
do
|
||||
{
|
||||
var toolResults = await client.SendRequestAsync<ListToolsResult>(
|
||||
CreateRequest("tools/list", CreateCursorDictionary(cursor)),
|
||||
CreateRequest(RequestMethods.ToolsList, CreateCursorDictionary(cursor)),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
foreach (var tool in toolResults.Tools)
|
||||
|
|
@ -126,7 +126,7 @@ public static class McpClientExtensions
|
|||
do
|
||||
{
|
||||
var promptResults = await client.SendRequestAsync<ListPromptsResult>(
|
||||
CreateRequest("prompts/list", CreateCursorDictionary(cursor)),
|
||||
CreateRequest(RequestMethods.PromptsList, CreateCursorDictionary(cursor)),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (prompts is null)
|
||||
|
|
@ -164,7 +164,7 @@ public static class McpClientExtensions
|
|||
do
|
||||
{
|
||||
var promptResults = await client.SendRequestAsync<ListPromptsResult>(
|
||||
CreateRequest("prompts/list", CreateCursorDictionary(cursor)),
|
||||
CreateRequest(RequestMethods.PromptsList, CreateCursorDictionary(cursor)),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
foreach (var prompt in promptResults.Prompts)
|
||||
|
|
@ -192,7 +192,7 @@ public static class McpClientExtensions
|
|||
Throw.IfNullOrWhiteSpace(name);
|
||||
|
||||
return client.SendRequestAsync<GetPromptResult>(
|
||||
CreateRequest("prompts/get", CreateParametersDictionary(name, arguments)),
|
||||
CreateRequest(RequestMethods.PromptsGet, CreateParametersDictionary(name, arguments)),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ public static class McpClientExtensions
|
|||
do
|
||||
{
|
||||
var templateResults = await client.SendRequestAsync<ListResourceTemplatesResult>(
|
||||
CreateRequest("resources/templates/list", CreateCursorDictionary(cursor)),
|
||||
CreateRequest(RequestMethods.ResourcesTemplatesList, CreateCursorDictionary(cursor)),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (templates is null)
|
||||
|
|
@ -251,7 +251,7 @@ public static class McpClientExtensions
|
|||
do
|
||||
{
|
||||
var templateResults = await client.SendRequestAsync<ListResourceTemplatesResult>(
|
||||
CreateRequest("resources/templates/list", CreateCursorDictionary(cursor)),
|
||||
CreateRequest(RequestMethods.ResourcesTemplatesList, CreateCursorDictionary(cursor)),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
foreach (var template in templateResults.ResourceTemplates)
|
||||
|
|
@ -281,7 +281,7 @@ public static class McpClientExtensions
|
|||
do
|
||||
{
|
||||
var resourceResults = await client.SendRequestAsync<ListResourcesResult>(
|
||||
CreateRequest("resources/list", CreateCursorDictionary(cursor)),
|
||||
CreateRequest(RequestMethods.ResourcesList, CreateCursorDictionary(cursor)),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (resources is null)
|
||||
|
|
@ -319,7 +319,7 @@ public static class McpClientExtensions
|
|||
do
|
||||
{
|
||||
var resourceResults = await client.SendRequestAsync<ListResourcesResult>(
|
||||
CreateRequest("resources/list", CreateCursorDictionary(cursor)),
|
||||
CreateRequest(RequestMethods.ResourcesList, CreateCursorDictionary(cursor)),
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
|
||||
foreach (var resource in resourceResults.Resources)
|
||||
|
|
@ -345,7 +345,7 @@ public static class McpClientExtensions
|
|||
Throw.IfNullOrWhiteSpace(uri);
|
||||
|
||||
return client.SendRequestAsync<ReadResourceResult>(
|
||||
CreateRequest("resources/read", new() { ["uri"] = uri }),
|
||||
CreateRequest(RequestMethods.ResourcesRead, new() { ["uri"] = uri }),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
|
|
@ -369,7 +369,7 @@ public static class McpClientExtensions
|
|||
}
|
||||
|
||||
return client.SendRequestAsync<CompleteResult>(
|
||||
CreateRequest("completion/complete", new()
|
||||
CreateRequest(RequestMethods.CompletionComplete, new()
|
||||
{
|
||||
["ref"] = reference,
|
||||
["argument"] = new Argument { Name = argumentName, Value = argumentValue }
|
||||
|
|
@ -389,7 +389,7 @@ public static class McpClientExtensions
|
|||
Throw.IfNullOrWhiteSpace(uri);
|
||||
|
||||
return client.SendRequestAsync<EmptyResult>(
|
||||
CreateRequest("resources/subscribe", new() { ["uri"] = uri }),
|
||||
CreateRequest(RequestMethods.ResourcesSubscribe, new() { ["uri"] = uri }),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
|
|
@ -405,7 +405,7 @@ public static class McpClientExtensions
|
|||
Throw.IfNullOrWhiteSpace(uri);
|
||||
|
||||
return client.SendRequestAsync<EmptyResult>(
|
||||
CreateRequest("resources/unsubscribe", new() { ["uri"] = uri }),
|
||||
CreateRequest(RequestMethods.ResourcesUnsubscribe, new() { ["uri"] = uri }),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
|
|
@ -424,7 +424,7 @@ public static class McpClientExtensions
|
|||
Throw.IfNull(toolName);
|
||||
|
||||
return client.SendRequestAsync<CallToolResponse>(
|
||||
CreateRequest("tools/call", CreateParametersDictionary(toolName, arguments)),
|
||||
CreateRequest(RequestMethods.ToolsCall, CreateParametersDictionary(toolName, arguments)),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
|
|
@ -560,7 +560,7 @@ public static class McpClientExtensions
|
|||
Throw.IfNull(client);
|
||||
|
||||
return client.SendRequestAsync<EmptyResult>(
|
||||
CreateRequest("logging/setLevel", new() { ["level"] = level }),
|
||||
CreateRequest(RequestMethods.LoggingSetLevel, new() { ["level"] = level }),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue