diff --git a/docs/concepts/elicitation/elicitation.md b/docs/concepts/elicitation/elicitation.md index 4f0b00cf..539fc534 100644 --- a/docs/concepts/elicitation/elicitation.md +++ b/docs/concepts/elicitation/elicitation.md @@ -1,7 +1,7 @@ --- title: Elicitation author: mikekistler -description: Learn about the telemetry collected by the HttpRepl. +description: Enable interactive AI experiences by requesting user input during tool execution. uid: elicitation --- diff --git a/docs/concepts/logging/logging.md b/docs/concepts/logging/logging.md new file mode 100644 index 00000000..3a83e369 --- /dev/null +++ b/docs/concepts/logging/logging.md @@ -0,0 +1,88 @@ +--- +title: Logging +author: mikekistler +description: How to use the logging feature in the MCP C# SDK. +uid: logging +--- + +MCP servers may expose log messages to clients through the [Logging utility]. + +[Logging utility]: https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/logging + +This document describes how to implement logging in MCP servers and how clients can consume log messages. + +### Logging Levels + +MCP uses the logging levels defined in [RFC 5424](https://tools.ietf.org/html/rfc5424). + +The MCP C# SDK uses the standard .NET [ILogger] and [ILoggerProvider] abstractions, which support a slightly +different set of logging levels. Here's the levels and how they map to standard .NET logging levels. + +| Level | .NET | Description | Example Use Case | +|-----------|------|-----------------------------------|------------------------------| +| debug | ✓ | Detailed debugging information | Function entry/exit points | +| info | ✓ | General informational messages | Operation progress updates | +| notice | | Normal but significant events | Configuration changes | +| warning | ✓ | Warning conditions | Deprecated feature usage | +| error | ✓ | Error conditions | Operation failures | +| critical | ✓ | Critical conditions | System component failures | +| alert | | Action must be taken immediately | Data corruption detected | +| emergency | | System is unusable | | + +**Note:** .NET's [ILogger] also supports a `Trace` level (more verbose than Debug) log level. +As there is no equivalent level in the MCP logging levels, Trace level logs messages are silently +dropped when sending messages to the client. + +[ILogger]: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger +[ILoggerProvider]: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerprovider + +### Server configuration and logging + +MCP servers that implement the Logging utility must declare this in the capabilities sent in the +[Initialization] phase at the beginning of the MCP session. + +[Initialization]: https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle#initialization + +Servers built with the C# SDK always declare the logging capability. The C# SDK provides an extension method +[WithSetLoggingLevelHandler] on [IMcpServerBuilder] to allow the server to perform any special logic it wants to perform +when a client sets the logging level. However, the SDK already takes care of setting the [LoggingLevel] +in the [IMcpServer], so most servers will not need to implement this. + +[IMcpServer]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Server.IMcpServer.html +[IMcpServerBuilder]: https://modelcontextprotocol.github.io/csharp-sdk/api/Microsoft.Extensions.DependencyInjection.IMcpServerBuilder.html +[WithSetLoggingLevelHandler]: https://modelcontextprotocol.github.io/csharp-sdk/api/Microsoft.Extensions.DependencyInjection.McpServerBuilderExtensions.html#Microsoft_Extensions_DependencyInjection_McpServerBuilderExtensions_WithSetLoggingLevelHandler_Microsoft_Extensions_DependencyInjection_IMcpServerBuilder_System_Func_ModelContextProtocol_Server_RequestContext_ModelContextProtocol_Protocol_SetLevelRequestParams__System_Threading_CancellationToken_System_Threading_Tasks_ValueTask_ModelContextProtocol_Protocol_EmptyResult___ +[LoggingLevel]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Server.IMcpServer.html#ModelContextProtocol_Server_IMcpServer_LoggingLevel + +MCP Servers using the MCP C# SDK can obtain an [ILoggerProvider] from the IMcpServer [AsClientLoggerProvider] extension method, +and from that can create an [ILogger] instance for logging messages that should be sent to the MCP client. + +[!code-csharp[](samples/server/Tools/LoggingTools.cs?name=snippet_LoggingConfiguration)] + +[ILoggerProvider]: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerprovider +[AsClientLoggerProvider]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Server.McpServerExtensions.html#ModelContextProtocol_Server_McpServerExtensions_AsClientLoggerProvider_ModelContextProtocol_Server_IMcpServer_ +[ILogger]: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger + +### Client support for logging + +Clients that wish to receive log messages from the server must first check if logging is supported. +This is done by checking the [Logging] property of the [ServerCapabilities] field of [IMcpClient]. + +[IMcpClient]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Client.IMcpClient.html +[ServerCapabilities]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Client.IMcpClient.html#ModelContextProtocol_Client_IMcpClient_ServerCapabilities +[Logging]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Protocol.ServerCapabilities.html#ModelContextProtocol_Protocol_ServerCapabilities_Logging + +[!code-csharp[](samples/client/Program.cs?name=snippet_LoggingCapabilities)] + +If the server supports logging, the client can set the level of log messages it wishes to receive with +the [SetLoggingLevel] method on [IMcpClient]. The `loggingLevel` specified here is an MCP logging level. +See the [Logging Levels](#logging-levels) section above for the mapping between MCP and .NET logging levels. + +[SetLoggingLevel]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Client.McpClientExtensions.html#ModelContextProtocol_Client_McpClientExtensions_SetLoggingLevel_ModelContextProtocol_Client_IMcpClient_Microsoft_Extensions_Logging_LogLevel_System_Threading_CancellationToken_ + +[!code-csharp[](samples/client/Program.cs?name=snippet_LoggingLevel)] + +Lastly, the client must configure a notification handler for [NotificationMethods.LoggingMessageNotification] notifications. + +[NotificationMethods.LoggingMessageNotification]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Protocol.NotificationMethods.html#ModelContextProtocol_Protocol_NotificationMethods_LoggingMessageNotification + +[!code-csharp[](samples/client/Program.cs?name=snippet_LoggingHandler)] diff --git a/docs/concepts/logging/samples/client/LoggingClient.csproj b/docs/concepts/logging/samples/client/LoggingClient.csproj new file mode 100644 index 00000000..2ecfd2cb --- /dev/null +++ b/docs/concepts/logging/samples/client/LoggingClient.csproj @@ -0,0 +1,14 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + diff --git a/docs/concepts/logging/samples/client/Program.cs b/docs/concepts/logging/samples/client/Program.cs new file mode 100644 index 00000000..3d18c715 --- /dev/null +++ b/docs/concepts/logging/samples/client/Program.cs @@ -0,0 +1,67 @@ +using ModelContextProtocol.Protocol; +using ModelContextProtocol.Client; +using System.Text.Json; + +var endpoint = Environment.GetEnvironmentVariable("ENDPOINT") ?? "http://localhost:3001"; + +var clientTransport = new SseClientTransport(new() +{ + Endpoint = new Uri(endpoint), + TransportMode = HttpTransportMode.StreamableHttp, +}); + +await using var mcpClient = await McpClientFactory.CreateAsync(clientTransport); + +// +// Verify that the server supports logging +if (mcpClient.ServerCapabilities.Logging is null) +{ + Console.WriteLine("Server does not support logging."); + return; +} +// + +// Get the first argument if it was specified +var firstArgument = args.Length > 0 ? args[0] : null; + +if (firstArgument is not null) +{ + // Set the logging level to the value from the first argument + if (Enum.TryParse(firstArgument, true, out var loggingLevel)) + { + // + await mcpClient.SetLoggingLevel(loggingLevel); + // + } + else + { + Console.WriteLine($"Invalid logging level: {firstArgument}"); + // Print a list of valid logging levels + Console.WriteLine("Valid logging levels are:"); + foreach (var level in Enum.GetValues()) + { + Console.WriteLine($" - {level}"); + } + } +} + +// +mcpClient.RegisterNotificationHandler(NotificationMethods.LoggingMessageNotification, + (notification, ct) => + { + if (JsonSerializer.Deserialize(notification.Params) is { } ln) + { + Console.WriteLine($"[{ln.Level}] {ln.Logger} {ln.Data}"); + } + else + { + Console.WriteLine($"Received unexpected logging notification: {notification.Params}"); + } + + return default; + }); +// + +// Now call the "logging_tool" tool +await mcpClient.CallToolAsync("logging_tool"); + diff --git a/docs/concepts/logging/samples/server/Logging.csproj b/docs/concepts/logging/samples/server/Logging.csproj new file mode 100644 index 00000000..a27101aa --- /dev/null +++ b/docs/concepts/logging/samples/server/Logging.csproj @@ -0,0 +1,13 @@ + + + + net9.0 + enable + enable + + + + + + + diff --git a/docs/concepts/logging/samples/server/Logging.http b/docs/concepts/logging/samples/server/Logging.http new file mode 100644 index 00000000..3f0f028b --- /dev/null +++ b/docs/concepts/logging/samples/server/Logging.http @@ -0,0 +1,40 @@ +@HostAddress = http://localhost:3001 + +POST {{HostAddress}}/ +Accept: application/json, text/event-stream +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "id": 1, + "method": "initialize", + "params": { + "clientInfo": { + "name": "RestClient", + "version": "0.1.0" + }, + "capabilities": {}, + "protocolVersion": "2025-06-18" + } +} + +### + +@SessionId = JCo3W4Q7KA_evyWoFE5qwA + +### + +POST {{HostAddress}}/ +Accept: application/json, text/event-stream +Content-Type: application/json +MCP-Protocol-Version: 2025-06-18 +Mcp-Session-Id: {{SessionId}} + +{ + "jsonrpc": "2.0", + "id": 2, + "method": "tools/call", + "params": { + "name": "logging_tool" + } +} \ No newline at end of file diff --git a/docs/concepts/logging/samples/server/Program.cs b/docs/concepts/logging/samples/server/Program.cs new file mode 100644 index 00000000..7de039e0 --- /dev/null +++ b/docs/concepts/logging/samples/server/Program.cs @@ -0,0 +1,20 @@ +using Logging.Tools; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddMcpServer() + .WithHttpTransport(options => + options.IdleTimeout = Timeout.InfiniteTimeSpan // Never timeout + ) + .WithTools(); + // .WithSetLoggingLevelHandler(async (ctx, ct) => new EmptyResult()); + +var app = builder.Build(); + +app.UseHttpsRedirection(); + +app.MapMcp(); + +app.Run(); diff --git a/docs/concepts/logging/samples/server/Properties/launchSettings.json b/docs/concepts/logging/samples/server/Properties/launchSettings.json new file mode 100644 index 00000000..c09325b2 --- /dev/null +++ b/docs/concepts/logging/samples/server/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:3001", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7207;http://localhost:3001", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/docs/concepts/logging/samples/server/Tools/LoggingTools.cs b/docs/concepts/logging/samples/server/Tools/LoggingTools.cs new file mode 100644 index 00000000..bb25d2b6 --- /dev/null +++ b/docs/concepts/logging/samples/server/Tools/LoggingTools.cs @@ -0,0 +1,45 @@ +using System.ComponentModel; +using ModelContextProtocol.Protocol; +using ModelContextProtocol.Server; + +namespace Logging.Tools; + +[McpServerToolType] +public class LoggingTools +{ + [McpServerTool, Description("Demonstrates a tool that produces log messages")] + public static async Task LoggingTool( + RequestContext context, + int duration = 10, + int steps = 10) + { + var progressToken = context.Params?.ProgressToken; + var stepDuration = duration / steps; + + // + ILoggerProvider loggerProvider = context.Server.AsClientLoggerProvider(); + ILogger logger = loggerProvider.CreateLogger("LoggingTools"); + // + + for (int i = 1; i <= steps; i++) + { + await Task.Delay(stepDuration * 1000); + + try + { + logger.LogCritical("A critial log message"); + logger.LogError("An error log message"); + logger.LogWarning("A warning log message"); + logger.LogInformation("An informational log message"); + logger.LogDebug("A debug log message"); + logger.LogTrace("A trace log message"); + } + catch (Exception ex) + { + logger.LogError(ex, "An error occurred while logging messages"); + } + } + + return $"Long running tool completed. Duration: {duration} seconds. Steps: {steps}."; + } +} \ No newline at end of file diff --git a/docs/concepts/logging/samples/server/appsettings.Development.json b/docs/concepts/logging/samples/server/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/docs/concepts/logging/samples/server/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/docs/concepts/logging/samples/server/appsettings.json b/docs/concepts/logging/samples/server/appsettings.json new file mode 100644 index 00000000..10f68b8c --- /dev/null +++ b/docs/concepts/logging/samples/server/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/docs/concepts/progress/progress.md b/docs/concepts/progress/progress.md new file mode 100644 index 00000000..0ea2e364 --- /dev/null +++ b/docs/concepts/progress/progress.md @@ -0,0 +1,61 @@ +--- +title: Progress +author: mikekistler +description: +uid: progress +--- +The Model Context Protocol (MCP) supports [progress tracking] for long-running operations through notification messages. + +[progress tracking]: https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress + +Typically progress tracking is supported by server tools that perform operations that take a significant amount of time to complete, such as data processing or complex calculations. +However, progress tracking is defined in the MCP specification as a general feature that can be implemented for any request that is handled by either a server or a client. +This project illustrates the common case of a server tool that performs a long-running operation and sends progress updates to the client. + +### Server Implementation + +When processing a request, the server can use the [sendNotificationAsync] extension method of [IMcpServer] to send progress updates, +specifying `"notifications/progress"` as the notification method name. +The C# SDK registers an instance of [IMcpServer] with the dependency injection container, +so tools can simply add a parameter of type [IMcpServer] to their method signature to access it. +The parameters passed to [sendNotificationAsync] should be an instance of [ProgressNotificationParams], which includes the current progress, total steps, and an optional message. + +[sendNotificationAsync]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.McpEndpointExtensions.html#ModelContextProtocol_McpEndpointExtensions_SendNotificationAsync_ModelContextProtocol_IMcpEndpoint_System_String_System_Threading_CancellationToken_ +[IMcpServer]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Server.IMcpServer.html +[ProgressNotificationParams]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Protocol.ProgressNotificationParams.html + +The server should verify that the caller provided a `progressToken` in the request and include it in the call to [sendNotificationAsync]. The following example demonstrates how a server can send a progress notification: + +[!code-csharp[](samples/server/Tools/LongRunningTools.cs?name=snippet_SendProgress)] + +### Client Implementation + +Clients request progress updates by including a `progressToken` in the parameters of a request. +Note that servers are not required to support progress tracking, so clients should not depend on receiving progress updates. + +In the MCP C# SDK, clients can specify a `progressToken` in the request parameters when calling a tool method. +The client should also provide a notification handler to process "notifications/progress" notifications. +There are two way to do this. The first is to register a notification handler using the [RegisterNotificationHandler] method on the [IMcpClient] instance. A handler registered this way will receive all progress notifications sent by the server. + +[IMcpClient]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Client.IMcpClient.html +[RegisterNotificationHandler]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.IMcpEndpoint.html#ModelContextProtocol_IMcpEndpoint_RegisterNotificationHandler_System_String_System_Func_ModelContextProtocol_Protocol_JsonRpcNotification_System_Threading_CancellationToken_System_Threading_Tasks_ValueTask__ + +```csharp +mcpClient.RegisterNotificationHandler(NotificationMethods.ProgressNotification, + (notification, cancellationToken) => + { + if (JsonSerializer.Deserialize(notification.Params) is { } pn && + pn.ProgressToken == progressToken) + { + // progress.Report(pn.Progress); + Console.WriteLine($"Tool progress: {pn.Progress.Progress} of {pn.Progress.Total} - {pn.Progress.Message}"); + } + return ValueTask.CompletedTask; + }).ConfigureAwait(false); +``` + +The second way is to pass a [Progress] instance to the tool method. The MCP C# SDK will automatically handle progress notifications and report them through the [Progress] instance. This notification handler will only receive progress updates for the specific request that was made, rather than all progress notifications from the server. + +[Progress]: https://learn.microsoft.com/en-us/dotnet/api/system.progress-1 + +[!code-csharp[](samples/client/Program.cs?name=snippet_ProgressHandler)] diff --git a/docs/concepts/progress/samples/client/Program.cs b/docs/concepts/progress/samples/client/Program.cs new file mode 100644 index 00000000..6dde5de9 --- /dev/null +++ b/docs/concepts/progress/samples/client/Program.cs @@ -0,0 +1,52 @@ +using System.Text.Json; +using ModelContextProtocol; +using ModelContextProtocol.Client; +using ModelContextProtocol.Protocol; + +var endpoint = Environment.GetEnvironmentVariable("ENDPOINT") ?? "http://localhost:3001"; + +var clientTransport = new SseClientTransport(new() +{ + Endpoint = new Uri(endpoint), + TransportMode = HttpTransportMode.StreamableHttp, +}); + +McpClientOptions options = new() +{ + ClientInfo = new() + { + Name = "ProgressClient", + Version = "1.0.0" + } +}; + +await using var mcpClient = await McpClientFactory.CreateAsync(clientTransport, options); + +var tools = await mcpClient.ListToolsAsync(); +foreach (var tool in tools) +{ + Console.WriteLine($"Connected to server with tools: {tool.Name}"); +} + +Console.WriteLine($"Calling tool: {tools.First().Name}"); + +// +var progressHandler = new Progress(value => +{ + Console.WriteLine($"Tool progress: {value.Progress} of {value.Total} - {value.Message}"); +}); + +var result = await mcpClient.CallToolAsync(toolName: tools.First().Name, progress: progressHandler); +// + +foreach (var block in result.Content) +{ + if (block is TextContentBlock textBlock) + { + Console.WriteLine(textBlock.Text); + } + else + { + Console.WriteLine($"Received unexpected result content of type {block.GetType()}"); + } +} diff --git a/docs/concepts/progress/samples/client/ProgressClient.csproj b/docs/concepts/progress/samples/client/ProgressClient.csproj new file mode 100644 index 00000000..2ecfd2cb --- /dev/null +++ b/docs/concepts/progress/samples/client/ProgressClient.csproj @@ -0,0 +1,14 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + diff --git a/docs/concepts/progress/samples/server/Program.cs b/docs/concepts/progress/samples/server/Program.cs new file mode 100644 index 00000000..7216b2fe --- /dev/null +++ b/docs/concepts/progress/samples/server/Program.cs @@ -0,0 +1,22 @@ +using Progress.Tools; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddMcpServer() + .WithHttpTransport() + .WithTools(); + +builder.Logging.AddConsole(options => +{ + options.LogToStandardErrorThreshold = LogLevel.Information; +}); + +var app = builder.Build(); + +app.UseHttpsRedirection(); + +app.MapMcp(); + +app.Run(); diff --git a/docs/concepts/progress/samples/server/Progress.csproj b/docs/concepts/progress/samples/server/Progress.csproj new file mode 100644 index 00000000..a27101aa --- /dev/null +++ b/docs/concepts/progress/samples/server/Progress.csproj @@ -0,0 +1,13 @@ + + + + net9.0 + enable + enable + + + + + + + diff --git a/docs/concepts/progress/samples/server/Progress.http b/docs/concepts/progress/samples/server/Progress.http new file mode 100644 index 00000000..3b40db85 --- /dev/null +++ b/docs/concepts/progress/samples/server/Progress.http @@ -0,0 +1,18 @@ +@HostAddress = http://localhost:3001 + +POST {{HostAddress}}/ +Accept: application/json, text/event-stream +Content-Type: application/json +MCP-Protocol-Version: 2025-06-18 + +{ + "jsonrpc": "2.0", + "id": 2, + "method": "tools/call", + "params": { + "_meta": { + "progressToken": "abc123" + }, + "name": "long_running_tool" + } +} diff --git a/docs/concepts/progress/samples/server/Properties/launchSettings.json b/docs/concepts/progress/samples/server/Properties/launchSettings.json new file mode 100644 index 00000000..f5b342d6 --- /dev/null +++ b/docs/concepts/progress/samples/server/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:3001", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7175;http://localhost:3001", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/docs/concepts/progress/samples/server/Tools/LongRunningTools.cs b/docs/concepts/progress/samples/server/Tools/LongRunningTools.cs new file mode 100644 index 00000000..5f3adee7 --- /dev/null +++ b/docs/concepts/progress/samples/server/Tools/LongRunningTools.cs @@ -0,0 +1,44 @@ +using System.ComponentModel; +using ModelContextProtocol; +using ModelContextProtocol.Protocol; +using ModelContextProtocol.Server; + +namespace Progress.Tools; + +[McpServerToolType] +public class LongRunningTools +{ + [McpServerTool, Description("Demonstrates a long running tool with progress updates")] + public static async Task LongRunningTool( + IMcpServer server, + RequestContext context, + int duration = 10, + int steps = 5) + { + var progressToken = context.Params?.ProgressToken; + var stepDuration = duration / steps; + + for (int i = 1; i <= steps; i++) + { + await Task.Delay(stepDuration * 1000); + + // + if (progressToken is not null) + { + await server.SendNotificationAsync("notifications/progress", new ProgressNotificationParams + { + ProgressToken = progressToken.Value, + Progress = new ProgressNotificationValue + { + Progress = i, + Total = steps, + Message = $"Step {i} of {steps} completed.", + }, + }); + } + // + } + + return $"Long running tool completed. Duration: {duration} seconds. Steps: {steps}."; + } +} \ No newline at end of file diff --git a/docs/concepts/progress/samples/server/appsettings.Development.json b/docs/concepts/progress/samples/server/appsettings.Development.json new file mode 100644 index 00000000..0c208ae9 --- /dev/null +++ b/docs/concepts/progress/samples/server/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/docs/concepts/progress/samples/server/appsettings.json b/docs/concepts/progress/samples/server/appsettings.json new file mode 100644 index 00000000..10f68b8c --- /dev/null +++ b/docs/concepts/progress/samples/server/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/docs/concepts/toc.yml b/docs/concepts/toc.yml index 46598cc6..939f21fc 100644 --- a/docs/concepts/toc.yml +++ b/docs/concepts/toc.yml @@ -1,5 +1,15 @@ items: - name: Overview href: index.md -- name: Elicitation - uid: elicitation +- name: Base Protocol + items: + - name: Progress + uid: progress +- name: Client Features + items: + - name: Elicitation + uid: elicitation +- name: Server Features + items: + - name: Logging + uid: logging