Skip to content

Commit c45278b

Browse files
authored
Merge branch 'main' into copilot/support-output-schema-independently
2 parents 24bbac3 + 231e013 commit c45278b

File tree

115 files changed

+3926
-715
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+3926
-715
lines changed

Directory.Packages.props

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
<System8Version>8.0.22</System8Version>
55
<System9Version>9.0.11</System9Version>
6-
<System10Version>10.0.2</System10Version>
7-
<MicrosoftExtensionsVersion>10.2.0</MicrosoftExtensionsVersion>
6+
<System10Version>10.0.3</System10Version>
7+
<MicrosoftExtensionsVersion>10.3.0</MicrosoftExtensionsVersion>
88
</PropertyGroup>
99

1010
<!-- Product dependencies shared -->
@@ -62,8 +62,8 @@
6262

6363
<!-- Testing dependencies -->
6464
<ItemGroup>
65-
<PackageVersion Include="Anthropic" Version="12.3.0" />
66-
<PackageVersion Include="coverlet.collector" Version="6.0.4">
65+
<PackageVersion Include="Anthropic" Version="12.5.0" />
66+
<PackageVersion Include="coverlet.collector" Version="8.0.0">
6767
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
6868
<PrivateAssets>all</PrivateAssets>
6969
</PackageVersion>
@@ -87,11 +87,11 @@
8787
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
8888
<PackageVersion Include="Serilog.Sinks.Debug" Version="3.0.0" />
8989
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
90-
<PackageVersion Include="Serilog" Version="4.3.0" />
90+
<PackageVersion Include="Serilog" Version="4.3.1" />
9191
<PackageVersion Include="System.Linq.AsyncEnumerable" Version="$(System10Version)" />
9292
<PackageVersion Include="xunit.v3" Version="3.2.2" />
9393
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
9494
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
95-
<PackageVersion Include="JsonSchema.Net" Version="9.0.0" />
95+
<PackageVersion Include="JsonSchema.Net" Version="9.1.0" />
9696
</ItemGroup>
9797
</Project>

SECURITY.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
# Security Policy
2-
Thank you for helping us keep the SDKs and systems they interact with secure.
2+
3+
Thank you for helping keep the Model Context Protocol and its ecosystem secure.
34

45
## Reporting Security Issues
56

6-
This SDK is maintained by [Anthropic](https://www.anthropic.com/) as part of the Model Context Protocol project.
7+
If you discover a security vulnerability in this repository, please report it through
8+
the [GitHub Security Advisory process](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability)
9+
for this repository.
710

8-
The security of our systems and user data is Anthropic’s top priority. We appreciate the work of security researchers acting in good faith in identifying and reporting potential vulnerabilities.
11+
Please **do not** report security vulnerabilities through public GitHub issues, discussions,
12+
or pull requests.
913

10-
Our security program is managed on HackerOne and we ask that any validated vulnerability in this functionality be reported through their [submission form](https://hackerone.com/anthropic-vdp/reports/new?type=team&report_type=vulnerability).
14+
## What to Include
1115

12-
## Vulnerability Disclosure Program
16+
To help us triage and respond quickly, please include:
1317

14-
Our Vulnerability Program Guidelines are defined on our [HackerOne program page](https://hackerone.com/anthropic-vdp).
18+
- A description of the vulnerability
19+
- Steps to reproduce the issue
20+
- The potential impact
21+
- Any suggested fixes (optional)

docs/concepts/tasks/tasks.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,8 @@ Task operations may throw <xref:ModelContextProtocol.McpException> with these er
424424

425425
| Error Code | Scenario |
426426
|------------|----------|
427-
| `InvalidParams` | Invalid or nonexistent task ID |
428-
| `InvalidRequest` | Tool with `taskSupport: forbidden` called with task metadata, or tool with `taskSupport: required` called without task metadata |
427+
| `InvalidParams` | Invalid or nonexistent task ID or invalid cursor |
428+
| `InvalidParams` | Tool with `taskSupport: forbidden` called with task metadata, or tool with `taskSupport: required` called without task metadata |
429429
| `InternalError` | Task execution failure or result unavailable |
430430

431431
Example error handling:

package-lock.json

Lines changed: 12 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"description": "Pinned npm dependencies for MCP C# SDK integration and conformance tests",
44
"dependencies": {
55
"@modelcontextprotocol/conformance": "0.1.13",
6-
"@modelcontextprotocol/server-everything": "2025.12.18",
6+
"@modelcontextprotocol/server-everything": "2026.1.26",
77
"@modelcontextprotocol/server-memory": "2026.1.26"
88
}
99
}

src/ModelContextProtocol.AspNetCore/StreamableHttpHandler.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,34 @@ internal sealed class StreamableHttpHandler(
2323
ILoggerFactory loggerFactory)
2424
{
2525
private const string McpSessionIdHeaderName = "Mcp-Session-Id";
26+
private const string McpProtocolVersionHeaderName = "MCP-Protocol-Version";
2627
private const string LastEventIdHeaderName = "Last-Event-ID";
2728

29+
/// <summary>
30+
/// All protocol versions supported by this implementation.
31+
/// Keep in sync with McpSessionHandler.SupportedProtocolVersions in ModelContextProtocol.Core.
32+
/// </summary>
33+
private static readonly HashSet<string> s_supportedProtocolVersions =
34+
[
35+
"2024-11-05",
36+
"2025-03-26",
37+
"2025-06-18",
38+
"2025-11-25",
39+
];
40+
2841
private static readonly JsonTypeInfo<JsonRpcMessage> s_messageTypeInfo = GetRequiredJsonTypeInfo<JsonRpcMessage>();
2942
private static readonly JsonTypeInfo<JsonRpcError> s_errorTypeInfo = GetRequiredJsonTypeInfo<JsonRpcError>();
3043

3144
public HttpServerTransportOptions HttpServerTransportOptions => httpServerTransportOptions.Value;
3245

3346
public async Task HandlePostRequestAsync(HttpContext context)
3447
{
48+
if (!ValidateProtocolVersionHeader(context, out var errorMessage))
49+
{
50+
await WriteJsonRpcErrorAsync(context, errorMessage!, StatusCodes.Status400BadRequest);
51+
return;
52+
}
53+
3554
// The Streamable HTTP spec mandates the client MUST accept both application/json and text/event-stream.
3655
// ASP.NET Core Minimal APIs mostly try to stay out of the business of response content negotiation,
3756
// so we have to do this manually. The spec doesn't mandate that servers MUST reject these requests,
@@ -74,6 +93,12 @@ await WriteJsonRpcErrorAsync(context,
7493

7594
public async Task HandleGetRequestAsync(HttpContext context)
7695
{
96+
if (!ValidateProtocolVersionHeader(context, out var errorMessage))
97+
{
98+
await WriteJsonRpcErrorAsync(context, errorMessage!, StatusCodes.Status400BadRequest);
99+
return;
100+
}
101+
77102
if (!context.Request.GetTypedHeaders().Accept.Any(MatchesTextEventStreamMediaType))
78103
{
79104
await WriteJsonRpcErrorAsync(context,
@@ -171,6 +196,12 @@ private static async Task HandleResumePostResponseStreamAsync(HttpContext contex
171196

172197
public async Task HandleDeleteRequestAsync(HttpContext context)
173198
{
199+
if (!ValidateProtocolVersionHeader(context, out var errorMessage))
200+
{
201+
await WriteJsonRpcErrorAsync(context, errorMessage!, StatusCodes.Status400BadRequest);
202+
return;
203+
}
204+
174205
var sessionId = context.Request.Headers[McpSessionIdHeaderName].ToString();
175206
if (sessionManager.TryRemove(sessionId, out var session))
176207
{
@@ -339,6 +370,7 @@ internal static void InitializeSseResponse(HttpContext context)
339370

340371
// Make sure we disable all response buffering for SSE.
341372
context.Response.Headers.ContentEncoding = "identity";
373+
context.Response.Headers["X-Accel-Buffering"] = "no";
342374
context.Features.GetRequiredFeature<IHttpResponseBodyFeature>().DisableBuffering();
343375
}
344376

@@ -390,6 +422,24 @@ internal static Task RunSessionAsync(HttpContext httpContext, McpServer session,
390422

391423
internal static JsonTypeInfo<T> GetRequiredJsonTypeInfo<T>() => (JsonTypeInfo<T>)McpJsonUtilities.DefaultOptions.GetTypeInfo(typeof(T));
392424

425+
/// <summary>
426+
/// Validates the MCP-Protocol-Version header if present. A missing header is allowed for backwards compatibility,
427+
/// but an invalid or unsupported value must be rejected with 400 Bad Request per the MCP spec.
428+
/// </summary>
429+
private static bool ValidateProtocolVersionHeader(HttpContext context, out string? errorMessage)
430+
{
431+
var protocolVersionHeader = context.Request.Headers[McpProtocolVersionHeaderName].ToString();
432+
if (!string.IsNullOrEmpty(protocolVersionHeader) &&
433+
!s_supportedProtocolVersions.Contains(protocolVersionHeader))
434+
{
435+
errorMessage = $"Bad Request: The MCP-Protocol-Version header value '{protocolVersionHeader}' is not supported.";
436+
return false;
437+
}
438+
439+
errorMessage = null;
440+
return true;
441+
}
442+
393443
private static bool MatchesApplicationJsonMediaType(MediaTypeHeaderValue acceptHeaderValue)
394444
=> acceptHeaderValue.MatchesMediaType("application/json");
395445

src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,8 +618,9 @@ private async Task PerformDynamicClientRegistrationAsync(
618618
Scope = GetScopeParameter(protectedResourceMetadata),
619619
};
620620

621-
var requestJson = JsonSerializer.Serialize(registrationRequest, McpJsonUtilities.JsonContext.Default.DynamicClientRegistrationRequest);
622-
using var requestContent = new StringContent(requestJson, Encoding.UTF8, "application/json");
621+
var requestBytes = JsonSerializer.SerializeToUtf8Bytes(registrationRequest, McpJsonUtilities.JsonContext.Default.DynamicClientRegistrationRequest);
622+
using var requestContent = new ByteArrayContent(requestBytes);
623+
requestContent.Headers.ContentType = McpHttpClient.s_applicationJsonContentType;
623624

624625
using var request = new HttpRequestMessage(HttpMethod.Post, authServerMetadata.RegistrationEndpoint)
625626
{

src/ModelContextProtocol.Core/Client/McpClient.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ public abstract partial class McpClient : McpSession
3535
/// <remarks>
3636
/// <para>
3737
/// This property contains instructions provided by the server during initialization that explain
38-
/// how to effectively use its capabilities. These instructions can include details about available
39-
/// tools, expected input formats, limitations, or any other helpful information.
38+
/// how to effectively use its capabilities. They should focus on guidance that helps a model
39+
/// use the server effectively and should avoid duplicating tool, prompt, or resource descriptions.
4040
/// </para>
4141
/// <para>
42-
/// This can be used by clients to improve an LLM's understanding of available tools, prompts, and resources.
42+
/// This can be used by clients to improve an LLM's understanding of how to use the server.
4343
/// It can be thought of like a "hint" to the model and can be added to a system prompt.
4444
/// </para>
4545
/// </remarks>

src/ModelContextProtocol.Core/Client/McpHttpClient.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
using ModelContextProtocol.Protocol;
22
using System.Diagnostics;
3+
using System.Net.Http.Headers;
34

45
#if NET
56
using System.Net.Http.Json;
67
#else
7-
using System.Text;
88
using System.Text.Json;
99
#endif
1010

1111
namespace ModelContextProtocol.Client;
1212

1313
internal class McpHttpClient(HttpClient httpClient)
1414
{
15+
internal static readonly MediaTypeHeaderValue s_applicationJsonContentType = new("application/json") { CharSet = "utf-8" };
16+
1517
internal virtual async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, JsonRpcMessage? message, CancellationToken cancellationToken)
1618
{
1719
Debug.Assert(request.Content is null, "The request body should only be supplied as a JsonRpcMessage");
@@ -32,11 +34,10 @@ internal virtual async Task<HttpResponseMessage> SendAsync(HttpRequestMessage re
3234
#if NET
3335
return JsonContent.Create(message, McpJsonUtilities.JsonContext.Default.JsonRpcMessage);
3436
#else
35-
return new StringContent(
36-
JsonSerializer.Serialize(message, McpJsonUtilities.JsonContext.Default.JsonRpcMessage),
37-
Encoding.UTF8,
38-
"application/json"
39-
);
37+
var bytes = JsonSerializer.SerializeToUtf8Bytes(message, McpJsonUtilities.JsonContext.Default.JsonRpcMessage);
38+
var content = new ByteArrayContent(bytes);
39+
content.Headers.ContentType = s_applicationJsonContentType;
40+
return content;
4041
#endif
4142
}
4243
}

src/ModelContextProtocol.Core/Client/StdioClientSessionTransport.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,13 @@ protected override async ValueTask CleanupAsync(Exception? error = null, Cancell
7272
try
7373
{
7474
// The process has exited, but we still need to ensure stderr has been flushed.
75+
// WaitForExitAsync only waits for exit; it does not guarantee that all
76+
// ErrorDataReceived events have been dispatched. The synchronous WaitForExit()
77+
// (no arguments) does ensure that, so call it after WaitForExitAsync completes.
7578
#if NET
7679
await _process.WaitForExitAsync(cancellationToken).ConfigureAwait(false);
77-
#else
78-
_process.WaitForExit();
7980
#endif
81+
_process.WaitForExit();
8082
}
8183
catch { }
8284

0 commit comments

Comments
 (0)