Edit

Server mode

MTP server mode lets an editor, IDE, or other test tool launch a test application and drive discovery and execution through JSON-RPC. Use server mode when you build tooling around MTP. For normal command-line and CI runs, run the test application directly or use dotnet test.

Start the public JSON-RPC server with --server or --server jsonrpc.

Important

The .NET SDK uses a separate internal binary protocol through --server dotnettestcli. Don't pass that value yourself. dotnet test configures the transport and protocol arguments.

Use the source-only client

MTP 2.4 provides a canonical JSON-RPC client. Add the Microsoft.Testing.Platform.ServerMode.Client.Sources package. The package injects C# source into your project instead of adding a runtime assembly.

The source-only design provides:

  • No runtime DLL or additional deployment dependency.
  • Native AOT-compatible, reflection-free serialization.
  • Protocol types and serialization code from the same repository as the MTP server.

The injected MtpServerClient, IMtpServerClient, and protocol types can initialize a connection, discover tests, run tests, request server exit, and report test-node updates. All injected types remain internal to the consuming assembly.

Meet client requirements

Use C# 12 or later. The package respects your project's language-version setting. If your target framework defaults to an earlier C# version, set LangVersion to 12.0 or later. The package also supplies internal compatibility types for .NET Framework 4.6.2 and netstandard2.0.

Remove any hand-written copy of the MTP client before you add the package to avoid duplicate internal types.

Choose a launch model

To start the test application as an external process, use MtpServerClient.LaunchAsync. The client owns that child process and terminates it during teardown when needed.

For an embedded host or UI-thread environment that can't use Process.Start, use MtpServerClient.LaunchInProcessAsync. The method runs the test application through an asynchronous callback in the current process. Don't block the launching thread because the callback and client share the process.

Both launch models use a loopback TCP transport. Browser WebAssembly can't create the required listener, so in-process launch throws PlatformNotSupportedException. In-process launch doesn't provide an alternative WebAssembly transport.

Shut down the client

To tear down the client and launched application without blocking the calling thread, call IMtpServerClient.ShutdownAsync(). The asynchronous method avoids UI-thread responsiveness and deadlock problems in embedded hosts.

For an in-process host, MtpServerClientOptions.ServerShutdownTimeout controls how long teardown waits after the client closes the transport. The default is 30 seconds. Read ServerExitCode after shutdown to get the callback's exit code. The value remains null while the application runs or when the application fails instead of returning an exit code.

Declare client statefulness

Starting with MTP 2.4.1, set the nullable MtpServerClientOptions.IsStateful option to describe how the client consumes test-node updates:

Value Declaration
true The client retains an addressable set of test nodes for the session and keeps each node's last-known state until another update changes it, as an IDE test explorer might.
false The client consumes updates without retaining that test-node state.
null (default) The client doesn't declare the capability. The initialize handshake omits the field.

The client sends an explicit Boolean value through the experimental capabilities.testing.isStateful protocol capability. Statefulness is independent of connection lifetime and the server's MultiRequestSupport capability. A client doesn't become stateful merely because it sends several requests over the same connection.

MTP 2.4.0 uses a non-nullable Boolean option with a default of false. To preserve an undeclared capability, use MTP 2.4.1 or later.

Inside a framework or extension, use the experimental IClientInfo service to inspect the declaration. Read clientInfo.Capabilities.IsStateful for a conservative Boolean result, which is false when the capability is undeclared. In MTP 2.4.1 or later, ClientCapabilitiesExtensions.GetIsStateful() preserves the distinction between undeclared, explicitly stateless, and stateful clients.

Negotiate protocol compatibility

Starting with MTP 2.4, server-mode protocol negotiation is independent from the MTP NuGet package version. A client declares the protocol versions that it supports, and the server selects a common version. When no supported version overlaps, the test application exits with the ProtocolError exit code (12) instead of continuing with an incompatible wire contract.

Use the versioned server-mode 1.0 JSON schema to validate messages. The System.Text.Json and Jsonite serializers follow the same schema and error envelope.

See also