Some build failures are easy - the error tells you exactly what to fix. Then there are the others: a property that mysteriously has the wrong value, a stale DLL being copied from who-knows-where, a build that works locally but fails in CI, or a multi-targeted project that behaves differently per framework. Staring at console output (or a 200 MB diagnostic text log) is a slow way to solve these.
MSBuild binary logs (binlogs) capture everything the build did - every project, property, item, task, and environment variable - in a compact, searchable file.
Add -bl to any build-related command:
dotnet build -bldotnet restore -bl:restore.binlogdotnet publish -bl:publish.binlog
This produces an msbuild.binlog file (or the name you specified) in the current directory.
For builds started inside Visual Studio, install the Project System Tools extension to capture binlogs from IDE builds.
Open the file in the free MSBuild Structured Log Viewer - it turns the log into a navigable tree with full-text search.
Things that are painful with console output and trivial in the viewer:
$property TargetFramework and see every assignment, including which .props file set it. Invaluable when debugging Directory.Build.props inheritance and multi-targeting conditionsNU1605 downgrade or version conflict was resolvedBinlogs aren't just for humans. The Microsoft Binlog MCP Server lets AI assistants (GitHub Copilot, Claude Code, etc.) query a binlog directly - it's built on the same engine as the Structured Log Viewer and exposes tools for exactly the investigations above: errors and warnings with full context, property tracing, the most expensive projects/targets/tasks, embedded file search, and comparing 2 builds.
The easiest setup is the dotnet-msbuild plugin from the .NET Agent Skills repo, which bundles the MCP server with curated skills for build investigation. You can also register the server manually:
{"servers": {"binlog-mcp": {"type": "stdio","command": "dotnet","args": ["tool", "run", "Microsoft.AITools.BinlogMcp"]}}}
✅ Good example - .vscode/mcp.json registering the Binlog MCP Server as a dotnet tool
Once connected, capture a binlog and ask questions like:
TargetFramework get its value in MyProject?"local.binlog and ci.binlog - why is CI slower?"This also works beyond the chat window - an agent in your pipeline can pick up the binlog from a failed build and post a diagnosis, see MCP Beyond the Chat Window: Build Diagnostics in CI.
dotnet build -v:diag > build.log
❌ Bad example - Diagnostic verbosity dumps hundreds of MB of unsearchable text and still misses structure
dotnet build -bl
✅ Good example - A binlog is smaller, complete, and opens in a purpose-built viewer
The worst place to debug a build is a CI agent you can't touch. Produce a binlog in your pipeline and upload it as an artifact when the build fails:
- name: Buildrun: dotnet build -bl:build.binlog- name: Upload binlogif: failure()uses: actions/upload-artifact@v4with:name: binlogpath: build.binlog
✅ Good example - GitHub Actions publishing a binlog on failure, so "works on my machine" arguments end with evidence
A binlog embeds environment variables, command lines, and the full content of your project and targets files. Treat it like a memory dump: