Run .NET benchmarks from an LLM.
An MCP (Model Context Protocol) server in C# that executes BenchmarkDotNet on demand and returns results & artifacts. Works with MCP Inspector and GitHub Copilot Chat (Tools) in Visual Studio.
Maintained by Aliaksandr Marozka — amarozka.dev
TL;DR – Ask your AI to “run the hash benchmarks,” get back Mean/Alloc deltas and Markdown/JSON/CSV artifacts. Perfect for demoing MCP, perf checks in PRs, or quick regression hunts.
- MCP tools
run_bench(filter?, job?, exporters?, timeoutSec?)– run benchmarks, get arunId+ brief JSON summaryget_results(runId)– parsed JSON summary (Mean, Alloc/Op, etc.)list_artifacts(runId)– list all files (JSON / Markdown / CSV / logs)compare_runs(baseRunId, headRunId)– simple deltas (% change for Mean & AllocatedBytes/Op)
- Job presets:
Short,Medium,Long - Exporters:
json,fulljson,md,csv - Clients: MCP Inspector (stdio) and Visual Studio (Copilot Chat Tools)
Mcp.BenchmarkRunner.sln
│
├─ src/
│ ├─ Mcp.BenchmarkRunner.Server/ # MCP server (console)
│ │ ├─ Program.cs # host + stdio transport + attribute discovery
│ │ └─ Tools/
│ │ ├─ BenchTools.cs # run_bench / get_results / list_artifacts
│ │ └─ CompareTools.cs # compare_runs
│ │
│ └─ SampleBenchmarks/ # BenchmarkDotNet executable
│ ├─ Program.cs # CLI: --artifacts/--exporters/--job/--filter
│ ├─ Jobs.cs # Short/Medium/Long presets
│ └─ HashBench.cs # MD5 vs SHA256 demo
│
└─ runs/ # output per runId (created at runtime)
Flow: Inspector/Copilot → MCP server (stdio) → spawns dotnet run on SampleBenchmarks → BDN writes artifacts → server returns JSON/paths.
- .NET SDK 9.0 (or switch both projects to .NET 8.0)
- (Optional) Node.js for MCP Inspector (
npx)
dotnet restore
dotnet build
# Run benchmarks without MCP (sanity)
dotnet run --project src/SampleBenchmarks/SampleBenchmarks.csproj -c Release -- \
--artifacts runs/manual1 --exporters json,md --job Short --filter *Hash*
# Start the MCP server
dotnet run --project src/Mcp.BenchmarkRunner.ServerArtifacts appear under runs/<runId or manual1>.
Start Inspector:
npx -y @modelcontextprotocol/inspector
# or:
npm i -g @modelcontextprotocol/inspector
mcp-inspectorConnect (stdio):
- Command:
dotnet - Args:
run --project src/Mcp.BenchmarkRunner.Server/Mcp.BenchmarkRunner.Server.csproj
Example payloads:
{ "filter": "*Hash*", "job": "Short", "exporters": "json,md" }{ "BaseRunId": "<first>", "HeadRunId": "<second>" }Windows npm ENOENT fix
Ifnpxfails with%APPDATA%\npmnot found:
mkdir "%APPDATA%\npm" && npm config set prefix "%APPDATA%\npm"and add%APPDATA%\npmto PATH.
{
"servers": {
"benchrunner": {
"name": "Benchmark Runner",
"type": "stdio",
"command": "dotnet",
"args": [
"run",
"--project",
"src/Mcp.BenchmarkRunner.Server/Mcp.BenchmarkRunner.Server.csproj"
]
}
}
}{
"servers": {
"benchrunner": {
"name": "Benchmark Runner",
"type": "stdio",
"command": "dotnet",
"args": [
"run",
"--project",
"C:\\path\\to\\repo\\src\\Mcp.BenchmarkRunner.Server\\Mcp.BenchmarkRunner.Server.csproj"
]
}
}
}Use it: View → GitHub Copilot Chat → Tools/Agent → enable Benchmark Runner → run:
run_bench→ grabrunIdget_results/list_artifactscompare_runswith two runIds
Logs: View → Output → GitHub Copilot.
{ "filter": "string?", "job": "Short|Medium|Long", "exporters": "json|fulljson|md|csv", "timeoutSec": 600 }Returns: { "runId": "string", "artifactsDir": "path", "summary": { ... } }
{ "runId": "string" }Returns: parsed JSON exporter object or null.
{ "runId": "string" }Returns: list of file paths under runs/<runId>.
{ "BaseRunId": "string", "HeadRunId": "string" }Returns: rows with Mean/Alloc base/head and %Δ.
restore failed- Enable
nuget.orgsource; clear caches:
dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org
dotnet nuget locals all --clear - Enable prerelease (MCP SDK is preview) or switch both projects to
net8.0.
- Enable
- Benchmarks work in CLI but fail via MCP
- Typically a path issue when launching from
bin/…. - Walk up 5 levels from
AppContext.BaseDirectoryto repo root or auto-detect the root (look for.sln/src).
- Typically a path issue when launching from
dotnetnot found in VS- Add
C:\\Program Files\\dotnet\\to user PATH and restart Visual Studio.
- Add
upload_projecttool: zip → sandbox → run user benchmarksDisassemblyDiagnosertool for hot-path asm dumps- Publish as
dotnet newtemplate or a NuGet tool - CI hook: post
compare_runsdeltas on PRs
Built by Aliaksandr Marozka — amarozka.dev
MIT