ZeroMcp.TestKit.Xunit
xUnit integration for ZeroMcp.TestKit β adds [McpFact] and [McpTheory] attributes, McpAssert static helpers, and fluent assertion chains for testing MCP servers in Visual Studio Test Explorer.
Ask AI about ZeroMcp.TestKit.Xunit
Powered by Claude Β· Grounded in docs
I know everything about ZeroMcp.TestKit.Xunit. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
ZeroMcp.TestKit β .NET DSL
A fluent .NET API for testing MCP (Model Context Protocol) servers. Wraps the mcptest Rust engine and integrates with xUnit for Visual Studio Test Explorer support.
Quick Start
using ZeroMcp.TestKit;
await McpTest
.Server("http://localhost:8000/mcp")
.Tool("search")
.WithParams(new { query = "hello" })
.ExpectSchemaMatch()
.ExpectDeterministic()
.RunAsync();
Packages
| Package | Purpose |
|---|---|
ZeroMcp.TestKit | Core DSL, models, engine runner |
ZeroMcp.TestKit.Xunit | xUnit attributes ([McpFact], [McpTheory]) and McpAssert |
Engine Resolution
The mcptest binary is located automatically in this order:
MCPTEST_PATHenvironment variable (full path to binary)- NuGet native assets (
runtimes/{rid}/native/mcptest) - System
PATH
Override per-builder: .WithEnginePath("path/to/mcptest")
Fluent API
await McpTest
.Server("http://localhost:8000/mcp")
.WithTimeout(TimeSpan.FromSeconds(30))
.WithDeterminismRuns(5)
.ValidateProtocol()
.ValidateMetadata()
.WithAutoErrorTests()
.Tool("search")
.WithParams(new { query = "hello" })
.ExpectSchemaMatch()
.ExpectDeterministic()
.WithIgnorePaths("$.result.timestamp")
.Tool("echo")
.WithParams(new { text = "world" })
.ExpectSchemaMatch()
.RunAsync();
Key Methods
McpServerBuilder (from McpTest.Server(url)):
.WithTimeout(TimeSpan)β global timeout.WithDeterminismRuns(int)β number of re-runs for determinism checks.ValidateProtocol()β enable MCP handshake + JSON-RPC frame validation.ValidateMetadata()β validate tool name, description, inputSchema.WithAutoErrorTests()β auto-generate error-path tests.Tool(name)β add a tool test case
McpToolBuilder (from .Tool(name)):
.WithParams(object)β tool call parameters.ExpectSchemaMatch()β validate output against declared schema.ExpectDeterministic()β assert identical output across runs.WithIgnorePaths(params string[])β JSONPath fields to skip in determinism.ExpectError()/.ExpectErrorCode(long)β error-path testing.ExpectMinStreamChunks(int)β streaming validation.WithTimeout(TimeSpan)β per-tool timeout override
Execution:
.RunAsync()β execute and throwMcpTestExceptionon failure.RunWithoutThrowAsync()β execute and return result without throwing
xUnit Integration
using ZeroMcp.TestKit;
using ZeroMcp.TestKit.Xunit;
public class MyMcpServerTests
{
[McpFact(DisplayName = "search returns valid schema")]
public async Task SearchToolSchemaValid()
{
await McpTest
.Server("http://localhost:8000/mcp")
.Tool("search")
.WithParams(new { query = "hello" })
.ExpectSchemaMatch()
.RunAsync();
}
}
McpAssert Helpers
var result = await McpTest
.Server("http://localhost:8000/mcp")
.Tool("search").WithParams(new { query = "hi" }).ExpectSchemaMatch()
.RunWithoutThrowAsync();
McpAssert.Passed(result);
McpAssert.ToolPassed(result, "search");
McpAssert.SchemaValid(result, "search");
McpAssert.Deterministic(result, "search");
Response Value Assertions
The engine now includes the raw MCP server response in each tool result. Use these helpers to assert on specific response properties and values:
var result = await McpTest
.Server("http://localhost:8000/mcp")
.Tool("search").WithParams(new { query = "hi" })
.RunWithoutThrowAsync();
// Assert a specific property path has an expected value
McpAssert.ResponseContains(result, "search", "content[0].text", "hello world");
// Assert a property exists at a given path
McpAssert.ResponseHasProperty(result, "search", "content[0].type");
// Get the raw JsonElement for custom assertions
var response = McpAssert.GetResponse(result, "search");
Assert.Equal("text", response.GetProperty("content")[0].GetProperty("type").GetString());
Fluent Assertion Chains
var result = await McpTest
.Server("http://localhost:8000/mcp")
.Tool("search").WithParams(new { query = "hi" })
.RunWithoutThrowAsync();
result
.Passed()
.HasToolName("search")
.HasValidSchema("search")
.HasReturnProperty("content")
.HasReturnValue("search", "content[0].type", "text");
Project Structure
dotnet/
βββ ZeroMcp.TestKit.slnx
βββ src/
β βββ ZeroMcp.TestKit/ # Core DSL library
β β βββ Models/
β β β βββ McpTestDefinition.cs
β β β βββ McpTestResult.cs
β β βββ McpTest.cs
β β βββ McpServerBuilder.cs
β β βββ McpToolBuilder.cs
β β βββ McpTestRunner.cs
β β βββ EngineResolver.cs
β β βββ McpTestException.cs
β βββ ZeroMcp.TestKit.Xunit/ # xUnit integration
β βββ McpFluentAssertions.cs
β βββ McpFactAttribute.cs
β βββ McpTheoryAttribute.cs
β βββ McpAssert.cs
βββ tests/
βββ ZeroMcp.TestKit.Tests/ # Unit tests (33 passing)
βββ Models/
β βββ McpTestDefinitionTests.cs
β βββ McpTestResultTests.cs
βββ FluentApiTests.cs
βββ McpTestExceptionTests.cs
βββ McpAssertResponseTests.cs
βββ EngineResolverTests.cs
Building
dotnet build
dotnet test
Requirements
- .NET 8.0 SDK
mcptestbinary (see Engine Resolution above)
License
MIT
