Skip to content

Commit 616bd2a

Browse files
Merge branch 'main' into use-lowercase-derived-uritemplaes
2 parents 4e70cc1 + 283a052 commit 616bd2a

22 files changed

Lines changed: 208 additions & 42 deletions

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<LangVersion>13</LangVersion>
3+
<LangVersion>preview</LangVersion>
44
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>

samples/QuickstartClient/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ static void PromptForInput()
8888
{
8989
[var script] when script.EndsWith(".py") => ("python", args),
9090
[var script] when script.EndsWith(".js") => ("node", args),
91-
[var script] when Directory.Exists(script) || (File.Exists(script) && script.EndsWith(".csproj")) => ("dotnet", ["run", "--project", script, "--no-build"]),
92-
_ => ("dotnet", ["run", "--project", "../../../../QuickstartWeatherServer", "--no-build"])
91+
[var script] when Directory.Exists(script) || (File.Exists(script) && script.EndsWith(".csproj")) => ("dotnet", ["run", "--project", script]),
92+
_ => ("dotnet", ["run", "--project", "../QuickstartWeatherServer"])
9393
};
9494
}

src/Common/Polyfills/System/Runtime/CompilerServices/DefaultInterpolatedStringHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace System.Runtime.CompilerServices
1313
{
1414
/// <summary>Provides a handler used by the language compiler to process interpolated strings into <see cref="string"/> instances.</summary>
15-
public ref struct DefaultInterpolatedStringHandler
15+
internal ref struct DefaultInterpolatedStringHandler
1616
{
1717
// Implementation note:
1818
// As this type lives in CompilerServices and is only intended to be targeted by the compiler,

src/Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<PackageProjectUrl>https://github.com/modelcontextprotocol/csharp-sdk</PackageProjectUrl>
66
<RepositoryUrl>https://github.com/modelcontextprotocol/csharp-sdk</RepositoryUrl>
77
<RepositoryType>git</RepositoryType>
8-
<VersionPrefix>0.2.0</VersionPrefix>
9-
<VersionSuffix>preview.4</VersionSuffix>
8+
<VersionPrefix>0.3.0</VersionPrefix>
9+
<VersionSuffix>preview.1</VersionSuffix>
1010
<Authors>ModelContextProtocolOfficial</Authors>
1111
<Copyright>© Anthropic and Contributors.</Copyright>
1212
<PackageTags>ModelContextProtocol;mcp;ai;llm</PackageTags>

src/ModelContextProtocol.AspNetCore/HttpServerTransportOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace ModelContextProtocol.AspNetCore;
66
/// <summary>
77
/// Configuration options for <see cref="M:McpEndpointRouteBuilderExtensions.MapMcp"/>.
88
/// which implements the Streaming HTTP transport for the Model Context Protocol.
9-
/// See the protocol specification for details on the Streamable HTTP transport. <see href="https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http"/>
9+
/// See the protocol specification for details on the Streamable HTTP transport. <see href="https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http"/>
1010
/// </summary>
1111
public class HttpServerTransportOptions
1212
{
@@ -28,7 +28,7 @@ public class HttpServerTransportOptions
2828
/// </summary>
2929
/// <remarks>
3030
/// If <see langword="true"/>, the "/sse" endpoint will be disabled, and client information will be round-tripped as part
31-
/// of the "mcp-session-id" header instead of stored in memory. Unsolicited server-to-client messages and all server-to-client
31+
/// of the "MCP-Session-Id" header instead of stored in memory. Unsolicited server-to-client messages and all server-to-client
3232
/// requests are also unsupported, because any responses may arrive at another ASP.NET Core application process.
3333
/// Client sampling and roots capabilities are also disabled in stateless mode, because the server cannot make requests.
3434
/// Defaults to <see langword="false"/>.

src/ModelContextProtocol.AspNetCore/McpEndpointRouteBuilderExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public static class McpEndpointRouteBuilderExtensions
1515
{
1616
/// <summary>
1717
/// Sets up endpoints for handling MCP Streamable HTTP transport.
18-
/// See <see href="https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http">the 2025-03-26 protocol specification</see> for details about the Streamable HTTP transport.
18+
/// See <see href="https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http">the 2025-06-18 protocol specification</see> for details about the Streamable HTTP transport.
1919
/// Also maps legacy SSE endpoints for backward compatibility at the path "/sse" and "/message". <see href="https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse">the 2024-11-05 protocol specification</see> for details about the HTTP with SSE transport.
2020
/// </summary>
2121
/// <param name="endpoints">The web application to attach MCP HTTP endpoints.</param>

src/ModelContextProtocol.AspNetCore/StreamableHttpHandler.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ internal sealed class StreamableHttpHandler(
2626
ILoggerFactory loggerFactory,
2727
IServiceProvider applicationServices)
2828
{
29+
private const string McpSessionIdHeaderName = "Mcp-Session-Id";
2930
private static readonly JsonTypeInfo<JsonRpcError> s_errorTypeInfo = GetRequiredJsonTypeInfo<JsonRpcError>();
3031

3132
public ConcurrentDictionary<string, HttpMcpSession<StreamableHttpServerTransport>> Sessions { get; } = new(StringComparer.Ordinal);
@@ -70,8 +71,8 @@ await WriteJsonRpcErrorAsync(context,
7071
}
7172
finally
7273
{
73-
// Stateless sessions are 1:1 with HTTP requests and are outlived by the MCP session tracked by the mcp-session-id.
74-
// Non-stateless sessions are 1:1 with the mcp-session-id and outlive the POST request.
74+
// Stateless sessions are 1:1 with HTTP requests and are outlived by the MCP session tracked by the Mcp-Session-Id.
75+
// Non-stateless sessions are 1:1 with the Mcp-Session-Id and outlive the POST request.
7576
// Non-stateless sessions get disposed by a DELETE request or the IdleTrackingBackgroundService.
7677
if (HttpServerTransportOptions.Stateless)
7778
{
@@ -90,7 +91,7 @@ await WriteJsonRpcErrorAsync(context,
9091
return;
9192
}
9293

93-
var sessionId = context.Request.Headers["mcp-session-id"].ToString();
94+
var sessionId = context.Request.Headers[McpSessionIdHeaderName].ToString();
9495
var session = await GetSessionAsync(context, sessionId);
9596
if (session is null)
9697
{
@@ -117,7 +118,7 @@ await WriteJsonRpcErrorAsync(context,
117118

118119
public async Task HandleDeleteRequestAsync(HttpContext context)
119120
{
120-
var sessionId = context.Request.Headers["mcp-session-id"].ToString();
121+
var sessionId = context.Request.Headers[McpSessionIdHeaderName].ToString();
121122
if (Sessions.TryRemove(sessionId, out var session))
122123
{
123124
await session.DisposeAsync();
@@ -157,14 +158,14 @@ await WriteJsonRpcErrorAsync(context,
157158
return null;
158159
}
159160

160-
context.Response.Headers["mcp-session-id"] = session.Id;
161+
context.Response.Headers[McpSessionIdHeaderName] = session.Id;
161162
context.Features.Set(session.Server);
162163
return session;
163164
}
164165

165166
private async ValueTask<HttpMcpSession<StreamableHttpServerTransport>?> GetOrCreateSessionAsync(HttpContext context)
166167
{
167-
var sessionId = context.Request.Headers["mcp-session-id"].ToString();
168+
var sessionId = context.Request.Headers[McpSessionIdHeaderName].ToString();
168169

169170
if (string.IsNullOrEmpty(sessionId))
170171
{
@@ -188,11 +189,11 @@ private async ValueTask<HttpMcpSession<StreamableHttpServerTransport>> StartNewS
188189
{
189190
SessionId = sessionId,
190191
};
191-
context.Response.Headers["mcp-session-id"] = sessionId;
192+
context.Response.Headers[McpSessionIdHeaderName] = sessionId;
192193
}
193194
else
194195
{
195-
// "(uninitialized stateless id)" is not written anywhere. We delay writing the mcp-session-id
196+
// "(uninitialized stateless id)" is not written anywhere. We delay writing the MCP-Session-Id
196197
// until after we receive the initialize request with the client info we need to serialize.
197198
sessionId = "(uninitialized stateless id)";
198199
transport = new()
@@ -204,7 +205,7 @@ private async ValueTask<HttpMcpSession<StreamableHttpServerTransport>> StartNewS
204205

205206
var session = await CreateSessionAsync(context, transport, sessionId);
206207

207-
// The HttpMcpSession is not stored between requests in stateless mode. Instead, the session is recreated from the mcp-session-id.
208+
// The HttpMcpSession is not stored between requests in stateless mode. Instead, the session is recreated from the MCP-Session-Id.
208209
if (!HttpServerTransportOptions.Stateless)
209210
{
210211
if (!Sessions.TryAdd(sessionId, session))
@@ -299,7 +300,7 @@ private void ScheduleStatelessSessionIdWrite(HttpContext context, StreamableHttp
299300

300301
var sessionJson = JsonSerializer.Serialize(statelessId, StatelessSessionIdJsonContext.Default.StatelessSessionId);
301302
transport.SessionId = Protector.Protect(sessionJson);
302-
context.Response.Headers["mcp-session-id"] = transport.SessionId;
303+
context.Response.Headers[McpSessionIdHeaderName] = transport.SessionId;
303304
return ValueTask.CompletedTask;
304305
};
305306
}

src/ModelContextProtocol.Core/Client/SseClientSessionTransport.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public override async Task SendMessageAsync(
9191
{
9292
Content = content,
9393
};
94-
StreamableHttpClientSessionTransport.CopyAdditionalHeaders(httpRequestMessage.Headers, _options.AdditionalHeaders);
94+
StreamableHttpClientSessionTransport.CopyAdditionalHeaders(httpRequestMessage.Headers, _options.AdditionalHeaders, sessionId: null, protocolVersion: null);
9595
var response = await _httpClient.SendAsync(httpRequestMessage, cancellationToken).ConfigureAwait(false);
9696

9797
if (!response.IsSuccessStatusCode)
@@ -152,7 +152,7 @@ private async Task ReceiveMessagesAsync(CancellationToken cancellationToken)
152152
{
153153
using var request = new HttpRequestMessage(HttpMethod.Get, _sseEndpoint);
154154
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));
155-
StreamableHttpClientSessionTransport.CopyAdditionalHeaders(request.Headers, _options.AdditionalHeaders);
155+
StreamableHttpClientSessionTransport.CopyAdditionalHeaders(request.Headers, _options.AdditionalHeaders, sessionId: null, protocolVersion: null);
156156

157157
using var response = await _httpClient.SendAsync(
158158
request,

src/ModelContextProtocol.Core/Client/SseClientTransportOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public required Uri Endpoint
3939
/// Streamable HTTP transport and automatically fall back to SSE transport if the server doesn't support it.
4040
/// </para>
4141
/// <para>
42-
/// <see href="https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http">Streamable HTTP transport specification</see>.
42+
/// <see href="https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http">Streamable HTTP transport specification</see>.
4343
/// <see href="https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse">HTTP with SSE transport specification</see>.
4444
/// </para>
4545
/// </remarks>

src/ModelContextProtocol.Core/Client/StdioClientTransport.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ public async Task<ITransport> ConnectAsync(CancellationToken cancellationToken =
146146
stderrRollingLog.Enqueue(data);
147147
}
148148

149+
_options.StandardErrorLines?.Invoke(data);
150+
149151
LogReadStderr(logger, endpointName, data);
150152
}
151153
};

0 commit comments

Comments
 (0)