From c72a5d4110195696da3aa032fa7e086500c2ec32 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Thu, 14 Aug 2025 11:55:54 -0700 Subject: [PATCH 01/11] Add conceptual docs. --- docs/concepts/architecture.md | 6 ++++++ docs/concepts/index.md | 2 ++ docs/concepts/introduction.md | 6 ++++++ docs/concepts/key-concepts.md | 6 ++++++ docs/concepts/toc.yml | 9 +++++++++ docs/docfx.json | 1 + docs/toc.yml | 4 +++- 7 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 docs/concepts/architecture.md create mode 100644 docs/concepts/index.md create mode 100644 docs/concepts/introduction.md create mode 100644 docs/concepts/key-concepts.md create mode 100644 docs/concepts/toc.yml diff --git a/docs/concepts/architecture.md b/docs/concepts/architecture.md new file mode 100644 index 000000000..bc6772e22 --- /dev/null +++ b/docs/concepts/architecture.md @@ -0,0 +1,6 @@ +--- +title: "Architecture" +uid: architecture +--- + +This page describes the architecture of the Model Context Protocol SDK. diff --git a/docs/concepts/index.md b/docs/concepts/index.md new file mode 100644 index 000000000..e038c8996 --- /dev/null +++ b/docs/concepts/index.md @@ -0,0 +1,2 @@ + +Welcome to the conceptual documentation for the Model Context Protocol SDK. Here you'll find high-level overviews, explanations, and guides to help you understand how the SDK implements the Model Context Protocol. diff --git a/docs/concepts/introduction.md b/docs/concepts/introduction.md new file mode 100644 index 000000000..9de3618aa --- /dev/null +++ b/docs/concepts/introduction.md @@ -0,0 +1,6 @@ +--- +title: "Introduction" +uid: introduction +--- + +This page introduces the core ideas behind the Model Context Protocol SDK. diff --git a/docs/concepts/key-concepts.md b/docs/concepts/key-concepts.md new file mode 100644 index 000000000..1c81d3fe7 --- /dev/null +++ b/docs/concepts/key-concepts.md @@ -0,0 +1,6 @@ +--- +title: "Key Concepts" +uid: key-concepts +--- + +This page explains the key concepts of the Model Context Protocol SDK. diff --git a/docs/concepts/toc.yml b/docs/concepts/toc.yml new file mode 100644 index 000000000..4d4600ee1 --- /dev/null +++ b/docs/concepts/toc.yml @@ -0,0 +1,9 @@ +items: +- name: Overview + href: index.md +- name: Introduction + uid: introduction +- name: Architecture + uid: architecture +- name: Key Concepts + uid: key-concepts diff --git a/docs/docfx.json b/docs/docfx.json index 6b4feb833..8ec84a929 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -42,6 +42,7 @@ "_appLogoPath": "images/mcp.svg", "_appFaviconPath": "images/favicon.ico", "_enableSearch": true, + "_appFooter": "", "pdf": false } } diff --git a/docs/toc.yml b/docs/toc.yml index f63a01348..350a2ae3b 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -1,5 +1,7 @@ items: -- name: API Docs +- name: Documentation + href: concepts/index.md +- name: API Reference href: api/ModelContextProtocol.yml - name: Github href: https://github.com/ModelContextProtocol/csharp-sdk \ No newline at end of file From eac1c80d73283eab019310f06490d5032c6f401c Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Thu, 14 Aug 2025 15:27:10 -0700 Subject: [PATCH 02/11] Replace dummy conceptual docs with article on elicitation --- docs/concepts/architecture.md | 6 ------ docs/concepts/introduction.md | 6 ------ docs/concepts/key-concepts.md | 6 ------ docs/concepts/toc.yml | 8 ++------ 4 files changed, 2 insertions(+), 24 deletions(-) delete mode 100644 docs/concepts/architecture.md delete mode 100644 docs/concepts/introduction.md delete mode 100644 docs/concepts/key-concepts.md diff --git a/docs/concepts/architecture.md b/docs/concepts/architecture.md deleted file mode 100644 index bc6772e22..000000000 --- a/docs/concepts/architecture.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: "Architecture" -uid: architecture ---- - -This page describes the architecture of the Model Context Protocol SDK. diff --git a/docs/concepts/introduction.md b/docs/concepts/introduction.md deleted file mode 100644 index 9de3618aa..000000000 --- a/docs/concepts/introduction.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: "Introduction" -uid: introduction ---- - -This page introduces the core ideas behind the Model Context Protocol SDK. diff --git a/docs/concepts/key-concepts.md b/docs/concepts/key-concepts.md deleted file mode 100644 index 1c81d3fe7..000000000 --- a/docs/concepts/key-concepts.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: "Key Concepts" -uid: key-concepts ---- - -This page explains the key concepts of the Model Context Protocol SDK. diff --git a/docs/concepts/toc.yml b/docs/concepts/toc.yml index 4d4600ee1..46598cc61 100644 --- a/docs/concepts/toc.yml +++ b/docs/concepts/toc.yml @@ -1,9 +1,5 @@ items: - name: Overview href: index.md -- name: Introduction - uid: introduction -- name: Architecture - uid: architecture -- name: Key Concepts - uid: key-concepts +- name: Elicitation + uid: elicitation From 25fe0f545dc23eee806b5813bae2c267797af047 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 18 Aug 2025 16:58:20 -0700 Subject: [PATCH 03/11] Apply suggestions from PR review. Co-authored-by: Stephen Halter --- docs/docfx.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docfx.json b/docs/docfx.json index 8ec84a929..fe8a18d95 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -42,7 +42,7 @@ "_appLogoPath": "images/mcp.svg", "_appFaviconPath": "images/favicon.ico", "_enableSearch": true, - "_appFooter": "", + "_disableNextArticle": true, "pdf": false } } From 659b6095051d81d2408b1a012f34b53ce3341ceb Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 18 Aug 2025 16:50:20 -0700 Subject: [PATCH 04/11] Add article on elicitation --- docs/concepts/elicitation/elicitation.md | 49 +++++++ .../samples/client/ElicitationClient.csproj | 14 ++ .../elicitation/samples/client/Program.cs | 121 +++++++++++++++++ .../samples/server/Elicitation.csproj | 13 ++ .../samples/server/Elicitation.http | 58 ++++++++ .../elicitation/samples/server/Program.cs | 24 ++++ .../server/Properties/launchSettings.json | 21 +++ .../samples/server/Tools/InteractiveTools.cs | 126 ++++++++++++++++++ 8 files changed, 426 insertions(+) create mode 100644 docs/concepts/elicitation/elicitation.md create mode 100644 docs/concepts/elicitation/samples/client/ElicitationClient.csproj create mode 100644 docs/concepts/elicitation/samples/client/Program.cs create mode 100644 docs/concepts/elicitation/samples/server/Elicitation.csproj create mode 100644 docs/concepts/elicitation/samples/server/Elicitation.http create mode 100644 docs/concepts/elicitation/samples/server/Program.cs create mode 100644 docs/concepts/elicitation/samples/server/Properties/launchSettings.json create mode 100644 docs/concepts/elicitation/samples/server/Tools/InteractiveTools.cs diff --git a/docs/concepts/elicitation/elicitation.md b/docs/concepts/elicitation/elicitation.md new file mode 100644 index 000000000..da6b91d16 --- /dev/null +++ b/docs/concepts/elicitation/elicitation.md @@ -0,0 +1,49 @@ +--- +title: Elicitation +author: mikekistler +description: Learn about the telemetry collected by the HttpRepl. +uid: elicitation +--- + +The **elicitation** feature allows servers to request additional information from users during interactions. This enables more dynamic and interactive AI experiences, making it easier to gather necessary context before executing tasks. + +## Server Support for Elicitation + +Servers request structured data from users with the [ElicitAsync] extension method on [IMcpServer]. +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. + +[ElicitAsync]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Server.McpServerExtensions.html#ModelContextProtocol_Server_McpServerExtensions_ElicitAsync_ModelContextProtocol_Server_IMcpServer_ModelContextProtocol_Protocol_ElicitRequestParams_System_Threading_CancellationToken_ +[IMcpServer]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Server.IMcpServer.html + +The MCP Server must specify the schema of each input value it is requesting from the user. +Only primitive types (string, number, boolean) are supported for elicitation requests. +The schema may include a description to help the user understand what is being requested. + +The server can request a single input or multiple inputs at once. +To help distinguish multiple inputs, each input has a unique name. + +The following example demonstrates how a server could request a boolean response from the user. + +[!code-csharp[](samples/server/Tools/InteractiveTools.cs?name=snippet_GuessTheNumber)] + +## Client Support for Elicitation + +Elicitation is an optional feature so clients declare their support for it in their capabilities as part of the `initialize` request. In the MCP C# SDK, this is done by configuring an [ElicitationHandler] in the [McpClientOptions]: + +[ElicitationHandler]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Protocol.ElicitationCapability.html#ModelContextProtocol_Protocol_ElicitationCapability_ElicitationHandler +[McpClientOptions]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Client.McpClientOptions.html + +[!code-csharp[](samples/client/Program.cs?name=snippet_McpInitialize)] + +The ElicitationHandler is an asynchronous method that will be called when the server requests additional information. +The ElicitationHandler must request input from the user and return the data in a format that matches the requested schema. +This will be highly dependent on the client application and how it interacts with the user. + +If the user provides the requested information, the ElicitationHandler should return an [ElicitResult] with the action set to "accept" and the content containing the user's input. +If the user does not provide the requested information, the ElicitationHandler should return an [ElicitResult] with the action set to "reject" and no content. + +Below is an example of how a console application might handle elicitation requests. +Here's an example implementation: + +[!code-csharp[](samples/client/Program.cs?name=snippet_ElicitationHandler)] diff --git a/docs/concepts/elicitation/samples/client/ElicitationClient.csproj b/docs/concepts/elicitation/samples/client/ElicitationClient.csproj new file mode 100644 index 000000000..e8e10376e --- /dev/null +++ b/docs/concepts/elicitation/samples/client/ElicitationClient.csproj @@ -0,0 +1,14 @@ + + + + Exe + net9.0 + enable + enable + + + + + + + diff --git a/docs/concepts/elicitation/samples/client/Program.cs b/docs/concepts/elicitation/samples/client/Program.cs new file mode 100644 index 000000000..02fef06c7 --- /dev/null +++ b/docs/concepts/elicitation/samples/client/Program.cs @@ -0,0 +1,121 @@ +using System.Text.Json; +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 = "ElicitationClient", + Version = "1.0.0" + }, + Capabilities = new() + { + Elicitation = new() + { + ElicitationHandler = HandleElicitationAsync + } + } +}; + +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 result = await mcpClient.CallToolAsync(toolName: tools.First().Name); + +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()}"); + } +} + +// +async ValueTask HandleElicitationAsync(ElicitRequestParams? requestParams, CancellationToken token) +{ + // Bail out if the requestParams is null or if the requested schema has no properties + if (requestParams?.RequestedSchema?.Properties == null) + { + return new ElicitResult(); + } + + // Process the elicitation request + if (requestParams?.Message is not null) + { + Console.WriteLine(requestParams.Message); + } + + var content = new Dictionary(); + + // Loop through requestParams.requestSchema.Properties dictionary requesting values for each property + foreach (var property in requestParams.RequestedSchema.Properties) + { + if (property.Value is ElicitRequestParams.BooleanSchema booleanSchema) + { + Console.Write($"{booleanSchema.Description}: "); + var clientInput = Console.ReadLine(); + bool parsedBool; + + // Try standard boolean parsing first + if (bool.TryParse(clientInput, out parsedBool)) + { + content[property.Key] = JsonSerializer.Deserialize(JsonSerializer.Serialize(parsedBool)); + } + // Also accept "yes"/"no" as valid boolean inputs + else if (string.Equals(clientInput?.Trim(), "yes", StringComparison.OrdinalIgnoreCase)) + { + content[property.Key] = JsonSerializer.Deserialize(JsonSerializer.Serialize(true)); + } + else if (string.Equals(clientInput?.Trim(), "no", StringComparison.OrdinalIgnoreCase)) + { + content[property.Key] = JsonSerializer.Deserialize(JsonSerializer.Serialize(false)); + } + } + else if (property.Value is ElicitRequestParams.NumberSchema numberSchema) + { + Console.Write($"{numberSchema.Description}: "); + var clientInput = Console.ReadLine(); + double parsedNumber; + if (double.TryParse(clientInput, out parsedNumber)) + { + content[property.Key] = JsonSerializer.Deserialize(JsonSerializer.Serialize(parsedNumber)); + } + } + else if (property.Value is ElicitRequestParams.StringSchema stringSchema) + { + Console.Write($"{stringSchema.Description}: "); + var clientInput = Console.ReadLine(); + content[property.Key] = JsonSerializer.Deserialize(JsonSerializer.Serialize(clientInput)); + } + } + + // Return the user's input + return new ElicitResult + { + Action = "accept", + Content = content + }; +} +// diff --git a/docs/concepts/elicitation/samples/server/Elicitation.csproj b/docs/concepts/elicitation/samples/server/Elicitation.csproj new file mode 100644 index 000000000..a27101aa0 --- /dev/null +++ b/docs/concepts/elicitation/samples/server/Elicitation.csproj @@ -0,0 +1,13 @@ + + + + net9.0 + enable + enable + + + + + + + diff --git a/docs/concepts/elicitation/samples/server/Elicitation.http b/docs/concepts/elicitation/samples/server/Elicitation.http new file mode 100644 index 000000000..04dcdb343 --- /dev/null +++ b/docs/concepts/elicitation/samples/server/Elicitation.http @@ -0,0 +1,58 @@ +@HostAddress = http://localhost:3001 + +# No session ID, so elicitation capabilities not declared. + +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": { + "name": "guess_the_number" + } +} + +### + +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": { + "elicitation": {} + }, + "protocolVersion": "2025-06-18" + } +} + +### + +@SessionId = lgEu87uKTy8kLffZayO5rQ + +POST {{HostAddress}}/ +Accept: application/json, text/event-stream +Content-Type: application/json +Mcp-Session-Id: {{SessionId}} +MCP-Protocol-Version: 2025-06-18 + +{ + "jsonrpc": "2.0", + "id": 2, + "method": "tools/call", + "params": { + "name": "guess_the_number" + } +} diff --git a/docs/concepts/elicitation/samples/server/Program.cs b/docs/concepts/elicitation/samples/server/Program.cs new file mode 100644 index 000000000..8c6862464 --- /dev/null +++ b/docs/concepts/elicitation/samples/server/Program.cs @@ -0,0 +1,24 @@ +using Elicitation.Tools; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. + +builder.Services.AddMcpServer() + .WithHttpTransport(options => + options.IdleTimeout = Timeout.InfiniteTimeSpan // Never timeout + ) + .WithTools(); + +builder.Logging.AddConsole(options => +{ + options.LogToStandardErrorThreshold = LogLevel.Information; +}); + +var app = builder.Build(); + +app.UseHttpsRedirection(); + +app.MapMcp(); + +app.Run(); diff --git a/docs/concepts/elicitation/samples/server/Properties/launchSettings.json b/docs/concepts/elicitation/samples/server/Properties/launchSettings.json new file mode 100644 index 000000000..74cf457ef --- /dev/null +++ b/docs/concepts/elicitation/samples/server/Properties/launchSettings.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:3001", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7133;http://localhost:3001", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + } + } + } +} \ No newline at end of file diff --git a/docs/concepts/elicitation/samples/server/Tools/InteractiveTools.cs b/docs/concepts/elicitation/samples/server/Tools/InteractiveTools.cs new file mode 100644 index 000000000..b6a75e005 --- /dev/null +++ b/docs/concepts/elicitation/samples/server/Tools/InteractiveTools.cs @@ -0,0 +1,126 @@ +using System.ComponentModel; +using System.Text.Json; +using ModelContextProtocol; +using ModelContextProtocol.Protocol; +using ModelContextProtocol.Server; +using static ModelContextProtocol.Protocol.ElicitRequestParams; + +namespace Elicitation.Tools; + +[McpServerToolType] +public sealed class InteractiveTools +{ + // + [McpServerTool, Description("A simple game where the user has to guess a number between 1 and 10.")] + public async Task GuessTheNumber( + IMcpServer server, // Get the McpServer from DI container + CancellationToken token + ) + { + // Check if the client supports elicitation + if (server.ClientCapabilities?.Elicitation == null) + { + // fail the tool call + throw new McpException("Client does not support elicitation"); + } + + // First ask the user if they want to play + var playSchema = new RequestSchema + { + Properties = + { + ["Answer"] = new BooleanSchema() + } + }; + + var playResponse = await server.ElicitAsync(new ElicitRequestParams + { + Message = "Do you want to play a game?", + RequestedSchema = playSchema + }, token); + + // Check if user wants to play + if (playResponse.Action != "accept" || playResponse.Content?["Answer"].ValueKind != JsonValueKind.True) + { + return "Maybe next time!"; + } + // + + // Now ask the user to enter their name + var nameSchema = new RequestSchema + { + Properties = + { + ["Name"] = new StringSchema() + { + Description = "Name of the player", + MinLength = 2, + MaxLength = 50, + } + } + }; + + var nameResponse = await server.ElicitAsync(new ElicitRequestParams + { + Message = "What is your name?", + RequestedSchema = nameSchema + }, token); + + if (nameResponse.Action != "accept") + { + return "Maybe next time!"; + } + string? playerName = nameResponse.Content?["Name"].GetString(); + + // Generate a random number between 1 and 10 + Random random = new Random(); + int targetNumber = random.Next(1, 11); // 1 to 10 inclusive + int attempts = 0; + + var message = "Guess a number between 1 and 10"; + + while (true) + { + attempts++; + + var guessSchema = new RequestSchema + { + Properties = + { + ["Guess"] = new NumberSchema() + { + Type = "integer", + Minimum = 1, + Maximum = 10, + } + } + }; + + var guessResponse = await server.ElicitAsync(new ElicitRequestParams + { + Message = message, + RequestedSchema = guessSchema + }, token); + + if (guessResponse.Action != "accept") + { + return "Maybe next time!"; + } + int guess = (int)(guessResponse.Content?["Guess"].GetInt32())!; + + // Check if the guess is correct + if (guess == targetNumber) + { + return $"Congratulations {playerName}! You guessed the number {targetNumber} in {attempts} attempts!"; + } + else if (guess < targetNumber) + { + message = $"Your guess is too low! Try again (Attempt #{attempts}):"; + } + else + { + message = $"Your guess is too high! Try again (Attempt #{attempts}):"; + } + } + } +} \ No newline at end of file From afca59da004009d38d4b96699745fd7703663717 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 18 Aug 2025 17:12:11 -0700 Subject: [PATCH 05/11] Fix markdown link errors maybe? --- docs/concepts/elicitation/elicitation.md | 8 +++++--- docs/concepts/elicitation/samples/client/Program.cs | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/concepts/elicitation/elicitation.md b/docs/concepts/elicitation/elicitation.md index da6b91d16..e0d6531cc 100644 --- a/docs/concepts/elicitation/elicitation.md +++ b/docs/concepts/elicitation/elicitation.md @@ -25,7 +25,7 @@ To help distinguish multiple inputs, each input has a unique name. The following example demonstrates how a server could request a boolean response from the user. -[!code-csharp[](samples/server/Tools/InteractiveTools.cs?name=snippet_GuessTheNumber)] +[!code-csharp[](./samples/server/Tools/InteractiveTools.cs?name=snippet_GuessTheNumber)] ## Client Support for Elicitation @@ -34,7 +34,7 @@ Elicitation is an optional feature so clients declare their support for it in th [ElicitationHandler]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Protocol.ElicitationCapability.html#ModelContextProtocol_Protocol_ElicitationCapability_ElicitationHandler [McpClientOptions]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Client.McpClientOptions.html -[!code-csharp[](samples/client/Program.cs?name=snippet_McpInitialize)] +[!code-csharp[](./samples/client/Program.cs?name=snippet_McpInitialize)] The ElicitationHandler is an asynchronous method that will be called when the server requests additional information. The ElicitationHandler must request input from the user and return the data in a format that matches the requested schema. @@ -43,7 +43,9 @@ This will be highly dependent on the client application and how it interacts wit If the user provides the requested information, the ElicitationHandler should return an [ElicitResult] with the action set to "accept" and the content containing the user's input. If the user does not provide the requested information, the ElicitationHandler should return an [ElicitResult] with the action set to "reject" and no content. +[ElicitResult]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Protocol.ElicitResult.html + Below is an example of how a console application might handle elicitation requests. Here's an example implementation: -[!code-csharp[](samples/client/Program.cs?name=snippet_ElicitationHandler)] +[!code-csharp[](./samples/client/Program.cs?name=snippet_ElicitationHandler)] diff --git a/docs/concepts/elicitation/samples/client/Program.cs b/docs/concepts/elicitation/samples/client/Program.cs index 02fef06c7..5405a61ba 100644 --- a/docs/concepts/elicitation/samples/client/Program.cs +++ b/docs/concepts/elicitation/samples/client/Program.cs @@ -28,7 +28,7 @@ }; await using var mcpClient = await McpClientFactory.CreateAsync(clientTransport, options); -// +// var tools = await mcpClient.ListToolsAsync(); foreach (var tool in tools) From 95bcc02d473bea9c8afac89de89f01ab0d8ad095 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 18 Aug 2025 19:00:56 -0700 Subject: [PATCH 06/11] Don't link check DocFX alert blocks --- .github/workflows/markdown-link-check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/markdown-link-check.yml b/.github/workflows/markdown-link-check.yml index 6a49bec6a..07324a11e 100644 --- a/.github/workflows/markdown-link-check.yml +++ b/.github/workflows/markdown-link-check.yml @@ -21,5 +21,5 @@ jobs: - name: Markup Link Checker (mlc) uses: becheran/mlc@c925f90a9a25e16e4c4bfa29058f6f9ffa9f0d8c # v0.21.0 with: - # Ignore external links that result in 403 errors during CI. Do not warn for redirects where we want to keep the vanity URL in the markdown or for GitHub links that redirect to the login. - args: --ignore-links "https://www.anthropic.com/*,https://hackerone.com/anthropic-vdp/*" --do-not-warn-for-redirect-to "https://modelcontextprotocol.io/*,https://github.com/login?*" ./ + # Ignore external links that result in 403 errors during CI. Do not warn for redirects where we want to keep the vanity URL in the markdown or for GitHub links that redirect to the login, and DocFX alert blocks. + args: --ignore-links "https://www.anthropic.com/*,https://hackerone.com/anthropic-vdp/*" --do-not-warn-for-redirect-to "https://modelcontextprotocol.io/*,https://github.com/login?*" --ignore-links "\[!\w+\]" ./docs From e8c7589eaaf53a776f108e3d46826f24b235294d Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 18 Aug 2025 20:45:29 -0700 Subject: [PATCH 07/11] try again --- .github/workflows/markdown-link-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/markdown-link-check.yml b/.github/workflows/markdown-link-check.yml index 07324a11e..983ad485c 100644 --- a/.github/workflows/markdown-link-check.yml +++ b/.github/workflows/markdown-link-check.yml @@ -22,4 +22,4 @@ jobs: uses: becheran/mlc@c925f90a9a25e16e4c4bfa29058f6f9ffa9f0d8c # v0.21.0 with: # Ignore external links that result in 403 errors during CI. Do not warn for redirects where we want to keep the vanity URL in the markdown or for GitHub links that redirect to the login, and DocFX alert blocks. - args: --ignore-links "https://www.anthropic.com/*,https://hackerone.com/anthropic-vdp/*" --do-not-warn-for-redirect-to "https://modelcontextprotocol.io/*,https://github.com/login?*" --ignore-links "\[!\w+\]" ./docs + args: --ignore-links "https://www.anthropic.com/*,https://hackerone.com/anthropic-vdp/*" --do-not-warn-for-redirect-to "https://modelcontextprotocol.io/*,https://github.com/login?*" --ignore-links "\[!\w+(\[\]\(.*\?name=snippet_.*\))?\]" ./docs From dabf3e5f21b46bdf724f5ff2d599d9aadfaac4b1 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 18 Aug 2025 21:02:25 -0700 Subject: [PATCH 08/11] try again --- .github/workflows/markdown-link-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/markdown-link-check.yml b/.github/workflows/markdown-link-check.yml index 983ad485c..e2069ddb2 100644 --- a/.github/workflows/markdown-link-check.yml +++ b/.github/workflows/markdown-link-check.yml @@ -22,4 +22,4 @@ jobs: uses: becheran/mlc@c925f90a9a25e16e4c4bfa29058f6f9ffa9f0d8c # v0.21.0 with: # Ignore external links that result in 403 errors during CI. Do not warn for redirects where we want to keep the vanity URL in the markdown or for GitHub links that redirect to the login, and DocFX alert blocks. - args: --ignore-links "https://www.anthropic.com/*,https://hackerone.com/anthropic-vdp/*" --do-not-warn-for-redirect-to "https://modelcontextprotocol.io/*,https://github.com/login?*" --ignore-links "\[!\w+(\[\]\(.*\?name=snippet_.*\))?\]" ./docs + args: --ignore-links "https://www.anthropic.com/*,https://hackerone.com/anthropic-vdp/*" --do-not-warn-for-redirect-to "https://modelcontextprotocol.io/*,https://github.com/login?*" --ignore-links ".*\?name=snippet_.*" ./docs From f5aff74d27bab81aa46753da013766c0f8978c89 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 18 Aug 2025 21:29:33 -0700 Subject: [PATCH 09/11] try again --- .github/workflows/markdown-link-check.yml | 2 +- docs/concepts/elicitation/elicitation.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/markdown-link-check.yml b/.github/workflows/markdown-link-check.yml index e2069ddb2..bae3ff6a7 100644 --- a/.github/workflows/markdown-link-check.yml +++ b/.github/workflows/markdown-link-check.yml @@ -22,4 +22,4 @@ jobs: uses: becheran/mlc@c925f90a9a25e16e4c4bfa29058f6f9ffa9f0d8c # v0.21.0 with: # Ignore external links that result in 403 errors during CI. Do not warn for redirects where we want to keep the vanity URL in the markdown or for GitHub links that redirect to the login, and DocFX alert blocks. - args: --ignore-links "https://www.anthropic.com/*,https://hackerone.com/anthropic-vdp/*" --do-not-warn-for-redirect-to "https://modelcontextprotocol.io/*,https://github.com/login?*" --ignore-links ".*\?name=snippet_.*" ./docs + args: --ignore-links "https://www.anthropic.com/*,https://hackerone.com/anthropic-vdp/*" --do-not-warn-for-redirect-to "https://modelcontextprotocol.io/*,https://github.com/login?*" --ignore-links "samples.*\?name=snippet_.*" ./docs diff --git a/docs/concepts/elicitation/elicitation.md b/docs/concepts/elicitation/elicitation.md index e0d6531cc..4f0b00cff 100644 --- a/docs/concepts/elicitation/elicitation.md +++ b/docs/concepts/elicitation/elicitation.md @@ -25,7 +25,7 @@ To help distinguish multiple inputs, each input has a unique name. The following example demonstrates how a server could request a boolean response from the user. -[!code-csharp[](./samples/server/Tools/InteractiveTools.cs?name=snippet_GuessTheNumber)] +[!code-csharp[](samples/server/Tools/InteractiveTools.cs?name=snippet_GuessTheNumber)] ## Client Support for Elicitation @@ -34,7 +34,7 @@ Elicitation is an optional feature so clients declare their support for it in th [ElicitationHandler]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Protocol.ElicitationCapability.html#ModelContextProtocol_Protocol_ElicitationCapability_ElicitationHandler [McpClientOptions]: https://modelcontextprotocol.github.io/csharp-sdk/api/ModelContextProtocol.Client.McpClientOptions.html -[!code-csharp[](./samples/client/Program.cs?name=snippet_McpInitialize)] +[!code-csharp[](samples/client/Program.cs?name=snippet_McpInitialize)] The ElicitationHandler is an asynchronous method that will be called when the server requests additional information. The ElicitationHandler must request input from the user and return the data in a format that matches the requested schema. @@ -48,4 +48,4 @@ If the user does not provide the requested information, the ElicitationHandler s Below is an example of how a console application might handle elicitation requests. Here's an example implementation: -[!code-csharp[](./samples/client/Program.cs?name=snippet_ElicitationHandler)] +[!code-csharp[](samples/client/Program.cs?name=snippet_ElicitationHandler)] From 227bf23cf413ec93bd2414206b1398a3841b292f Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 18 Aug 2025 21:48:30 -0700 Subject: [PATCH 10/11] oh my --- .github/workflows/markdown-link-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/markdown-link-check.yml b/.github/workflows/markdown-link-check.yml index bae3ff6a7..36f392a68 100644 --- a/.github/workflows/markdown-link-check.yml +++ b/.github/workflows/markdown-link-check.yml @@ -22,4 +22,4 @@ jobs: uses: becheran/mlc@c925f90a9a25e16e4c4bfa29058f6f9ffa9f0d8c # v0.21.0 with: # Ignore external links that result in 403 errors during CI. Do not warn for redirects where we want to keep the vanity URL in the markdown or for GitHub links that redirect to the login, and DocFX alert blocks. - args: --ignore-links "https://www.anthropic.com/*,https://hackerone.com/anthropic-vdp/*" --do-not-warn-for-redirect-to "https://modelcontextprotocol.io/*,https://github.com/login?*" --ignore-links "samples.*\?name=snippet_.*" ./docs + args: --ignore-links "https://www.anthropic.com/*,https://hackerone.com/anthropic-vdp/*" --do-not-warn-for-redirect-to "https://modelcontextprotocol.io/*,https://github.com/login?*" --ignore-links "*samples/*?name=snippet_*" ./docs From b109847553c2296fdc2246be1c48b523f789e8a7 Mon Sep 17 00:00:00 2001 From: Mike Kistler Date: Mon, 18 Aug 2025 21:57:20 -0700 Subject: [PATCH 11/11] Fixup doc --- .github/workflows/markdown-link-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/markdown-link-check.yml b/.github/workflows/markdown-link-check.yml index 36f392a68..b69bbc440 100644 --- a/.github/workflows/markdown-link-check.yml +++ b/.github/workflows/markdown-link-check.yml @@ -21,5 +21,5 @@ jobs: - name: Markup Link Checker (mlc) uses: becheran/mlc@c925f90a9a25e16e4c4bfa29058f6f9ffa9f0d8c # v0.21.0 with: - # Ignore external links that result in 403 errors during CI. Do not warn for redirects where we want to keep the vanity URL in the markdown or for GitHub links that redirect to the login, and DocFX alert blocks. + # Ignore external links that result in 403 errors during CI. Do not warn for redirects where we want to keep the vanity URL in the markdown or for GitHub links that redirect to the login, and DocFX snippet links. args: --ignore-links "https://www.anthropic.com/*,https://hackerone.com/anthropic-vdp/*" --do-not-warn-for-redirect-to "https://modelcontextprotocol.io/*,https://github.com/login?*" --ignore-links "*samples/*?name=snippet_*" ./docs