diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7504760a9..7f9411025 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -97,6 +97,12 @@ The test projects include shared infrastructure in `tests/Common/Utils/` that mo
Use `TestConstants.DefaultTimeout` (60 seconds) rather than hardcoded values. CI machines are often slower than developer workstations, and short timeouts cause flaky failures.
+For direct client connections to controlled test servers that respond to discovery, use `TestMcpClient.CreateAsync`.
+It disables the separate discovery probe timeout while retaining the overall `TestConstants.DefaultTimeout` initialization deadline.
+If configuring client options, start with `TestMcpClient.CreateOptions()` before applying test-specific settings; explicitly supplied options are otherwise preserved unchanged.
+Do not use these defaults in discovery-timeout tests or with servers that silently ignore discovery, since those rely on the probe timeout for fallback.
+For a mock that only implements the legacy initialize handshake, explicitly select its supported protocol version instead of waiting for discovery to time out.
+
```csharp
// Good
using var cts = CancellationTokenSource.CreateLinkedTokenSource(TestContext.Current.CancellationToken);
diff --git a/tests/Common/Utils/TestMcpClient.cs b/tests/Common/Utils/TestMcpClient.cs
new file mode 100644
index 000000000..8847bade2
--- /dev/null
+++ b/tests/Common/Utils/TestMcpClient.cs
@@ -0,0 +1,24 @@
+using Microsoft.Extensions.Logging;
+using ModelContextProtocol.Client;
+
+namespace ModelContextProtocol.Tests.Utils;
+
+///
+/// Creates clients for controlled test servers that respond to discovery, including with a fallback error.
+/// Do not use these defaults with servers that silently ignore discovery or in discovery-timeout tests.
+///
+internal static class TestMcpClient
+{
+ public static McpClientOptions CreateOptions() => new()
+ {
+ DiscoverProbeTimeout = Timeout.InfiniteTimeSpan,
+ InitializationTimeout = TestConstants.DefaultTimeout,
+ };
+
+ public static Task CreateAsync(
+ IClientTransport clientTransport,
+ McpClientOptions? clientOptions = null,
+ ILoggerFactory? loggerFactory = null,
+ CancellationToken cancellationToken = default) =>
+ McpClient.CreateAsync(clientTransport, clientOptions ?? CreateOptions(), loggerFactory, cancellationToken);
+}
diff --git a/tests/ModelContextProtocol.AotCompatibility.TestApp/ModelContextProtocol.AotCompatibility.TestApp.csproj b/tests/ModelContextProtocol.AotCompatibility.TestApp/ModelContextProtocol.AotCompatibility.TestApp.csproj
index a8ab66edf..626891314 100644
--- a/tests/ModelContextProtocol.AotCompatibility.TestApp/ModelContextProtocol.AotCompatibility.TestApp.csproj
+++ b/tests/ModelContextProtocol.AotCompatibility.TestApp/ModelContextProtocol.AotCompatibility.TestApp.csproj
@@ -12,6 +12,9 @@
+
+
+
diff --git a/tests/ModelContextProtocol.AotCompatibility.TestApp/Program.cs b/tests/ModelContextProtocol.AotCompatibility.TestApp/Program.cs
index 708cd9361..e71c6a6c9 100644
--- a/tests/ModelContextProtocol.AotCompatibility.TestApp/Program.cs
+++ b/tests/ModelContextProtocol.AotCompatibility.TestApp/Program.cs
@@ -3,6 +3,7 @@
using ModelContextProtocol.Extensions.Apps;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
+using ModelContextProtocol.Tests.Utils;
using System.IO.Pipelines;
Pipe clientToServerPipe = new(), serverToClientPipe = new();
@@ -18,7 +19,7 @@
_ = server.RunAsync();
// Connect a client using a stream-based transport over the same in-memory pipe.
-await using McpClient client = await McpClient.CreateAsync(
+await using McpClient client = await TestMcpClient.CreateAsync(
new StreamClientTransport(clientToServerPipe.Writer.AsStream(), serverToClientPipe.Reader.AsStream()));
// List all tools.
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/AuthorizeAttributeTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/AuthorizeAttributeTests.cs
index 369bd7eb0..aa6e18924 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/AuthorizeAttributeTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/AuthorizeAttributeTests.cs
@@ -25,12 +25,8 @@ private async Task ConnectAsync()
Endpoint = new("http://localhost:5000"),
}, HttpClient, LoggerFactory);
- // This server supports discovery; slow startup must not trigger legacy fallback.
- return await McpClient.CreateAsync(transport, new()
- {
- DiscoverProbeTimeout = Timeout.InfiniteTimeSpan,
- InitializationTimeout = TestConstants.DefaultTimeout,
- }, cancellationToken: TestContext.Current.CancellationToken, loggerFactory: LoggerFactory);
+ return await TestMcpClient.CreateAsync(transport,
+ cancellationToken: TestContext.Current.CancellationToken, loggerFactory: LoggerFactory);
}
[Fact]
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/HttpTaskIntegrationTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/HttpTaskIntegrationTests.cs
index d64a55987..fa8915c51 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/HttpTaskIntegrationTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/HttpTaskIntegrationTests.cs
@@ -6,6 +6,7 @@
using ModelContextProtocol.Extensions.Tasks;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
+using ModelContextProtocol.Tests.Utils;
using Moq;
using System.Security.Claims;
@@ -30,7 +31,7 @@ public async Task WithTasks_CanCallToolOverHttp()
new HttpClientTransportOptions { Endpoint = new("http://localhost:5000") },
HttpClient,
LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
@@ -67,7 +68,7 @@ public async Task WithTasks_AfterOrdinaryFilter_RunsFilter()
new HttpClientTransportOptions { Endpoint = new("http://localhost:5000") },
HttpClient,
LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
@@ -120,7 +121,7 @@ [new Claim(ClaimTypes.NameIdentifier, "test-user")],
new HttpClientTransportOptions { Endpoint = new("http://localhost:5000") },
HttpClient,
LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
@@ -166,7 +167,7 @@ public async Task WithTasks_UnauthorizedTool_DoesNotCreateTask(bool registerTask
new HttpClientTransportOptions { Endpoint = new("http://localhost:5000") },
HttpClient,
LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
@@ -217,7 +218,7 @@ public async Task WithTasks_ReauthorizesToolChangedByOrdinaryFilter()
new HttpClientTransportOptions { Endpoint = new("http://localhost:5000") },
HttpClient,
LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolHttpFallbackTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolHttpFallbackTests.cs
index 22cc36ad7..0a9a46ceb 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolHttpFallbackTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolHttpFallbackTests.cs
@@ -221,7 +221,7 @@ await StartServerAsync(async context =>
}, HttpClient, LoggerFactory);
// Default options prefer 2026-07-28 but allow automatic fallback to an initialize-handshake server.
- await using var client = await McpClient.CreateAsync(transport, new McpClientOptions(),
+ await using var client = await TestMcpClient.CreateAsync(transport,
loggerFactory: LoggerFactory, cancellationToken: ct);
Assert.Equal(McpProtocolVersions.June2025ProtocolVersion, client.NegotiatedProtocolVersion);
@@ -308,7 +308,7 @@ await StartServerAsync(async context =>
}, HttpClient, LoggerFactory);
// Default options prefer 2026-07-28 but allow automatic fallback to an initialize-handshake server.
- await using var client = await McpClient.CreateAsync(transport, new McpClientOptions(),
+ await using var client = await TestMcpClient.CreateAsync(transport,
loggerFactory: LoggerFactory, cancellationToken: ct);
Assert.Equal(McpProtocolVersions.November2025ProtocolVersion, client.NegotiatedProtocolVersion);
@@ -354,10 +354,10 @@ await WriteJsonRpcErrorAsync(context, HttpStatusCode.BadRequest,
var exception = await Assert.ThrowsAsync(async () =>
{
- await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
- {
- ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion,
- }, loggerFactory: LoggerFactory, cancellationToken: ct);
+ var clientOptions = TestMcpClient.CreateOptions();
+ clientOptions.ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion;
+ await using var client = await McpClient.CreateAsync(transport, clientOptions,
+ loggerFactory: LoggerFactory, cancellationToken: ct);
});
Assert.Equal(McpErrorCode.HeaderMismatch, exception.ErrorCode);
@@ -408,9 +408,8 @@ await WriteJsonRpcErrorAsync(
var exception = await Assert.ThrowsAsync(async () =>
{
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
- new McpClientOptions(),
loggerFactory: LoggerFactory,
cancellationToken: ct);
});
@@ -481,10 +480,10 @@ await StartServerAsync(async context =>
Endpoint = new("http://localhost:5000/mcp"),
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
- {
- ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion,
- }, loggerFactory: LoggerFactory, cancellationToken: ct);
+ var clientOptions = TestMcpClient.CreateOptions();
+ clientOptions.ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion;
+ await using var client = await McpClient.CreateAsync(transport, clientOptions,
+ loggerFactory: LoggerFactory, cancellationToken: ct);
await client.ListToolsAsync(cancellationToken: ct);
@@ -541,10 +540,10 @@ await StartServerAsync(async context =>
OwnsSession = false,
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
- {
- ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion,
- }, loggerFactory: LoggerFactory, cancellationToken: ct);
+ var clientOptions = TestMcpClient.CreateOptions();
+ clientOptions.ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion;
+ await using var client = await McpClient.CreateAsync(transport, clientOptions,
+ loggerFactory: LoggerFactory, cancellationToken: ct);
Assert.Equal("", discoverSessionId);
}
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolHybridSessionModeTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolHybridSessionModeTests.cs
index 01a4b26cf..c4b398f95 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolHybridSessionModeTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolHybridSessionModeTests.cs
@@ -4,6 +4,7 @@
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
+using ModelContextProtocol.Tests.Utils;
using System.Net;
using System.Net.Http.Headers;
using System.Text;
@@ -109,7 +110,8 @@ private Task ConnectClientAsync(string? protocolVersion = null, Actio
// A null ProtocolVersion prefers 2026-07-28 and probes with server/discover before considering a
// fallback to the initialize handshake. Pinning an older version forces the initialize handshake.
- var clientOptions = new McpClientOptions { ProtocolVersion = protocolVersion };
+ var clientOptions = TestMcpClient.CreateOptions();
+ clientOptions.ProtocolVersion = protocolVersion;
configureClient?.Invoke(clientOptions);
return McpClient.CreateAsync(transport, clientOptions, LoggerFactory, TestContext.Current.CancellationToken);
}
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolStatefulFallbackTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolStatefulFallbackTests.cs
index 142536b9d..8956eaf76 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolStatefulFallbackTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/July2026ProtocolStatefulFallbackTests.cs
@@ -83,7 +83,7 @@ private async Task ConnectDefaultClientAsync(Action
// Default options: ProtocolVersion is null, which now prefers the 2026-07-28 protocol revision and probes
// with server/discover before falling back to an initialize handshake.
- var clientOptions = new McpClientOptions();
+ var clientOptions = TestMcpClient.CreateOptions();
configureClient?.Invoke(clientOptions);
return await McpClient.CreateAsync(transport, clientOptions, LoggerFactory, TestContext.Current.CancellationToken);
}
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs
index d413bf528..7424f8ac0 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Time.Testing;
using ModelContextProtocol.AspNetCore.Tests.Utils;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
@@ -37,11 +38,87 @@ protected async Task ConnectAsync(
TransportMode = UseStreamableHttp ? HttpTransportMode.StreamableHttp : HttpTransportMode.Sse,
}, HttpClient, LoggerFactory);
- var clientOptions = new McpClientOptions();
+ var clientOptions = TestMcpClient.CreateOptions();
configureClient?.Invoke(clientOptions);
return await McpClient.CreateAsync(transport, clientOptions, LoggerFactory, TestContext.Current.CancellationToken);
}
+ [Fact]
+ public async Task ConnectAsync_SlowDiscovery_PreservesModernProtocol()
+ {
+ Assert.SkipWhen(UseStreamableHttp && !Stateless, July2026StatefulStreamableHttpSkipReason);
+
+ var discovery = new AsyncGate();
+ var timeProvider = new FakeTimeProvider();
+ await using var app = await StartServerWithGatedDiscoveryAsync(discovery);
+
+ var connecting = ConnectAsync(configureClient: options =>
+ {
+ options.ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion;
+ options.TimeProvider = timeProvider;
+ });
+ await discovery.WaitUntilEnteredAsync(connecting);
+ timeProvider.Advance(new McpClientOptions().DiscoverProbeTimeout * 2);
+ discovery.Release.SetResult();
+
+ await using var client = await connecting.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken);
+ Assert.Equal(McpProtocolVersions.July2026ProtocolVersion, client.NegotiatedProtocolVersion);
+ }
+
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task ConnectAsync_Discovery_RespectsConfiguredDeadline(bool customProbeTimeout)
+ {
+ Assert.SkipWhen(UseStreamableHttp && !Stateless, July2026StatefulStreamableHttpSkipReason);
+
+ var discovery = new AsyncGate();
+ var timeProvider = new FakeTimeProvider();
+ var probeTimeout = new McpClientOptions().DiscoverProbeTimeout;
+ await using var app = await StartServerWithGatedDiscoveryAsync(discovery);
+
+ var connecting = ConnectAsync(configureClient: options =>
+ {
+ options.ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion;
+ options.TimeProvider = timeProvider;
+ if (customProbeTimeout)
+ {
+ options.DiscoverProbeTimeout = probeTimeout;
+ }
+ });
+ await discovery.WaitUntilEnteredAsync(connecting);
+ timeProvider.Advance(customProbeTimeout ? probeTimeout : TestConstants.DefaultTimeout);
+
+ if (customProbeTimeout)
+ {
+ await Assert.ThrowsAsync(() => connecting.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken));
+ }
+ else
+ {
+ var exception = await Assert.ThrowsAsync(() => connecting.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken));
+ Assert.Equal("Initialization timed out", exception.Message);
+ }
+ }
+
+ private async Task StartServerWithGatedDiscoveryAsync(AsyncGate discovery)
+ {
+ Builder.Services.AddMcpServer()
+ .WithHttpTransport(ConfigureStateless)
+ .WithMessageFilters(filters => filters.AddIncomingFilter(next => async (context, cancellationToken) =>
+ {
+ if (context.JsonRpcMessage is JsonRpcRequest { Method: RequestMethods.ServerDiscover })
+ {
+ await discovery.WaitAsync(cancellationToken);
+ }
+ await next(context, cancellationToken);
+ }));
+
+ var app = Builder.Build();
+ app.MapMcp();
+ await app.StartAsync(TestContext.Current.CancellationToken);
+ return app;
+ }
+
[Fact]
public async Task MapMcp_ThrowsInvalidOperationException_IfWithHttpTransportIsNotCalled()
{
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthEventTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthEventTests.cs
index 1866dfe13..4aef55169 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthEventTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthEventTests.cs
@@ -2,6 +2,7 @@
using ModelContextProtocol.AspNetCore.Authentication;
using ModelContextProtocol.Authentication;
using ModelContextProtocol.Client;
+using ModelContextProtocol.Tests.Utils;
using System.Net;
using System.Net.Http.Json;
@@ -55,7 +56,7 @@ public async Task CanAuthenticate_WithResourceMetadataFromEvent()
LoggerFactory
);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken
@@ -94,7 +95,7 @@ public async Task CanAuthenticate_WithDynamicClientRegistration_FromEvent()
LoggerFactory
);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthTests.cs
index 476a0ccf3..2da187d6f 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthTests.cs
@@ -48,7 +48,7 @@ public async Task CanAuthenticate()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -76,7 +76,7 @@ public async Task AuthorizationCallbackHandler_ReceivesConfiguredRedirectUri()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(callbackContext);
@@ -118,7 +118,7 @@ public async Task AuthorizationRedirectDelegate_ReceivesConfiguredUrisAndSkipsRe
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(receivedAuthorizationUri);
@@ -145,7 +145,7 @@ public async Task AuthorizationRedirectDelegate_DoesNotSkipMetadataIssuerValidat
},
}, HttpClient, LoggerFactory);
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Contains("does not match the expected issuer", ex.Message);
@@ -190,7 +190,7 @@ public async Task CanAuthenticate_WhenAuthorizationResponseStateMatches()
return HandleAuthorizationUrlAsync(context, cancellationToken);
});
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(requestedState);
@@ -205,7 +205,7 @@ public async Task CannotAuthenticate_WhenAuthorizationResponseStateIsMissing()
await using var transport = CreateOAuthTransport(
(_, _) => Task.FromResult(new() { Code = "unused-code" }));
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Contains("did not include the required state parameter", ex.Message);
@@ -220,7 +220,7 @@ public async Task CannotAuthenticate_WhenAuthorizationResponseStateMismatches()
(_, _) => Task.FromResult(
new() { Code = "unused-code", State = "unexpected-state" }));
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Contains("state did not match", ex.Message);
@@ -241,7 +241,7 @@ public async Task AuthorizationRequests_UseUniqueStateValues()
return HandleAuthorizationUrlAsync(context, cancellationToken);
});
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -259,7 +259,7 @@ public async Task CannotAuthenticate_WithoutOAuthConfiguration()
Endpoint = new(McpServerUrl),
}, HttpClient, LoggerFactory);
- var httpEx = await Assert.ThrowsAsync(async () => await McpClient.CreateAsync(
+ var httpEx = await Assert.ThrowsAsync(async () => await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Equal(HttpStatusCode.Unauthorized, httpEx.StatusCode);
@@ -283,7 +283,7 @@ public async Task CannotAuthenticate_WithUnregisteredClient()
}, HttpClient, LoggerFactory);
// The EqualException is thrown by HandleAuthorizationUrlAsync when the /authorize request gets a 400
- var equalEx = await Assert.ThrowsAsync(async () => await McpClient.CreateAsync(
+ var equalEx = await Assert.ThrowsAsync(async () => await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
}
@@ -307,7 +307,7 @@ public async Task CanAuthenticate_WithDynamicClientRegistration()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.Equal("native", TestOAuthServer.LastApplicationType);
@@ -332,7 +332,7 @@ public async Task DynamicClientRegistration_UsesExplicitApplicationType()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.Equal("web", TestOAuthServer.LastApplicationType);
@@ -358,7 +358,7 @@ public async Task CanAuthenticate_WithClientMetadataDocument()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -380,7 +380,7 @@ public async Task CannotAuthenticate_WhenMetadataOmitsPkceMethods()
},
}, HttpClient, LoggerFactory);
- await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
// No discovery endpoint advertises PKCE, so metadata discovery is exhausted. The precise PKCE reason
@@ -408,7 +408,7 @@ public async Task CannotAuthenticate_WhenMetadataLacksS256PkceMethod()
},
}, HttpClient, LoggerFactory);
- await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Contains(
@@ -437,7 +437,7 @@ public async Task CanAuthenticate_WhenFirstMetadataEndpointOmitsPkce_ButAnotherA
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -468,7 +468,7 @@ public async Task UsesDynamicClientRegistration_WhenCimdNotSupported()
}, HttpClient, LoggerFactory);
// Should succeed via dynamic client registration.
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -495,7 +495,7 @@ public async Task DoesNotUseClientMetadataDocument_WhenClientIdIsSpecified()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -517,7 +517,7 @@ public async Task CannotAuthenticate_WithInvalidClientMetadataDocument(string ur
},
}, HttpClient, LoggerFactory);
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.StartsWith("Failed to handle unauthorized response", ex.Message);
@@ -581,7 +581,7 @@ public async Task CanAuthenticate_WithTokenRefresh()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
await client.ListToolsAsync(cancellationToken: TestContext.Current.CancellationToken);
@@ -616,7 +616,7 @@ public async Task CanAuthenticate_WithExtraParams()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(lastAuthorizationUri?.Query);
@@ -646,7 +646,7 @@ public async Task CannotOverrideExistingParameters_WithExtraParams(string parame
},
}, HttpClient, LoggerFactory);
- await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
}
@@ -667,7 +667,7 @@ public async Task CanAuthenticate_WithoutResourceInWwwAuthenticateHeader()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -689,7 +689,7 @@ public async Task CanAuthenticate_WithoutResourceInWwwAuthenticateHeader_WithPat
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -722,7 +722,7 @@ public async Task AuthorizationFlow_UsesScopeFromProtectedResourceMetadata()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
var requestedScopeSet = new HashSet(requestedScope!.Split(' '));
@@ -775,7 +775,7 @@ public async Task AuthorizationFlow_UsesScopeFromChallengeHeader()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.Equal(challengeScopes, requestedScope);
@@ -870,7 +870,7 @@ public async Task AuthorizationFlow_UsesScopeFromForbiddenHeader()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.Equal("mcp:tools", requestedScope);
@@ -975,7 +975,7 @@ public async Task AuthorizationFlow_AccumulatesScopesAcrossMultipleStepUps()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
// Initial auth gets "mcp:tools" from protected resource metadata
@@ -1094,7 +1094,7 @@ public async Task AuthorizationFlow_ConcurrentStepUps_ReuseSteppedUpToken_WhenCh
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
// Initial connect requests "mcp:tools" from protected resource metadata.
@@ -1189,7 +1189,7 @@ public async Task AuthorizationFlow_StopsSteppingUpWhenChallengeAddsNoNewScope()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
// Initial auth gets "mcp:tools" from protected resource metadata.
@@ -1284,7 +1284,7 @@ public async Task AuthorizationFlow_AllowsOneStepUpEvenWhenChallengeAddsNoNewSco
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
// Initial auth already requests "mcp:tools" from protected resource metadata.
@@ -1327,7 +1327,7 @@ public async Task AuthorizationFails_WhenResourceMetadataPortDiffers()
},
}, HttpClient, LoggerFactory);
- await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
}
@@ -1366,7 +1366,7 @@ public async Task CannotAuthenticate_WhenProtectedResourceMetadataMissingResourc
},
}, HttpClient, LoggerFactory);
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Contains("Resource URI in metadata", ex.Message);
@@ -1394,7 +1394,7 @@ public async Task CanAuthenticate_WithAuthorizationServerPathInsertionMetadata()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
var requests = TestOAuthServer.MetadataRequests.ToArray();
@@ -1427,7 +1427,7 @@ public async Task CanAuthenticate_WithAuthorizationServerPathFallbacks()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.Equal(
@@ -1448,7 +1448,7 @@ public async Task CannotAuthenticate_WhenAuthorizationServerMetadataIssuerMismat
await using var app = await StartMcpServerAsync();
await using var transport = CreateOAuthTransport();
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Contains("does not match the expected issuer", ex.Message);
@@ -1463,7 +1463,7 @@ public async Task CannotAuthenticate_WhenAuthorizationServerMetadataOmitsIssuer(
await using var app = await StartMcpServerAsync();
await using var transport = CreateOAuthTransport();
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Contains("did not provide the required issuer", ex.Message);
@@ -1478,7 +1478,7 @@ public async Task CanAuthenticate_WhenAuthorizationResponseIssuerMatches()
await using var app = await StartMcpServerAsync();
await using var transport = CreateOAuthTransport();
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -1497,7 +1497,7 @@ public async Task CannotAuthenticate_WhenAuthorizationResponseIssuerIsInvalid(
await using var app = await StartMcpServerAsync();
await using var transport = CreateOAuthTransport();
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Contains(expectedMessage, ex.Message);
@@ -1623,7 +1623,7 @@ public async Task CannotAuthenticate_WhenResourceMetadataResourceIsNonRootParent
var ex = await Assert.ThrowsAsync(async () =>
{
- await McpClient.CreateAsync(
+ await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
});
@@ -1668,7 +1668,7 @@ public async Task CanAuthenticate_WhenWwwAuthenticateResourceMetadataIsRootPath(
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -1711,7 +1711,7 @@ public async Task CannotAuthenticate_WhenResourceMetadataUriDoesNotMatch()
}, HttpClient, LoggerFactory);
// This should fail because the resource URI doesn't match
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Contains("does not match", ex.Message);
@@ -1758,7 +1758,7 @@ public async Task CannotAuthenticate_WhenResourceMetadataResourceIsDifferentPath
// This should fail because the resource URI is a different path on the same host,
// which is neither an exact match nor the authority-only base URL.
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
Assert.Contains("does not match", ex.Message);
@@ -1805,7 +1805,7 @@ public async Task ResourceMetadata_DoesNotAddTrailingSlash()
// This should succeed - the client should not add a trailing slash
// If the client incorrectly added a trailing slash, ValidResources would reject it
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -1957,7 +1957,7 @@ public async Task ResourceMetadata_PreservesExplicitTrailingSlash()
// This should succeed with the explicitly configured trailing slash
// If the client incorrectly trimmed the slash, ValidResources would reject it
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -2072,7 +2072,7 @@ await context.Response.WriteAsync($$"""
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -2174,7 +2174,7 @@ public async Task CanAuthenticate_WithLegacyServerUsingDefaultEndpointFallback()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
}
@@ -2245,7 +2245,7 @@ await context.Response.WriteAsync($$"""
},
}, HttpClient, LoggerFactory);
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
// The specific PKCE failure reason is surfaced rather than a generic discovery failure or a
@@ -2278,7 +2278,7 @@ public async Task AuthorizationFlow_AppendsOfflineAccess_WhenServerAdvertisesIt(
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(requestedScope);
@@ -2310,7 +2310,7 @@ public async Task AuthorizationFlow_DoesNotAppendOfflineAccess_WhenServerDoesNot
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(requestedScope);
@@ -2349,7 +2349,7 @@ public async Task AuthorizationFlow_DoesNotDuplicateOfflineAccess_WhenAlreadyPre
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(requestedScope);
@@ -2387,7 +2387,7 @@ public async Task AuthorizationFlow_ScopeSelector_CanFilterServerProposedScopes(
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.Equal("mcp:tools", requestedScope);
@@ -2418,7 +2418,7 @@ public async Task AuthorizationFlow_ScopeSelector_CanAddCustomScope()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(requestedScope);
@@ -2455,7 +2455,7 @@ public async Task AuthorizationFlow_ScopeSelector_ReceivesNull_WhenServerProvide
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.Null(capturedInput);
@@ -2485,7 +2485,7 @@ public async Task AuthorizationFlow_ScopeSelector_ReturningNull_OmitsScopeParame
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.False(scopePresent);
@@ -2515,7 +2515,7 @@ public async Task AuthorizationFlow_ScopeSelector_ReturningEmpty_OmitsScopeParam
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.False(scopePresent);
@@ -2558,7 +2558,7 @@ public async Task DynamicClientRegistration_ScopeSelector_AppliesToDcrScope()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.Equal("mcp:tools", TestOAuthServer.LastRegistrationScope);
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/DcrFailureTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/DcrFailureTests.cs
index 43a69de68..375deb6f8 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/DcrFailureTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/DcrFailureTests.cs
@@ -1,5 +1,6 @@
using ModelContextProtocol.Authentication;
using ModelContextProtocol.Client;
+using ModelContextProtocol.Tests.Utils;
namespace ModelContextProtocol.AspNetCore.Tests.OAuth;
@@ -31,7 +32,7 @@ public async Task DcrRejection_PropagatesToConsumer_WithStatusBodyAndSentParamet
},
}, HttpClient, LoggerFactory);
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
// The consumer needs enough to produce a meaningful error: the HTTP status, the AS error
@@ -63,7 +64,7 @@ public async Task ConsumerCanRetryRegistration_WithAdjustedRedirectUri_AfterReje
},
}, HttpClient, LoggerFactory);
- await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
firstTransport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken));
// Second attempt: a new provider on the SAME HttpClient with an adjusted (loopback) redirect
@@ -84,7 +85,7 @@ await Assert.ThrowsAsync(() => McpClient.CreateAsync(
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
secondTransport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.Equal("native", TestOAuthServer.LastApplicationType);
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/DefaultAuthorizationUrlHandlerTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/DefaultAuthorizationUrlHandlerTests.cs
index 825ebe2fb..85ec3289a 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/DefaultAuthorizationUrlHandlerTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/DefaultAuthorizationUrlHandlerTests.cs
@@ -1,5 +1,6 @@
using ModelContextProtocol.Authentication;
using ModelContextProtocol.Client;
+using ModelContextProtocol.Tests.Utils;
namespace ModelContextProtocol.AspNetCore.Tests.OAuth;
@@ -31,7 +32,7 @@ public async Task RejectsAuthorizationCodeWithoutAbsoluteRedirectUrl()
try
{
- var ex = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var ex = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken));
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/IdentityAssertionGrantIntegrationTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/IdentityAssertionGrantIntegrationTests.cs
index 6972fa4b4..9051f1686 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/IdentityAssertionGrantIntegrationTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/IdentityAssertionGrantIntegrationTests.cs
@@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using ModelContextProtocol.Authentication;
using ModelContextProtocol.Client;
+using ModelContextProtocol.Tests.Utils;
using System.Net.Http.Headers;
namespace ModelContextProtocol.AspNetCore.Tests.OAuth;
@@ -76,7 +77,7 @@ public async Task CanAuthenticate_WithIdentityAssertionGrantProvider()
mcpHttpClient,
LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/TokenCacheTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/TokenCacheTests.cs
index 5b6f054ba..2fa865981 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/TokenCacheTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/TokenCacheTests.cs
@@ -1,6 +1,7 @@
using ModelContextProtocol.Authentication;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
+using ModelContextProtocol.Tests.Utils;
namespace ModelContextProtocol.AspNetCore.Tests.OAuth;
@@ -36,7 +37,7 @@ public async Task GetTokenAsync_CachedAccessTokenIsUsedForOutgoingRequests()
},
}, HttpClient, LoggerFactory);
- await using (var setupClient = await McpClient.CreateAsync(setupTransport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken))
+ await using (var setupClient = await TestMcpClient.CreateAsync(setupTransport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken))
{
// Just connecting should trigger auth and storage.
}
@@ -63,7 +64,7 @@ public async Task GetTokenAsync_CachedAccessTokenIsUsedForOutgoingRequests()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
+ await using var client = await TestMcpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.False(authDelegateCalledAgain, "AuthorizationCallbackHandler should not be called when token is valid");
}
@@ -88,7 +89,7 @@ public async Task StoreTokenAsync_NewlyAcquiredAccessTokenIsCached()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
+ await using var client = await TestMcpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(tokenCache.LastStoredToken);
Assert.False(string.IsNullOrEmpty(tokenCache.LastStoredToken.AccessToken));
@@ -119,7 +120,7 @@ public async Task GetTokenAsync_InvalidCachedTokenTriggersAuthDelegate()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
+ await using var client = await TestMcpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.True(authDelegateCalled, "AuthorizationCallbackHandler should be called when cached token is invalid");
Assert.NotNull(tokenCache.LastStoredToken);
@@ -151,7 +152,7 @@ public async Task GetTokenAsync_InvalidAccessTokenTriggersRefresh()
},
}, HttpClient, LoggerFactory);
- await using (var setupClient = await McpClient.CreateAsync(setupTransport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken))
+ await using (var setupClient = await TestMcpClient.CreateAsync(setupTransport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken))
{
// Just connecting should trigger auth and storage.
}
@@ -181,7 +182,7 @@ public async Task GetTokenAsync_InvalidAccessTokenTriggersRefresh()
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
+ await using var client = await TestMcpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.False(authDelegateCalledAgain, "AuthorizationCallbackHandler should not be called when refresh token is valid");
Assert.True(TestOAuthServer.HasRefreshedToken, "Token should have been refreshed");
@@ -207,7 +208,7 @@ public async Task GetTokenAsync_ExplicitClientDoesNotRefreshTokenFromDifferentAu
},
}, HttpClient, LoggerFactory);
- await using (var setupClient = await McpClient.CreateAsync(
+ await using (var setupClient = await TestMcpClient.CreateAsync(
setupTransport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken))
@@ -236,7 +237,7 @@ public async Task GetTokenAsync_ExplicitClientDoesNotRefreshTokenFromDifferentAu
},
}, HttpClient, LoggerFactory);
- var exception = await Assert.ThrowsAsync(() => McpClient.CreateAsync(
+ var exception = await Assert.ThrowsAsync(() => TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken));
@@ -266,7 +267,7 @@ public async Task GetTokenAsync_ExplicitClientDoesNotRefreshTokenIssuedToDiffere
},
}, HttpClient, LoggerFactory);
- await using (var setupClient = await McpClient.CreateAsync(
+ await using (var setupClient = await TestMcpClient.CreateAsync(
setupTransport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken))
@@ -295,7 +296,7 @@ public async Task GetTokenAsync_ExplicitClientDoesNotRefreshTokenIssuedToDiffere
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
@@ -325,7 +326,7 @@ public async Task GetTokenAsync_ExplicitClientWithLegacyUnboundCache_Reauthorize
},
}, HttpClient, LoggerFactory);
- await using (var setupClient = await McpClient.CreateAsync(
+ await using (var setupClient = await TestMcpClient.CreateAsync(
setupTransport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken))
@@ -354,7 +355,7 @@ public async Task GetTokenAsync_ExplicitClientWithLegacyUnboundCache_Reauthorize
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
@@ -393,7 +394,7 @@ public async Task GetTokenAsync_ColdStartWithDynamicRegistration_RefreshesUsingP
},
}, HttpClient, LoggerFactory);
- await using (var setupClient = await McpClient.CreateAsync(setupTransport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken))
+ await using (var setupClient = await TestMcpClient.CreateAsync(setupTransport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken))
{
// Just connecting should trigger dynamic registration, authorization, and storage.
}
@@ -432,7 +433,7 @@ public async Task GetTokenAsync_ColdStartWithDynamicRegistration_RefreshesUsingP
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
+ await using var client = await TestMcpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.False(authDelegateCalledAgain, "Authorization callback should not be called when the persisted refresh token can be used");
Assert.True(TestOAuthServer.HasRefreshedToken, "Token should have been refreshed using the persisted client credentials");
@@ -457,7 +458,7 @@ public async Task GetTokenAsync_ColdStartWithCredentialsFromDifferentAuthorizati
},
}, HttpClient, LoggerFactory);
- await using (var setupClient = await McpClient.CreateAsync(
+ await using (var setupClient = await TestMcpClient.CreateAsync(
setupTransport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken))
@@ -485,7 +486,7 @@ public async Task GetTokenAsync_ColdStartWithCredentialsFromDifferentAuthorizati
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
@@ -513,7 +514,7 @@ public async Task GetTokenAsync_ColdStartWithLegacyUnboundCredentials_Reregister
},
}, HttpClient, LoggerFactory);
- await using (var setupClient = await McpClient.CreateAsync(
+ await using (var setupClient = await TestMcpClient.CreateAsync(
setupTransport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken))
@@ -542,7 +543,7 @@ public async Task GetTokenAsync_ColdStartWithLegacyUnboundCredentials_Reregister
},
}, HttpClient, LoggerFactory);
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
transport,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
@@ -580,7 +581,7 @@ public async Task GetTokenAsync_ColdStartWithoutPersistedClientId_FallsBackToRea
},
}, HttpClient, LoggerFactory);
- await using (var setupClient = await McpClient.CreateAsync(setupTransport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken))
+ await using (var setupClient = await TestMcpClient.CreateAsync(setupTransport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken))
{
}
@@ -618,7 +619,7 @@ public async Task GetTokenAsync_ColdStartWithoutPersistedClientId_FallsBackToRea
// Should not throw "Client ID is not available"; instead re-authorizes via dynamic
// registration and the authorization-code flow.
- await using var client = await McpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
+ await using var client = await TestMcpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
Assert.True(authDelegateCalledAgain, "Authorization callback should be called to re-authorize when no client ID is available to refresh");
Assert.False(TestOAuthServer.HasRefreshedToken, "A refresh should not be attempted without a client ID");
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/SseServerIntegrationTestFixture.cs b/tests/ModelContextProtocol.AspNetCore.Tests/SseServerIntegrationTestFixture.cs
index c382c4385..7ebec277c 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/SseServerIntegrationTestFixture.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/SseServerIntegrationTestFixture.cs
@@ -46,7 +46,7 @@ public SseServerIntegrationTestFixture()
public Task ConnectMcpClientAsync(McpClientOptions? options, ILoggerFactory loggerFactory)
{
- return McpClient.CreateAsync(
+ return TestMcpClient.CreateAsync(
new HttpClientTransport(DefaultTransportOptions, HttpClient, loggerFactory),
options,
loggerFactory,
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/StatelessServerTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/StatelessServerTests.cs
index a95d989c5..c310e5475 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/StatelessServerTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/StatelessServerTests.cs
@@ -65,7 +65,7 @@ private async Task StartAsync()
}
private Task ConnectMcpClientAsync(McpClientOptions? clientOptions = null)
- => McpClient.CreateAsync(
+ => TestMcpClient.CreateAsync(
new HttpClientTransport(DefaultTransportOptions, HttpClient, LoggerFactory),
clientOptions, LoggerFactory, TestContext.Current.CancellationToken);
@@ -107,7 +107,7 @@ public async Task SamplingRequest_Fails_WithInvalidOperationException()
{
await StartAsync();
- var mcpClientOptions = new McpClientOptions();
+ var mcpClientOptions = TestMcpClient.CreateOptions();
mcpClientOptions.Handlers.SamplingHandler = (_, _, _) =>
{
throw new UnreachableException();
@@ -125,7 +125,7 @@ public async Task RootsRequest_Fails_WithInvalidOperationException()
{
await StartAsync();
- var mcpClientOptions = new McpClientOptions();
+ var mcpClientOptions = TestMcpClient.CreateOptions();
mcpClientOptions.Handlers.RootsHandler = (_, _) =>
{
throw new UnreachableException();
@@ -143,7 +143,7 @@ public async Task ElicitRequest_Fails_WithInvalidOperationException()
{
await StartAsync();
- var mcpClientOptions = new McpClientOptions();
+ var mcpClientOptions = TestMcpClient.CreateOptions();
mcpClientOptions.Handlers.ElicitationHandler = (_, _) =>
{
throw new UnreachableException();
@@ -160,7 +160,7 @@ public async Task ElicitRequest_Fails_WithInvalidOperationException()
public async Task ClientCapabilities_AreAvailableFromInjectedServer()
{
await StartAsync();
- var clientOptions = new McpClientOptions();
+ var clientOptions = TestMcpClient.CreateOptions();
clientOptions.Handlers.SamplingHandler = (_, _, _) => throw new UnreachableException();
clientOptions.Handlers.RootsHandler = (_, _) => throw new UnreachableException();
clientOptions.Handlers.ElicitationHandler = (_, _) => throw new UnreachableException();
@@ -179,7 +179,7 @@ public async Task ClientCapabilities_AreAvailableFromInjectedServer()
public async Task InterceptedServerToClientRequests_Succeed_InStatelessMode()
{
await StartAsync();
- var clientOptions = new McpClientOptions();
+ var clientOptions = TestMcpClient.CreateOptions();
clientOptions.Handlers.SamplingHandler = (_, _, _) => throw new UnreachableException();
clientOptions.Handlers.ElicitationHandler = (_, _) => throw new UnreachableException();
await using var client = await ConnectMcpClientAsync(clientOptions);
diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/StreamableHttpClientConformanceTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/StreamableHttpClientConformanceTests.cs
index 649286b09..9bfe39c71 100644
--- a/tests/ModelContextProtocol.AspNetCore.Tests/StreamableHttpClientConformanceTests.cs
+++ b/tests/ModelContextProtocol.AspNetCore.Tests/StreamableHttpClientConformanceTests.cs
@@ -620,9 +620,11 @@ public async Task TasksClient_SendsRoutingNameHeader_EndToEnd()
TransportMode = HttpTransportMode.StreamableHttp,
}, HttpClient, LoggerFactory);
+ var clientOptions = TestMcpClient.CreateOptions();
+ clientOptions.ProtocolVersion = McpProtocolVersions.July2026ProtocolVersion;
await using var client = await McpClient.CreateAsync(
transport,
- new McpClientOptions { ProtocolVersion = "2026-07-28" },
+ clientOptions,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
diff --git a/tests/ModelContextProtocol.Tests/Client/MrtrIntegrationTests.cs b/tests/ModelContextProtocol.Tests/Client/MrtrIntegrationTests.cs
index 86a107fd9..a696978f6 100644
--- a/tests/ModelContextProtocol.Tests/Client/MrtrIntegrationTests.cs
+++ b/tests/ModelContextProtocol.Tests/Client/MrtrIntegrationTests.cs
@@ -155,7 +155,8 @@ public async Task LegacyRequestOnMrtrSession_LogsWarning()
var clientToServer = new Pipe();
var serverToClient = new Pipe();
- var clientOptions = new McpClientOptions { ProtocolVersion = "2026-07-28" };
+ var clientOptions = TestMcpClient.CreateOptions();
+ clientOptions.ProtocolVersion = "2026-07-28";
clientOptions.Handlers.ElicitationHandler = (request, ct) =>
new ValueTask(new ElicitResult { Action = "accept" });
clientOptions.Handlers.SamplingHandler = (request, progress, ct) =>
@@ -411,7 +412,8 @@ public async Task IncompleteResultRetry_OmittingRequestState_StripsStaleStateFro
// Pin to the 2026-07-28 protocol so the client performs the server/discover handshake and
// treats InputRequiredResult as an MRTR round-trip.
- var clientOptions = new McpClientOptions { ProtocolVersion = "2026-07-28" };
+ var clientOptions = TestMcpClient.CreateOptions();
+ clientOptions.ProtocolVersion = "2026-07-28";
clientOptions.Handlers.ElicitationHandler = (_, _) =>
new ValueTask(new ElicitResult
{
diff --git a/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs b/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs
index 87c4ca397..7d40fa6b0 100644
--- a/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs
+++ b/tests/ModelContextProtocol.Tests/ClientIntegrationTestFixture.cs
@@ -50,12 +50,7 @@ public Task CreateClientAsync(string clientId, McpClientOptions? clie
{
if (clientId == "test_server" && clientOptions is null)
{
- // This server supports discovery; slow startup must not trigger legacy fallback.
- clientOptions = new()
- {
- DiscoverProbeTimeout = Timeout.InfiniteTimeSpan,
- InitializationTimeout = TestConstants.DefaultTimeout,
- };
+ clientOptions = TestMcpClient.CreateOptions();
}
return McpClient.CreateAsync(new StdioClientTransport(clientId switch
diff --git a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs
index a05084a86..8d5c53568 100644
--- a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs
+++ b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsToolsTests.cs
@@ -5,6 +5,7 @@
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
+using ModelContextProtocol.Tests.Utils;
using Moq;
using System.Collections;
using System.Collections.Concurrent;
@@ -156,7 +157,7 @@ public async Task Can_Create_Multiple_Servers_From_Options_And_List_Registered_T
await using var server = McpServer.Create(transport, options, loggerFactory, ServiceProvider);
var serverRunTask = server.RunAsync(TestContext.Current.CancellationToken);
- await using (var client = await McpClient.CreateAsync(
+ await using (var client = await TestMcpClient.CreateAsync(
new StreamClientTransport(
serverInput: stdinPipe.Writer.AsStream(),
serverOutput: stdoutPipe.Reader.AsStream(),
diff --git a/tests/ModelContextProtocol.Tests/DiagnosticTests.cs b/tests/ModelContextProtocol.Tests/DiagnosticTests.cs
index db6c2c2c4..3f5bda02b 100644
--- a/tests/ModelContextProtocol.Tests/DiagnosticTests.cs
+++ b/tests/ModelContextProtocol.Tests/DiagnosticTests.cs
@@ -1,6 +1,7 @@
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;
using ModelContextProtocol.Server;
+using ModelContextProtocol.Tests.Utils;
using OpenTelemetry.Trace;
using System.Diagnostics;
using System.IO.Pipelines;
@@ -245,7 +246,7 @@ private static async Task RunConnected(Func action,
{
serverTask = server.RunAsync(TestContext.Current.CancellationToken);
- await using (McpClient client = await McpClient.CreateAsync(
+ await using (McpClient client = await TestMcpClient.CreateAsync(
clientTransport,
cancellationToken: TestContext.Current.CancellationToken))
{
diff --git a/tests/ModelContextProtocol.Tests/Protocol/CacheableResultWarningTests.cs b/tests/ModelContextProtocol.Tests/Protocol/CacheableResultWarningTests.cs
index 20e55a782..891d884c7 100644
--- a/tests/ModelContextProtocol.Tests/Protocol/CacheableResultWarningTests.cs
+++ b/tests/ModelContextProtocol.Tests/Protocol/CacheableResultWarningTests.cs
@@ -117,13 +117,15 @@ public async Task AutoPaginatingOverload_MultiplePages_WarnsOnlyOncePerMethod()
var clientToServer = new Pipe();
var serverToClient = new Pipe();
+ var clientOptions = TestMcpClient.CreateOptions();
+ clientOptions.ProtocolVersion = July2026ProtocolVersion;
var clientTask = McpClient.CreateAsync(
new StreamClientTransport(
clientToServer.Writer.AsStream(),
serverToClient.Reader.AsStream(),
LoggerFactory),
- new McpClientOptions { ProtocolVersion = July2026ProtocolVersion },
+ clientOptions,
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);
@@ -219,12 +221,14 @@ private async Task RunScenarioAsync(
// Pin the protocol version so the client deterministically takes the per-request metadata
// (server/discover) lifecycle for 2026-07-28 and the initialize lifecycle for older versions.
+ var clientOptions = TestMcpClient.CreateOptions();
+ clientOptions.ProtocolVersion = serverProtocolVersion;
var clientTask = McpClient.CreateAsync(
new StreamClientTransport(
clientToServer.Writer.AsStream(),
serverToClient.Reader.AsStream(),
LoggerFactory),
- new McpClientOptions { ProtocolVersion = serverProtocolVersion },
+ clientOptions,
loggerFactory: LoggerFactory,
cancellationToken: cancellationToken);
diff --git a/tests/ModelContextProtocol.Tests/Protocol/ElicitationClientDefaultsTests.cs b/tests/ModelContextProtocol.Tests/Protocol/ElicitationClientDefaultsTests.cs
index e91790512..d43f1311a 100644
--- a/tests/ModelContextProtocol.Tests/Protocol/ElicitationClientDefaultsTests.cs
+++ b/tests/ModelContextProtocol.Tests/Protocol/ElicitationClientDefaultsTests.cs
@@ -43,6 +43,7 @@ public async Task ClientAppliesDefaults_NullContent()
await using ClientElicitationTestTransport transport = new(s_elicitParamsWithDefaults);
await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
{
+ ProtocolVersion = "2025-03-26",
Handlers = new()
{
ElicitationHandler = (_, _) =>
@@ -69,6 +70,7 @@ public async Task ClientAppliesDefaults_EmptyContent()
await using ClientElicitationTestTransport transport = new(s_elicitParamsWithDefaults);
await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
{
+ ProtocolVersion = "2025-03-26",
Handlers = new()
{
ElicitationHandler = (_, _) =>
@@ -94,6 +96,7 @@ public async Task ClientAppliesDefaults_PartialContent()
await using ClientElicitationTestTransport transport = new(s_elicitParamsWithDefaults);
await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
{
+ ProtocolVersion = "2025-03-26",
Handlers = new()
{
ElicitationHandler = (_, _) =>
@@ -132,6 +135,7 @@ public async Task ClientAppliesDefaults_AllFieldsProvided_NoChange()
await using ClientElicitationTestTransport transport = new(s_elicitParamsWithDefaults);
await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
{
+ ProtocolVersion = "2025-03-26",
Handlers = new()
{
ElicitationHandler = (_, _) =>
@@ -168,6 +172,7 @@ public async Task ClientAppliesDefaults_Decline_NoDefaultsApplied()
await using ClientElicitationTestTransport transport = new(s_elicitParamsWithDefaults);
await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
{
+ ProtocolVersion = "2025-03-26",
Handlers = new()
{
ElicitationHandler = (_, _) =>
@@ -188,6 +193,7 @@ public async Task ClientAppliesDefaults_Cancel_NoDefaultsApplied()
await using ClientElicitationTestTransport transport = new(s_elicitParamsWithDefaults);
await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
{
+ ProtocolVersion = "2025-03-26",
Handlers = new()
{
ElicitationHandler = (_, _) => new(new ElicitResult { Action = "cancel" }),
@@ -220,6 +226,7 @@ public async Task ClientAppliesDefaults_SchemaWithNoDefaults_NoChange()
await using ClientElicitationTestTransport transport = new(paramsNoDefaults);
await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
{
+ ProtocolVersion = "2025-03-26",
Handlers = new()
{
ElicitationHandler = (_, _) =>
@@ -271,6 +278,7 @@ public async Task ClientAppliesDefaults_MultiSelectEnum()
await using ClientElicitationTestTransport transport = new(paramsMultiSelect);
await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
{
+ ProtocolVersion = "2025-03-26",
Handlers = new()
{
ElicitationHandler = (_, _) =>
@@ -318,6 +326,7 @@ public async Task ClientAppliesDefaults_TitledSingleSelectEnum()
await using ClientElicitationTestTransport transport = new(paramsTitledEnum);
await using var client = await McpClient.CreateAsync(transport, new McpClientOptions
{
+ ProtocolVersion = "2025-03-26",
Handlers = new()
{
ElicitationHandler = (_, _) =>
@@ -382,6 +391,10 @@ await _incomingToClient.Writer.WriteAsync(new JsonRpcResponse
}, CancellationToken.None);
});
}
+ else if (message is JsonRpcRequest request)
+ {
+ throw new InvalidOperationException($"The elicitation defaults test transport only supports initialize, not '{request.Method}'.");
+ }
else if (message is JsonRpcResponse response)
{
// Capture the raw elicitation response from the client
diff --git a/tests/ModelContextProtocol.Tests/StdioServerIntegrationTests.cs b/tests/ModelContextProtocol.Tests/StdioServerIntegrationTests.cs
index 88604f533..1da26a853 100644
--- a/tests/ModelContextProtocol.Tests/StdioServerIntegrationTests.cs
+++ b/tests/ModelContextProtocol.Tests/StdioServerIntegrationTests.cs
@@ -35,7 +35,7 @@ public async Task SigInt_DisposesTestServerWithHosting_Gracefully()
process.StandardInput.BaseStream,
serverName: "TestServerWithHosting");
- await using var client = await McpClient.CreateAsync(
+ await using var client = await TestMcpClient.CreateAsync(
new TestClientTransport(streamServerTransport),
loggerFactory: LoggerFactory,
cancellationToken: TestContext.Current.CancellationToken);