{
  "schema": "https://ai-atoms.com/schemas/skill-v1.json",
  "type": "skill",
  "id": "skill/mcp-csharp-test",
  "version": "1.0.1",
  "name": "mcp-csharp-test",
  "description": "Test MCP servers at two levels: unit tests for individual tool methods, and integration tests that exercise the full MCP protocol in-memory.",
  "system_prompt_fragment": "# C# MCP Server Testing\n\nTest MCP servers at two levels: unit tests for individual tool methods, and integration tests that exercise the full MCP protocol in-memory.\n\n## When to Use\n\n- Adding automated tests to an MCP server\n- Testing individual tool methods with mocked dependencies\n- Writing integration tests that validate tool listing and invocation via MCP protocol\n- Setting up CI test pipelines for MCP servers\n\n## Stop Signals\n\n- **No server yet?** → Use `mcp-csharp-create` first\n- **Server not running?** → Use `mcp-csharp-debug`\n- **Just need manual/interactive testing?** → Use `mcp-csharp-debug` for MCP Inspector\n\n## Inputs\n\n| Input | Required | Description |\n|-------|----------|-------------|\n| MCP server project path | Yes | Path to the server `.csproj` being tested |\n| Test framework | Recommended | Default: xUnit. Also supports NUnit or MSTest |\n| Transport type | Recommended | Determines integration test approach (stdio vs HTTP) |\n\n## Workflow\n\n### Step 1: Create the test project\n\n```bash\ndotnet new xunit -n <ServerName>.Tests\ncd <ServerName>.Tests\ndotnet add reference ../<ServerName>/<ServerName>.csproj\ndotnet add package ModelContextProtocol\ndotnet add package Moq\ndotnet add package FluentAssertions\n```\n\n### Step 2: Write unit tests for tool methods\n\nTest tool methods directly — fastest and most isolated:\n\n```csharp\npublic class MyToolTests\n{\n    [Fact]\n    public void Echo_ReturnsFormattedMessage()\n    {\n        var result = MyTools.Echo(\"Hello\");\n        result.Should().Be(\"Echo: Hello\");\n    }\n\n    [Theory]\n    [InlineData(\"\")]\n    [InlineData(\"   \")]\n    public void Echo_HandlesEdgeCases(string input)\n    {\n        var result = MyTools.Echo(input);\n        result.Should().StartWith(\"Echo:\");\n    }\n}\n```\n\nFor tools with DI dependencies, mock the dependency:\n```csharp\npublic class ApiToolTests\n{\n    [Fact]\n    public async Task FetchData_ReturnsApiResponse()\n    {\n        var handler = new MockHttpMessageHandler(\"\"\"{\"id\": 1}\"\"\");\n        var httpClient = new HttpClient(handler);\n\n        var result = await ApiTools.FetchData(httpClient, \"resource-1\");\n        result.Should().Contain(\"id\");\n    }\n}\n```\n\n### Step 3: Write integration tests with MCP client\n\nTest the full MCP protocol using a client-server connection:\n\n```csharp\nusing ModelContextProtocol.Client;\n\npublic class ServerIntegrationTests : IAsyncLifetime\n{\n    private McpClient _client = null!;\n\n    public async Task InitializeAsync()\n    {\n        var transport = new StdioClientTransport(new StdioClientTransportOptions\n        {\n            Name = \"TestClient\",\n            Command = \"dotnet\",\n            Arguments = [\"run\", \"--project\", \"../<ServerName>/<ServerName>.csproj\"]\n        });\n        _client = await McpClient.CreateAsync(transport);\n    }\n\n    public async Task DisposeAsync() => await _client.DisposeAsync();\n\n    [Fact]\n    public async Task Server_ListsExpectedTools()\n    {\n        var tools = await _client.ListToolsAsync();\n        tools.Should().Contain(t => t.Name == \"echo\");\n    }\n\n    [Fact]\n    public async Task Tool_ReturnsExpectedResult()\n    {\n        var result = await _client.CallToolAsync(\"echo\",\n            new Dictionary<string, object?> { [\"message\"] = \"Test\" });\n        var text = result.Content.OfType<TextContentBlock>().First().Text;\n        text.Should().Contain(\"Test\");\n    }\n}\n```\n\n**For the SDK's `ClientServerTestBase` (in-memory testing) and HTTP testing with `WebApplicationFactory`**, see [references/test-patterns.md](references/test-patterns.md).\n\n### Step 4: Run tests\n\n```bash\n# Run all tests\ndotnet test\n\n# Run a specific test class\ndotnet test --filter \"FullyQualifiedName~MyToolTests\"\n\n# Run with coverage\ndotnet test --collect:\"XPlat Code Coverage\"\n```\n\n### Step 5: Write evaluations\n\nEvaluations measure how well an LLM uses your tools. Good evaluation questions should be:\n- **Read-only and non-destructive** — never modify data as a side effect\n- **Deterministic** — have a single verifiable correct answer\n- **Multi-step** — require the LLM to call multiple tools or reason across results\n\nFor the evaluation format, example questions, and detailed guidance, see [references/evaluations.md](references/evaluations.md).\n\n## Validation\n\n- [ ] Unit tests cover all tool methods, including edge cases\n- [ ] Integration tests verify tool listing via `ListToolsAsync()`\n- [ ] Integration tests verify tool invocation via `CallToolAsync()`\n- [ ] All tests pass: `dotnet test`\n- [ ] Tests run in CI without manual setup\n\n## Common Pitfalls\n\n| Pitfall | Solution |\n|---------|----------|\n| Integration test hangs on `CreateAsync` | Server fails to start. Verify `dotnet build` succeeds first. For stdio, ensure no stdout logging |\n| `StdioClientTransport` not finding project | Use the correct relative path to `.csproj` from the test project directory |\n| Tests pass locally but fail in CI | Run `dotnet build` before test execution. Use `--no-build` only after an explicit build step |\n| Mocking `HttpClient` is awkward | Mock `HttpMessageHandler`, not `HttpClient` directly. See [references/test-patterns.md](references/test-patterns.md) |\n| Full test suite runs are slow | Use `--filter` for development. Run the full suite only for CI verification |\n\n## Related Skills\n\n- `mcp-csharp-create` — Create a new MCP server project\n- `mcp-csharp-debug` — Running and interactive debugging\n- `mcp-csharp-publish` — NuGet, Docker, Azure deployment\n\n## Reference Files\n\n- [references/test-patterns.md](references/test-patterns.md) — Complete test code examples: `ClientServerTestBase` in-memory pattern, `WebApplicationFactory` for HTTP, `MockHttpMessageHandler` helper, test categorization, coverage reporting. **Load when:** writing integration tests or need detailed mock patterns.\n- [references/evaluations.md](references/evaluations.md) — Evaluation format, question design principles, and example eval questions. **Load when:** user asks about evaluations, eval questions, or measuring tool quality.\n\n## More Info\n\n- [xUnit documentation](https://xunit.net/docs/getting-started/netcore/cmdline) — Getting started with xUnit for .NET",
  "applicable_domains": [
    "code",
    "dotnet",
    "engineering"
  ],
  "invocation": [
    "/mcp-csharp-test"
  ],
  "tags": [
    "dotnet-ai",
    "dotnet",
    "csharp",
    "microsoft"
  ],
  "authored_by": "anthropics",
  "source_url": "https://github.com/dotnet/skills/blob/main/plugins/dotnet-ai/skills/mcp-csharp-test/SKILL.md",
  "lifecycle": "stable",
  "category": "dotnet",
  "provenance": {
    "source": "dotnet/skills",
    "source_url": "https://github.com/dotnet/skills/blob/main/plugins/dotnet-ai/skills/mcp-csharp-test/SKILL.md",
    "author": "Microsoft / .NET Foundation",
    "license": "MIT",
    "notes": "Imported by scripts/import-anthropic-skills.py. Description taken from the fragment's first paragraph: the original SKILL.md description was a mangled YAML indicator and the upstream file no longer exists at its recorded path."
  }
}