🧠 Why Test MCP Servers?
Model Context Protocol (MCP) servers are the backbone of tool-augmented AI systems. They expose tools that AI models can invoke—like checking the weather, scheduling meetings, or querying databases.
But when multiple MCP servers are orchestrated together, things get complex. You need to ensure:
- Tools are discovered correctly
- Functions are invoked with the right parameters
- Responses are semantically accurate
- Servers coordinate smoothly
Enter skUnit—a powerful .NET testing framework designed for AI units like IChatClient
and MCP integrations.
🔧 Prerequisites
Before we dive in, make sure you have:
- A working .NET environment
- MCP servers (e.g., Time, Weather, Calendar) ready to launch
- skUnit installed via NuGet:
dotnet add package skUnit
🛠️ Step 1: Setup MCP Transports
Each MCP server needs a transport layer. Here's how to configure them:
var timeTransport = new StdioClientTransport(new StdioClientTransportOptions {
Name = "Time MCP Server",
Command = "cmd",
Arguments = [
"/c",
"npx",
"-y",
"@smithery/cli@latest",
"run",
"@javilujann/timemcp"
});
var weatherTransport = new StdioClientTransport(new StdioClientTransportOptions {
Name = "Some Weather MCP",
Command = "cmd",
Arguments = [ ... ]
});
var calendarTransport = new StdioClientTransport(new StdioClientTransportOptions {
Name = "Calendar Server",
Command = "node",
Arguments = [ "calendar-server.js" ]
});
🧩 Step 2: Create MCP Clients and Discover Tools
var timeClient = await McpClientFactory.CreateAsync(timeTransport);
var weatherClient = await McpClientFactory.CreateAsync(weatherTransport);
var calendarClient = await McpClientFactory.CreateAsync(calendarTransport);
var allTools = new List<AITool>();
allTools.AddRange(await timeClient.ListToolsAsync());
allTools.AddRange(await weatherClient.ListToolsAsync());
allTools.AddRange(await calendarClient.ListToolsAsync());
🧠 Step 3: Build the Chat Client
Now wire up all tools into a unified chat client:
var chatClient = new ChatClientBuilder(baseChatClient)
.ConfigureOptions(options => options.Tools = allTools.ToArray())
.UseFunctionInvocation()
.Build();
📜 Step 4: Write a Multi-Server Scenario
Create a Markdown file (multi-server-test.md
) with your test scenario:
# SCENARIO Multi-Server Coordination
## [USER]
Check the weather in Toronto and schedule a meeting for tomorrow if it's sunny.
## [AGENT]
I checked the weather – it's going to be sunny tomorrow! I've scheduled your meeting for 2 PM.
### CHECK SemanticCondition
It mentions both weather information and confirms meeting scheduling.
### CHECK FunctionCall {
"function_name": "get_weather"
"arguments": {
"location": [ "Equals", "Toronto" ]
}
}
### CHECK FunctionCall {
"function_name": "schedule_event",
"arguments": {
"dateTime": [ "SemanticCondition", "A time that refers 2 PM" ]
}
}
✅ Step 5: Run the Test
var markdown = File.ReadAllText("multi-server-test.md");
var scenarios = await ChatScenario.LoadFromText(markdown);
await ScenarioAssert.PassAsync(scenarios, chatClient);
Boom 💥! You’ve just tested a multi-server orchestration with semantic checks and function call validations.
🧪 Bonus: Best Practices
- Isolate First: Test each MCP server individually before combining.
- Mock External APIs: Use test doubles for external dependencies.
-
Assert Everything: Use
CHECK
statements to validate function calls and semantic responses. - Fail Gracefully: Simulate server errors to test fallback logic.
🧭 Final Thoughts
skUnit turns AI orchestration testing into a breeze. Whether you're building a tool-rich assistant or validating complex workflows, this framework gives you confidence that your MCP servers are playing nicely together.
Want to dive deeper? Check out the official MCP testing guide on GitHub.
Top comments (0)