Microsoft.AITools.BinlogMcp
1.0.0
Prefix Reserved
dotnet tool install --global Microsoft.AITools.BinlogMcp --version 1.0.0
dotnet new tool-manifest
dotnet tool install --local Microsoft.AITools.BinlogMcp --version 1.0.0
#tool dotnet:?package=Microsoft.AITools.BinlogMcp&version=1.0.0
nuke :add-package Microsoft.AITools.BinlogMcp --version 1.0.0
MSBuild Binlog MCP Server
An MCP (Model Context Protocol) server for MSBuild binary log (.binlog) analysis, providing 31 tools for AI-assisted build investigation, performance analysis, and comparison.
Bug reports
For bug reports and support please use the https://github.com/dotnet/skills repository
Notice
The tool is meant to be used solely by the plugins distributed via https://github.com/dotnet/skills, Microsoft does not guarantees and compatibility nor support for direct usages. The MCP and its implementation are considered internal technical details of the msbuild skills.
Overview
This tool parses MSBuild binary logs using the StructuredLogger library and exposes them through the MCP protocol. It enables AI assistants to investigate build failures, trace property origins, analyze performance bottlenecks, and compare builds — all through structured tool calls.
Key capabilities:
- StructuredLog Viewer search DSL with tree-format output and stable node
[id]s - Property origin tracing — find which file/target/task set a property
- Performance analysis — expensive projects, targets, and tasks
- Embedded file inspection — read and search .csproj/.props/.targets files captured during build
- Query result caching for repeated tool calls
- LRU memory management for multiple loaded binlogs
Tools (33)
Investigation (10)
| Tool | Description |
|---|---|
binlog_overview |
Build status, duration, project count, error/warning counts. Start here. |
binlog_errors |
Build errors with project, target, task, file, and line context |
binlog_warnings |
Build warnings, filterable by warning code |
binlog_search |
Search using StructuredLog Viewer DSL — returns hierarchical tree with node [id]s |
binlog_projects |
List all projects with status and duration |
binlog_properties |
MSBuild property values (curated defaults or filtered) |
binlog_compare_property |
Compare a property's value across all projects in one call (e.g. find which projects lack Configuration as a global property) |
binlog_items |
MSBuild items (PackageReference, Compile, etc.) |
binlog_imports |
Full import chain (.props/.targets files) |
binlog_explain_property |
Traces where a property gets its value (file/target/task that set it) |
Specialized diagnostics (5)
| Tool | Description |
|---|---|
binlog_assembly_conflicts |
MSB3277 / RAR analysis — extracts assembly version conflicts plus the RAR task parameters (AppConfigFile, Assemblies) per target framework |
binlog_diagnose |
Automated build diagnosis: failed targets, missing references, double writes, slow analyzers |
binlog_double_writes |
Detect files written by multiple tasks/targets (build correctness issue) |
binlog_compiler |
Extract compiler (Csc/Vbc/Fsc) command-line invocations, response files, and key switches |
binlog_nuget |
NuGet package restore information: resolved packages, versions, sources, duration |
Files (3)
| Tool | Description |
|---|---|
binlog_files |
List or retrieve source files embedded in the binlog (App.config, .csproj, .props, .targets) with paginated line-range reads |
binlog_search_files |
Search text or regex across all embedded source files with configurable context lines |
binlog_preprocess |
Preprocessed view of a project file with its full import chain (equivalent to msbuild /pp) |
Tree navigation (1)
| Tool | Description |
|---|---|
binlog_explore_node |
Navigate the build log tree by node ID — shows ancestor chain, node details, and children at configurable depth. Use with IDs from binlog_search to freely walk the tree. |
Targets & tasks (5)
| Tool | Description |
|---|---|
binlog_project_targets |
List targets executed in a specific project with timing and skip status |
binlog_search_targets |
Search for targets by name across all projects |
binlog_target_reasons |
Why a target ran or was skipped (inputs/outputs, dependency chain) |
binlog_tasks_in_target |
List all tasks within a specific target of a project |
binlog_task_details |
Full input parameters and output messages of a specific task execution (essential for RAR / Exec / Copy investigation) |
Evaluations (3)
| Tool | Description |
|---|---|
binlog_evaluations |
List project evaluations (project + TFM combinations) with their IDs |
binlog_evaluation_properties |
All evaluated properties for a specific project+TFM |
binlog_evaluation_global_properties |
Global properties (Configuration, Platform, TargetFramework) per evaluation — essential for diagnosing configuration mismatches |
Performance (5)
| Tool | Description |
|---|---|
binlog_expensive_projects |
Slowest projects by exclusive duration |
binlog_expensive_targets |
Slowest targets across the build |
binlog_expensive_tasks |
Slowest tasks across the build |
binlog_expensive_analyzers |
Slowest Roslyn analyzers and source generators |
binlog_project_target_times |
Target-level timing breakdown for a specific project |
Comparison (1)
| Tool | Description |
|---|---|
binlog_compare |
Diff two binlogs (properties, packages) |
Prompts (2)
| Prompt | Description |
|---|---|
analyze_errors |
Step-by-step error investigation workflow |
analyze_performance |
Step-by-step performance investigation workflow |
Setup
VS Code
Add to your .vscode/mcp.json:
{
"servers": {
"binlog-mcp": {
"type": "stdio",
"command": "dotnet",
"args": ["run", "--project", "<path-to>/src/Microsoft.AITools.BinlogMcp/Microsoft.AITools.BinlogMcp.csproj"]
}
}
}
Or if installed as a global tool:
{
"servers": {
"binlog-mcp": {
"type": "stdio",
"command": "binlog-mcp"
}
}
}
Pre-loading binlogs
Pass --binlog <path> to pre-load a binlog at startup:
{
"servers": {
"binlog-mcp": {
"type": "stdio",
"command": "binlog-mcp",
"args": ["--binlog", "msbuild.binlog"]
}
}
}
Search DSL Reference
The binlog_search tool uses the native StructuredLog Viewer search syntax and returns results as a hierarchical tree with stable [id] references:
200 result(s) (matched=200)
Project MyApp.csproj → Build [123]
Target CoreCompile [124]
Task Csc [125]
Error CS0246: The type 'Foo' could not be found [126]
| Token | Example | Meaning |
|---|---|---|
| plain text | error |
Case-insensitive substring match |
"quoted" |
"error CS0246" |
Exact phrase match |
$error |
$error |
All error nodes |
$warning |
$warning |
All warning nodes |
$task |
$task Csc |
Tasks (optionally named) |
$target |
$target CoreCompile |
Targets (optionally named) |
$project |
$project MyApp |
Project nodes |
$property |
$property name=Config |
Properties with field match |
$item |
$item PackageReference |
Items by type |
$time |
$task $time |
Include timing info, sorted slowest first |
under(query) |
under($project MyApp) $error |
Scope to under a parent |
not(query) |
not($warning) |
Exclude nodes |
name=value |
name=Configuration value=Debug |
Field match |
Architecture
Microsoft.AITools.BinlogMcp.Core/ Query engine (no MCP dependency)
├── BinlogAnalyzer.cs Binlog loading via StructuredLogger
├── TreeHelpers.cs Ancestor traversal utilities
├── Models/Models.cs Shared result types
└── Queries/ One query class per tool category
├── BuildOverviewQuery.cs
├── DiagnosticsQuery.cs
├── PropertiesQuery.cs
├── PerformanceQueries.cs
└── ...
Microsoft.AITools.BinlogMcp/ MCP server (stdio transport)
├── Program.cs Host setup, tool registration
├── BinlogCache.cs LRU cache with file-change detection
├── Tools/ One tool class per MCP tool
│ ├── OverviewTool.cs
│ ├── SearchTool.cs
│ └── ...
├── Prompts/ MCP prompt templates
│ └── BinlogPrompts.cs
└── instructions/ LLM guidance
└── server-instructions.md
The Core library has no MCP dependency and can be reused independently. The MCP layer is a thin wrapper that registers tools, manages caching, and handles the stdio transport.
Data Collection
The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described below. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft's privacy statement. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
Telemetry configuration
Telemetry collection is on by default to help improve the product. It can be disabled at any time.
Disabling telemetry
Set the standard .NET CLI opt-out environment variable to 1 or true (case-insensitive) before starting the MCP server:
export DOTNET_CLI_TELEMETRY_OPTOUT=true
Windows PowerShell:
$env:DOTNET_CLI_TELEMETRY_OPTOUT = "true"
When opted out the server starts no telemetry spans, records no metric values, and performs no hashing — nothing is emitted from BinlogTelemetry at all.
What is collected
Telemetry is emitted via .NET System.Diagnostics.ActivitySource, System.Diagnostics.Metrics.Meter, and Microsoft.Extensions.Logging.ILogger, with the in-process OpenTelemetry SDK wired up at startup. By default the SDK subscribes to the binlog-mcp source, runs the BinlogTelemetryEnricher (which stamps the correlation tags described below), writes one JSON file per activity to a local folder, and ships a structured log record per emit point to Microsoft via Azure Application Insights using the Azure Monitor direct log exporter (no local collector required). Activity spans themselves are not exported to Application Insights — the log record carries the same payload and inherits the span's trace context for correlation. Set DOTNET_CLI_TELEMETRY_OPTOUT=1 to disable all destinations.
Where the data goes
The pipeline has three destinations:
| Destination | Default | How to opt out |
|---|---|---|
| Azure Application Insights (Microsoft-owned resource, ingested over HTTPS via the Azure Monitor OpenTelemetry direct log exporter; one log record per emit point) | On | DOTNET_CLI_TELEMETRY_OPTOUT=1 |
Local JSON dump — %LOCALAPPDATA%/Microsoft/BinlogMcp/telemetry/<run-guid>/N-tool_binlog_<name>.json (one file per activity span, never leaves the box) |
On | DOTNET_CLI_TELEMETRY_OPTOUT=1 or BINLOG_MCP_TELEMETRY_NO_LOCAL_LOG=1 |
| External OTLP collector (copilot-watson, Aspire Dashboard, Jaeger, ...) — receives activity spans | Off | Set OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 (and optionally OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf) to enable |
This matches the NuGet MCP server's posture: on by default, single canonical opt-out via DOTNET_CLI_TELEMETRY_OPTOUT, with finer-grained per-destination toggles available for advanced users.
On first run the server prints a one-line notice to stderr (never stdout — stdout is the MCP JSON-RPC transport) pointing here. A sentinel file at %LOCALAPPDATA%\Microsoft\BinlogMcp\.first-run-notice-<version> keeps subsequent runs silent.
Correlation tags (stamped on every span)
BinlogTelemetryEnricher automatically attaches these tags to every activity emitted by the server so a downstream collector can group them into one logical run:
| Tag | Source | Purpose |
|---|---|---|
binlog.run_guid |
Guid.NewGuid() at process startup |
Group all spans from a single MCP stdio session, even tool calls that aren't parented to each other. Also used as the folder name under LOCALAPPDATA for the JSON dump. |
binlog.custom_marker |
BINLOG_MCP_TELEMETRY_MARKER env var (truncated to 128 chars) |
Tag benchmark / eval runs so they can be filtered or grouped downstream |
binlog.build_version |
Assembly version | Distinguish runs by tool version |
binlog.is_development |
Only when DOTNET_ENVIRONMENT=Development |
Filter out local dev traffic |
binlog.run_guid is a process-scoped random GUID, not a stable user id. binlog.custom_marker is whatever the operator chooses to put in the env var — keep PII out of it.
Trace span tags (per tool call)
All custom properties carry the unique binlog. prefix so that telemetry-backend property classifications never collide with properties emitted by other products to the same table. Spans are named tool_binlog/<tool> so the root segment uniquely identifies this product for ownership inference.
| Tag | Example | Customer-influenced | Notes |
|---|---|---|---|
binlog.mcp.tool.name |
binlog_overview |
No | Fixed tool name from the server registration |
binlog.mcp.server.name |
binlog-mcp |
No | Constant |
binlog.file.hash |
a3f1c8e9d2b46758 |
Yes — hashed | HMAC-SHA256 of the binlog filename (path stripped) truncated to 16 hex chars |
binlog.result.chars |
1234 |
No | Size of response in characters |
binlog.result.error |
false |
No | Whether the call failed |
binlog.error.message.hash |
b71e2f4a90c83d65 |
Yes — hashed | HMAC-SHA256 of Exception.Message (only on error). Raw text never leaves the process. |
binlog.exception.type |
System.IO.FileNotFoundException |
No | Exception type name (only on error) |
binlog.exception.stack.hash |
c92d4f1a8b03e756 |
Yes — hashed | HMAC-SHA256 of the stack trace (only on error). Raw text never leaves the process. |
Metrics
| Metric | Type | Tags | Description |
|---|---|---|---|
binlog.tool.call.count |
Counter | binlog.tool (fixed) |
Total tool calls |
binlog.tool.error.count |
Counter | binlog.tool (fixed) |
Failed tool calls |
binlog.tool.call.duration |
Histogram (ms) | binlog.tool (fixed) |
Tool call latency |
binlog.tool.result.size |
Histogram (chars) | binlog.tool (fixed) |
Response sizes |
binlog.load.count |
Counter | — | Binlog file loads |
binlog.load.duration |
Histogram (ms) | binlog.file.hash (hashed) |
Binlog load time |
binlog.cache.hit.count |
Counter | binlog.cache.type (build / query, fixed) |
Cache hits |
Privacy
- No binlog content (properties, items, build output, source files) is ever read by the telemetry layer.
- No file paths — only the filename component is considered, and it is hashed before being attached to any span or metric.
- No raw error messages —
Exception.Messageis hashed before being attached. - Hashing uses HMAC-SHA256 with a fixed per-tool key, so identical filenames within a session produce the same hash (enabling correlation) but the original value cannot be recovered.
- All data stays local to whichever OTLP listener (if any) you have configured.
Using with Aspire Dashboard
docker run --rm -p 18888:18888 -p 4318:18889 mcr.microsoft.com/dotnet/aspire-dashboard
# Open http://localhost:18888 to see traces
# Set OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 922 | 6/16/2026 |