Prevent cancellation of initialize request per MCP spec (#1350)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
This commit is contained in:
Copilot 2026-02-23 15:40:17 -05:00 • committed by GitHub
commit 4f7095453c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,6 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
using ModelContextProtocol.Tests.Utils;
using System.IO.Pipelines;
using System.Text;
namespace ModelContextProtocol.Tests;
@ -65,4 +69,37 @@ public class CancellationTests : ClientServerTestBase
cts.Cancel();
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await waitTask);
}
[Fact]
public async Task InitializeTimeout_DoesNotSendCancellationNotification()
{
// Arrange: Create a transport where the server never responds, so the client will time out.
var serverInput = new MemoryStream();
var serverOutputPipe = new Pipe();
var clientTransport = new StreamClientTransport(
serverInput: serverInput,
serverOutputPipe.Reader.AsStream(),
LoggerFactory);
var clientOptions = new McpClientOptions
{
InitializationTimeout = TimeSpan.FromMilliseconds(500),
};
// Act: Client will send initialize, then time out since no response comes.
// Per spec, "The initialize request MUST NOT be cancelled by clients",
// so no cancellation notification should be sent.
await Assert.ThrowsAsync<TimeoutException>(async () =>
{
await McpClient.CreateAsync(clientTransport, clientOptions: clientOptions, loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
});
// Assert: Read what was written to serverInput.
// The only message should be the initialize request, NOT a cancellation notification.
var content = Encoding.UTF8.GetString(serverInput.ToArray());
Assert.Contains("\"method\":\"initialize\"", content);
Assert.DoesNotContain("notifications/cancelled", content);
}
}