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