Skills mcp-csharp-test
install
source · Clone the upstream repo
git clone https://github.com/dotnet/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/dotnet/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/dotnet-ai/skills/mcp-csharp-test" ~/.claude/skills/dotnet-skills-mcp-csharp-test && rm -rf "$T"
manifest:
plugins/dotnet-ai/skills/mcp-csharp-test/SKILL.mdsource content
C# MCP Server Testing
Test MCP servers at two levels: unit tests for individual tool methods, and integration tests that exercise the full MCP protocol in-memory.
When to Use
- Adding automated tests to an MCP server
- Testing individual tool methods with mocked dependencies
- Writing integration tests that validate tool listing and invocation via MCP protocol
- Setting up CI test pipelines for MCP servers
Stop Signals
- No server yet? → Use
firstmcp-csharp-create - Server not running? → Use
mcp-csharp-debug - Just need manual/interactive testing? → Use
for MCP Inspectormcp-csharp-debug
Inputs
| Input | Required | Description |
|---|---|---|
| MCP server project path | Yes | Path to the server being tested |
| Test framework | Recommended | Default: xUnit. Also supports NUnit or MSTest |
| Transport type | Recommended | Determines integration test approach (stdio vs HTTP) |
Workflow
Step 1: Create the test project
dotnet new xunit -n <ServerName>.Tests cd <ServerName>.Tests dotnet add reference ../<ServerName>/<ServerName>.csproj dotnet add package ModelContextProtocol dotnet add package Moq dotnet add package FluentAssertions
Step 2: Write unit tests for tool methods
Test tool methods directly — fastest and most isolated:
public class MyToolTests { [Fact] public void Echo_ReturnsFormattedMessage() { var result = MyTools.Echo("Hello"); result.Should().Be("Echo: Hello"); } [Theory] [InlineData("")] [InlineData(" ")] public void Echo_HandlesEdgeCases(string input) { var result = MyTools.Echo(input); result.Should().StartWith("Echo:"); } }
For tools with DI dependencies, mock the dependency:
public class ApiToolTests { [Fact] public async Task FetchData_ReturnsApiResponse() { var handler = new MockHttpMessageHandler("""{"id": 1}"""); var httpClient = new HttpClient(handler); var result = await ApiTools.FetchData(httpClient, "resource-1"); result.Should().Contain("id"); } }
Step 3: Write integration tests with MCP client
Test the full MCP protocol using a client-server connection:
using ModelContextProtocol.Client; public class ServerIntegrationTests : IAsyncLifetime { private McpClient _client = null!; public async Task InitializeAsync() { var transport = new StdioClientTransport(new StdioClientTransportOptions { Name = "TestClient", Command = "dotnet", Arguments = ["run", "--project", "../<ServerName>/<ServerName>.csproj"] }); _client = await McpClient.CreateAsync(transport); } public async Task DisposeAsync() => await _client.DisposeAsync(); [Fact] public async Task Server_ListsExpectedTools() { var tools = await _client.ListToolsAsync(); tools.Should().Contain(t => t.Name == "echo"); } [Fact] public async Task Tool_ReturnsExpectedResult() { var result = await _client.CallToolAsync("echo", new Dictionary<string, object?> { ["message"] = "Test" }); var text = result.Content.OfType<TextContentBlock>().First().Text; text.Should().Contain("Test"); } }
For the SDK's
(in-memory testing) and HTTP testing with ClientServerTestBase
, see references/test-patterns.md.WebApplicationFactory
Step 4: Run tests
# Run all tests dotnet test # Run a specific test class dotnet test --filter "FullyQualifiedName~MyToolTests" # Run with coverage dotnet test --collect:"XPlat Code Coverage"
Step 5: Write evaluations
Evaluations measure how well an LLM uses your tools. Good evaluation questions should be:
- Read-only and non-destructive — never modify data as a side effect
- Deterministic — have a single verifiable correct answer
- Multi-step — require the LLM to call multiple tools or reason across results
For the evaluation format, example questions, and detailed guidance, see references/evaluations.md.
Validation
- Unit tests cover all tool methods, including edge cases
- Integration tests verify tool listing via
ListToolsAsync() - Integration tests verify tool invocation via
CallToolAsync() - All tests pass:
dotnet test - Tests run in CI without manual setup
Common Pitfalls
| Pitfall | Solution |
|---|---|
Integration test hangs on | Server fails to start. Verify succeeds first. For stdio, ensure no stdout logging |
not finding project | Use the correct relative path to from the test project directory |
| Tests pass locally but fail in CI | Run before test execution. Use only after an explicit build step |
Mocking is awkward | Mock , not directly. See references/test-patterns.md |
| Full test suite runs are slow | Use for development. Run the full suite only for CI verification |
Related Skills
— Create a new MCP server projectmcp-csharp-create
— Running and interactive debuggingmcp-csharp-debug
— NuGet, Docker, Azure deploymentmcp-csharp-publish
Reference Files
- references/test-patterns.md — Complete test code examples:
in-memory pattern,ClientServerTestBase
for HTTP,WebApplicationFactory
helper, test categorization, coverage reporting. Load when: writing integration tests or need detailed mock patterns.MockHttpMessageHandler - references/evaluations.md — Evaluation format, question design principles, and example eval questions. Load when: user asks about evaluations, eval questions, or measuring tool quality.
More Info
- xUnit documentation — Getting started with xUnit for .NET