Skip to content

Commit e63ec21

Browse files
halter73Copilot
andcommitted
Fix relative links and address PR review feedback
- Fix relative links to sessions doc from subdirectories - Fix doc URLs in error messages to use .html extension - Strengthen ConfigureSessionOptions test with two requests proving per-request behavior Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c04f198 commit e63ec21

File tree

5 files changed

+21
-11
lines changed

5 files changed

+21
-11
lines changed

docs/concepts/elicitation/elicitation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ Here's an example implementation of how a console application might handle elici
172172

173173
### URL Elicitation Required Error
174174

175-
When a tool cannot proceed without first completing a URL-mode elicitation (for example, when third-party OAuth authorization is needed), and calling `ElicitAsync` is not practical (for example in [stateless](sessions/sessions.md) mode where server-to-client requests are disabled), the server may throw a <xref:ModelContextProtocol.UrlElicitationRequiredException>. This is a specialized error (JSON-RPC error code `-32042`) that signals to the client that one or more URL-mode elicitations must be completed before the original request can be retried.
175+
When a tool cannot proceed without first completing a URL-mode elicitation (for example, when third-party OAuth authorization is needed), and calling `ElicitAsync` is not practical (for example in [stateless](../sessions/sessions.md) mode where server-to-client requests are disabled), the server may throw a <xref:ModelContextProtocol.UrlElicitationRequiredException>. This is a specialized error (JSON-RPC error code `-32042`) that signals to the client that one or more URL-mode elicitations must be completed before the original request can be retried.
176176

177177
#### Throwing UrlElicitationRequiredException on the Server
178178

docs/concepts/logging/logging.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ MCP servers that implement the Logging utility must declare this in the capabili
4646
[Initialization]: https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization
4747

4848
Servers built with the C# SDK always declare the logging capability. Doing so does not obligate the server
49-
to send log messages&mdash;only allows it. Note that [stateless](sessions/sessions.md) MCP servers might not be capable of sending log
49+
to send log messages&mdash;only allows it. Note that [stateless](../sessions/sessions.md) MCP servers might not be capable of sending log
5050
messages as there might not be an open connection to the client on which the log messages could be sent.
5151

5252
The C# SDK provides an extension method <xref:Microsoft.Extensions.DependencyInjection.McpServerBuilderExtensions.WithSetLoggingLevelHandler*> on <xref:Microsoft.Extensions.DependencyInjection.IMcpServerBuilder> to allow the

docs/concepts/transports/transports.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ app.MapMcp();
131131
app.Run();
132132
```
133133

134-
By default, the HTTP transport uses **stateful sessions** — the server assigns an `Mcp-Session-Id` to each client and tracks session state in memory. For most servers, **stateless mode is recommended** instead. It simplifies deployment, enables horizontal scaling without session affinity, and avoids issues with clients that don't send the `Mcp-Session-Id` header. See [Sessions](sessions/sessions.md) for a detailed guide on when to use stateless vs. stateful mode and how to configure session options.
134+
By default, the HTTP transport uses **stateful sessions** — the server assigns an `Mcp-Session-Id` to each client and tracks session state in memory. For most servers, **stateless mode is recommended** instead. It simplifies deployment, enables horizontal scaling without session affinity, and avoids issues with clients that don't send the `Mcp-Session-Id` header. See [Sessions](../sessions/sessions.md) for a detailed guide on when to use stateless vs. stateful mode and how to configure session options.
135135

136136
A custom route can be specified. For example, the [AspNetCoreMcpPerSessionTools] sample uses a route parameter:
137137

@@ -204,6 +204,6 @@ No additional configuration is needed. When a client connects using the SSE prot
204204
| Process model | Child process | Remote HTTP | Remote HTTP |
205205
| Direction | Bidirectional | Bidirectional | Server→client stream + client→server POST |
206206
| Session resumption | N/A | ✓ (stateful mode) ||
207-
| Stateless mode | N/A | ✓ ([recommended](sessions/sessions.md)) ||
207+
| Stateless mode | N/A | ✓ ([recommended](../sessions/sessions.md)) ||
208208
| Authentication | Process-level | HTTP auth (OAuth, headers) | HTTP auth (OAuth, headers) |
209209
| Best for | Local tools | Remote servers | Legacy compatibility |

src/ModelContextProtocol.AspNetCore/StreamableHttpHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ public async Task HandleDeleteRequestAsync(HttpContext context)
222222
await WriteJsonRpcErrorAsync(context,
223223
"Bad Request: Mcp-Session-Id header is required for GET and DELETE requests when the server is using sessions. " +
224224
"If your server doesn't need sessions, enable stateless mode by setting HttpServerTransportOptions.Stateless = true. " +
225-
"See https://csharp.sdk.modelcontextprotocol.io/concepts/sessions for more details.",
225+
"See https://csharp.sdk.modelcontextprotocol.io/concepts/sessions/sessions.html for more details.",
226226
StatusCodes.Status400BadRequest);
227227
return null;
228228
}
@@ -308,7 +308,7 @@ await WriteJsonRpcErrorAsync(context,
308308
await WriteJsonRpcErrorAsync(context,
309309
"Bad Request: A new session can only be created by an initialize request. Include a valid Mcp-Session-Id header for non-initialize requests, " +
310310
"or enable stateless mode by setting HttpServerTransportOptions.Stateless = true if your server doesn't need sessions. " +
311-
"See https://csharp.sdk.modelcontextprotocol.io/concepts/sessions for more details.",
311+
"See https://csharp.sdk.modelcontextprotocol.io/concepts/sessions/sessions.html for more details.",
312312
StatusCodes.Status400BadRequest);
313313
return null;
314314
}

tests/ModelContextProtocol.AspNetCore.Tests/StatelessServerTests.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -266,14 +266,24 @@ public async Task ConfigureSessionOptions_RunsPerRequest_InStatelessMode()
266266
HttpClient.DefaultRequestHeaders.Accept.Add(new("application/json"));
267267
HttpClient.DefaultRequestHeaders.Accept.Add(new("text/event-stream"));
268268

269-
// First request: set the header so ConfigureSessionOptions creates the tool.
269+
// First request with "alpha" — proves ConfigureSessionOptions runs and configures the tool.
270270
HttpClient.DefaultRequestHeaders.Add("X-Tool-Suffix", "alpha");
271271

272-
await using var client = await ConnectMcpClientAsync();
272+
await using var client1 = await ConnectMcpClientAsync();
273273

274-
var toolResponse = await client.CallToolAsync("dynamicTool", cancellationToken: TestContext.Current.CancellationToken);
275-
var content = Assert.Single(toolResponse.Content);
276-
Assert.Equal("configured-alpha", Assert.IsType<TextContentBlock>(content).Text);
274+
var toolResponse1 = await client1.CallToolAsync("dynamicTool", cancellationToken: TestContext.Current.CancellationToken);
275+
var content1 = Assert.Single(toolResponse1.Content);
276+
Assert.Equal("configured-alpha", Assert.IsType<TextContentBlock>(content1).Text);
277+
278+
// Second request with "beta" — proves ConfigureSessionOptions runs again with new request data.
279+
HttpClient.DefaultRequestHeaders.Remove("X-Tool-Suffix");
280+
HttpClient.DefaultRequestHeaders.Add("X-Tool-Suffix", "beta");
281+
282+
await using var client2 = await ConnectMcpClientAsync();
283+
284+
var toolResponse2 = await client2.CallToolAsync("dynamicTool", cancellationToken: TestContext.Current.CancellationToken);
285+
var content2 = Assert.Single(toolResponse2.Content);
286+
Assert.Equal("configured-beta", Assert.IsType<TextContentBlock>(content2).Text);
277287
}
278288

279289
[McpServerTool(Name = "testSamplingErrors")]

0 commit comments

Comments
 (0)