Skip to content

Repository files navigation

BinlogMcp

An MCP (Model Context Protocol) server for reading and analyzing MSBuild binary log files (.binlog).

Overview

This server exposes 54 tools that allow AI assistants to analyze MSBuild binary logs, including:

  • Build Info - Summaries, errors, warnings, properties, items
  • Performance - Slowest targets/tasks, compiler timing, parallelism analysis, I/O bottlenecks
  • Dependencies - Project graph, assembly references, NuGet packages
  • Comparison - Diff two builds, incremental build analysis
  • Diagnostics - Failure diagnosis with root cause detection and fix suggestions
  • Debugging - Target execution reasons, skipped targets, property origins, import chains
  • Evaluation - Flattened project view showing final properties, items, and imports

Standalone Tools

BinlogMCP Client - Interactive Build Investigator

An interactive REPL for analyzing MSBuild binlogs, powered by AIDavid - a virtual MSBuild debugging expert inspired by David Federman's debugging methodology. Uses the GitHub Copilot SDK for AI-powered analysis.

# Start interactive session with a binlog
dotnet run --project src/BinlogMcp.Client -- ./build.binlog
# Or launch and provide the path when prompted
dotnet run --project src/BinlogMcp.Client

Requirements: Authenticate with GitHub CLI first: gh auth login

Once loaded, you'll see an interactive prompt:


▐█▌ BinlogMCP ───────────────────────────────────
🔨 Build Log Investigator
inspired by dfederm.com/debugging-msbuild
msbuild.binlog loaded
50 analysis tools ready
───────────────────────────────────────────────────
Quick start:
[1] diagnose Automated build analysis
[2] visualize timeline Gantt chart of execution
[3] visualize slowest Slowest targets chart
[4] help All commands
Or ask: "Why did this build fail?"
───────────────────────────────────────────────────
binlog>

Interactive Commands:

  • diagnose - Run automated AIDavid diagnosis
  • visualize timeline - Open Gantt chart of build execution in browser
  • visualize slowest - Open bar chart of slowest targets
  • set baseline <path> - Set a baseline binlog for comparisons
  • compare - Compare current build with baseline
  • visualize comparison - Visual comparison chart (requires baseline)
  • help - Show available commands
  • exit - Exit the program

Or just ask questions naturally:

  • "Why did this build fail?"
  • "What targets took the longest?"
  • "Show me the errors"
  • "What version of Newtonsoft.Json is being used?"

The client maintains conversation history, so you can ask follow-up questions that reference previous answers.

Model Configuration:

  • The default model is claude-opus-4.7, configured in the session setup.

Logging: All LLM and tool interactions are logged to binlog-client.log in the current directory.

Requires GitHub CLI authentication (gh auth login) for Copilot SDK model access.

Casing Analysis

Detects and fixes path casing mismatches in MSBuild source files. On Windows, incorrect casing in paths (e.g., ..\librarya\ instead of ..\LibraryA\) can cause cache issues with NuGet and other tools.

Exposed as MCP tools — invoke them through the Client (e.g., ask "fix the casing issues in this binlog") or any MCP host:

  • GetCasingMismatches — scans a binlog for paths whose casing doesn't match disk and returns the definition site (source file + property/item) for each.
  • FixCasingMismatch — applies an XML-aware fix to a specific source file. Supports dryRun and a repoRoot safety guard that blocks edits outside the repo.

Requirements

  • .NET 10 SDK (pinned via global.json with rollForward: latestFeature)

Building

dotnet build

The repo uses Central Package Management (Directory.Packages.props), Nerdbank.GitVersioning, ReferenceTrimmer, and TreatWarningsAsErrors. All builds must be warning-free.

Running

dotnet run --project src/BinlogMcp

Testing

# Run unit tests
dotnet test tests/BinlogMcp.Tests

The interactive client (BinlogMcp.Client) uses the GitHub Copilot SDK and requires gh auth login.

MCP Configuration

Add to your MCP client configuration (e.g., Claude Desktop):

{
"mcpServers": {
"binlog": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/binlog-mcp/src/BinlogMcp"]
}
}
}

Available Tools

ToolDescription
GetCacheStatsGets binlog cache statistics and optionally clears the cache
ListBinlogsLists all binlog files in a directory (with optional recursive search)
GetBuildSummaryGets build summary: result, duration, error/warning counts, projects
GetErrorsExtracts all errors with file, line, column, code, and message
GetWarningsExtracts all warnings with the same detail as errors
GetTargetsGets target execution details sorted by duration (slowest first)
GetTasksGets task execution details with aggregation by task type
GetCriticalPathIdentifies targets on the critical path that determined build duration
GetProjectDependenciesGets project dependency graph, build order, and parallel execution info
SearchBinlogSearches binlog content for messages, errors, warnings, targets, tasks, or properties
GetPropertiesGets MSBuild properties with optional filtering and highlights important ones
GetItemsGets MSBuild item groups (Compile, Reference, PackageReference, etc.)
CompareBinlogsCompares two binlogs showing timing changes, new/fixed errors, and target differences
DiffPropertiesCompares property values between builds - added, removed, changed properties
DiffItemsCompares items between builds - added/removed files, package version changes
DiffTargetExecutionCompares target execution between builds - what ran differently
DiffImportsCompares import chains between builds - .props/.targets file changes
GetIncrementalBuildAnalysisAnalyzes incremental build behavior - executed vs skipped targets
GetNuGetRestoreAnalysisAnalyzes NuGet restore - packages, timing, and any restore issues
GetAssemblyReferencesGets assembly and project references with metadata
GetPerformanceReportComprehensive performance analysis - bottlenecks, slow targets/tasks, optimization hints
GetCompilerPerformanceDetailed C#/VB/F# compilation timing analysis
GetParallelismAnalysisBuild parallelism efficiency - concurrent operations, sequential bottlenecks
GetSlowOperationsAnalyzes slow file I/O operations (Copy, Move, Delete, Exec)
GetProjectPerformancePer-project timing rollup - identify which projects are slowest
ComparePerformanceFocused performance comparison between builds - timing regressions/improvements
GetParallelismBlockersIdentifies what's blocking parallelism - serialization points, dependency bottlenecks
AnalyzeTargetDeep dive into a single target - tasks, parameters, I/O, timing breakdown
GetFailureDiagnosisAnalyzes build failures - categorizes errors, identifies root causes, suggests fixes
GetDuplicateFileWritesDetects files written multiple times during build (wasteful I/O)
GetPropertyReassignmentsFinds MSBuild properties set multiple times (conflicts/overrides)
GetRedundantOperationsDetects tasks running with identical inputs (wasted work)
GetUnusedProjectOutputsFinds projects built but whose outputs aren't referenced (dead code)
GetTargetDependencyGraphAnalyzes target dependencies, finds circular and redundant deps
GetWarningTrendsAnalysisCategorizes warnings, suggests bulk fixes and suppressions
GetFileAccessPatternsIdentifies frequently read files and caching opportunities
GetSdkFrameworkMismatchDetects SDK/framework version conflicts across projects
GetTargetExecutionReasonsShows why targets executed (DependsOnTargets, BeforeTargets, AfterTargets)
GetSkippedTargetsLists targets that were skipped and explains why
GetPropertyOriginTraces property values back to their source file and location
GetImportChainShows the import hierarchy (.props/.targets files) for projects
TracePropertyFull property evaluation trace: initial → each assignment → final
TraceItemTrack items through build (consumed, transformed, output)
GetItemTransformsShow item transformations within targets
GetMSBuildTaskCallsShow MSBuild task invocations between projects
GetEnvironmentVariablesExtract environment variables used during the build
GetItemMetadataDeep dive into item metadata (versions, HintPaths, CopyLocal settings)
GetTargetInputsOutputsShow target incremental build inputs/outputs for debugging re-runs
GetTimelineExport timeline data for external visualization tools
GetEvaluatedProjectShows flattened project view - final properties, items, imports after evaluation
ListEmbeddedSourceFilesLists all embedded source files in the binlog's source archive (.csproj, .props, .targets, etc.)
GetEmbeddedSourceFileReads the content of a specific embedded source file from the binlog

Output Formats

21 high-value tools support multiple output formats via a format parameter:

FormatDescription
jsonDefault. Structured JSON for programmatic use
markdownHuman-readable reports with tables and bullet lists
csvTabular data for spreadsheet import
timelineJSON format for timing visualization

Tools supporting formats: GetBuildSummary, GetErrors, GetWarnings, GetTargets, GetTasks, GetCriticalPath, GetPerformanceReport, GetParallelismAnalysis, GetFailureDiagnosis, CompareBinlogs, DiffProperties, DiffTargetExecution, GetProjectDependencies, GetAssemblyReferences, GetProperties, GetItems, GetEvaluatedProject, GetProjectPerformance, ComparePerformance, GetParallelismBlockers, AnalyzeTarget.

Performance

BinlogMcp indexes a binlog once into a memory-mapped columnar sidecar and answers every subsequent query from that index. Analysis of very large binlogs is fast and bounded in memory.

Measured on a 1 GB binlog (80,313,218 records, 67 M messages, 64 M items):

Object tree (BinaryLog.ReadBuild)Streaming index
First analysis~100 GB RAM, did not complete56 s, 6.2 GB peak
Subsequent runsfull reparse0.10 s (memory-mapped open)
Full-text search of 67 M messagesnot feasible~0.9 s
All 36 analysis tools, end to endnot feasible~35 s total, 10 GB peak

How it works

  1. One streaming pass. The indexer uses BinaryLog.ReadRecords, which deserializes each record lazily and retains nothing, instead of BinaryLog.ReadBuild, which materializes every project, target, task, message, item and property as a live object graph.
  2. Messages are never pre-formatted.BuildEventArgs.Message formats its text from a format string plus arguments on demand. Doing that for every record in the sample binlog produces about 40 billion characters - roughly 80 GB of strings, and the bulk of the original memory cost. The index stores the format string and its arguments as interned string ids instead, which is about 25x smaller, and formats a message only when it appears in a query result.
  3. Columnar, zero-copy layout. The sidecar's on-disk layout is its in-memory layout, so opening an index is a file mapping plus a few pointer casts rather than a deserialization pass. Parent links are stored as packed integer scope handles, so resolving "which project owns this row" is an array lookup rather than a walk up a tree.
  4. Two-pass search. Text search first marks which of the ~3 million distinct interned strings match the query, then scans the message columns testing that bit vector - integer work only. Cost scales with distinct strings, not with the 67 million message rows.

The sidecar file

The index is written next to the binlog as <name>.binlog.binlogidx, and is rebuilt automatically whenever the binlog changes. Expect it to be several times the size of the binlog: it is stored uncompressed so it can be memory-mapped and scanned without decoding. If the binlog's directory is not writable, the sidecar falls back to a cache directory under %TEMP%.

Add *.binlogidx to .gitignore if you keep binlogs in a repository.

Building an index ahead of time

# Build (or rebuild) the index and print statistics
BinlogMcp index path/to/build.binlog [--force]
# Print statistics for an existing index
BinlogMcp index-stats path/to/build.binlog
# Time a full-text search
BinlogMcp index-search path/to/build.binlog "Copying file"

Configuration (optional):

  • BINLOG_INDEX_DIR - Directory to write sidecar indexes to (default: next to the binlog)
  • BINLOG_INDEX_PERSIST=false - Never write sidecars next to the binlog; use the temp cache instead
  • BINLOG_CACHE_SIZE=10 - Maximum indexes to keep mapped (default: 10)
  • BINLOG_CACHE_ENABLED=false - Disable the in-process index cache
  • BINLOG_MAX_RESPONSE_CHARS=4000000 - Global cap on the size of any single tool response

Use GetCacheStats to view cache status or clear it.

Result limits

Tools that can return large result sets accept a limit parameter, default 200 and capped at 5000. Responses include a truncated flag and the true total count when results were cut off. A global response-size cap acts as a backstop: a query that would still exceed it returns a short error suggesting a smaller limit or a narrower filter, rather than a payload no client can consume.

Regression testing on large binlogs

LargeBinlogSmokeTests runs every tool against a large binlog and fails if any tool errors, takes longer than 30 seconds, or returns more than 5 MB. It skips silently unless a binlog is supplied:

# PowerShell$env:BINLOGMCP_LARGE_BINLOG = "path\to\big.binlog"
dotnet test tests/BinlogMcp.Tests --filter "FullyQualifiedName~LargeBinlogSmokeTests"

Set BINLOGMCP_SMOKE_LOG to a file path to watch per-tool timings while the run is in progress.

Example Usage

Once configured, you can ask your AI assistant questions like:

  • "List the binlog files in C:\builds"
  • "What errors are in the latest build?"
  • "Which targets took the longest to execute?"
  • "What's on the critical path of this build?"

Generating Binlog Files

To create a binlog from any MSBuild/dotnet build:

dotnet build -bl # Creates msbuild.binlog
dotnet build -bl:mybuild.binlog # Custom filename
msbuild MySolution.sln -bl # Works with msbuild too

Dependencies

License

MIT

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - AndyGerlicher/BinlogMCP · GitHub
Skip to content

Repository files navigation

BinlogMcp

An MCP (Model Context Protocol) server for reading and analyzing MSBuild binary log files (.binlog).

Overview

This server exposes 54 tools that allow AI assistants to analyze MSBuild binary logs, including:

  • Build Info - Summaries, errors, warnings, properties, items
  • Performance - Slowest targets/tasks, compiler timing, parallelism analysis, I/O bottlenecks
  • Dependencies - Project graph, assembly references, NuGet packages
  • Comparison - Diff two builds, incremental build analysis
  • Diagnostics - Failure diagnosis with root cause detection and fix suggestions
  • Debugging - Target execution reasons, skipped targets, property origins, import chains
  • Evaluation - Flattened project view showing final properties, items, and imports

Standalone Tools

BinlogMCP Client - Interactive Build Investigator

An interactive REPL for analyzing MSBuild binlogs, powered by AIDavid - a virtual MSBuild debugging expert inspired by David Federman's debugging methodology. Uses the GitHub Copilot SDK for AI-powered analysis.

# Start interactive session with a binlog
dotnet run --project src/BinlogMcp.Client -- ./build.binlog
# Or launch and provide the path when prompted
dotnet run --project src/BinlogMcp.Client

Requirements: Authenticate with GitHub CLI first: gh auth login

Once loaded, you'll see an interactive prompt:


▐█▌ BinlogMCP ───────────────────────────────────
🔨 Build Log Investigator
inspired by dfederm.com/debugging-msbuild
msbuild.binlog loaded
50 analysis tools ready
───────────────────────────────────────────────────
Quick start:
[1] diagnose Automated build analysis
[2] visualize timeline Gantt chart of execution
[3] visualize slowest Slowest targets chart
[4] help All commands
Or ask: "Why did this build fail?"
───────────────────────────────────────────────────
binlog>

Interactive Commands:

  • diagnose - Run automated AIDavid diagnosis
  • visualize timeline - Open Gantt chart of build execution in browser
  • visualize slowest - Open bar chart of slowest targets
  • set baseline <path> - Set a baseline binlog for comparisons
  • compare - Compare current build with baseline
  • visualize comparison - Visual comparison chart (requires baseline)
  • help - Show available commands
  • exit - Exit the program

Or just ask questions naturally:

  • "Why did this build fail?"
  • "What targets took the longest?"
  • "Show me the errors"
  • "What version of Newtonsoft.Json is being used?"

The client maintains conversation history, so you can ask follow-up questions that reference previous answers.

Model Configuration:

  • The default model is claude-opus-4.7, configured in the session setup.

Logging: All LLM and tool interactions are logged to binlog-client.log in the current directory.

Requires GitHub CLI authentication (gh auth login) for Copilot SDK model access.

Casing Analysis

Detects and fixes path casing mismatches in MSBuild source files. On Windows, incorrect casing in paths (e.g., ..\librarya\ instead of ..\LibraryA\) can cause cache issues with NuGet and other tools.

Exposed as MCP tools — invoke them through the Client (e.g., ask "fix the casing issues in this binlog") or any MCP host:

  • GetCasingMismatches — scans a binlog for paths whose casing doesn't match disk and returns the definition site (source file + property/item) for each.
  • FixCasingMismatch — applies an XML-aware fix to a specific source file. Supports dryRun and a repoRoot safety guard that blocks edits outside the repo.

Requirements

  • .NET 10 SDK (pinned via global.json with rollForward: latestFeature)

Building

dotnet build

The repo uses Central Package Management (Directory.Packages.props), Nerdbank.GitVersioning, ReferenceTrimmer, and TreatWarningsAsErrors. All builds must be warning-free.

Running

dotnet run --project src/BinlogMcp

Testing

# Run unit tests
dotnet test tests/BinlogMcp.Tests

The interactive client (BinlogMcp.Client) uses the GitHub Copilot SDK and requires gh auth login.

MCP Configuration

Add to your MCP client configuration (e.g., Claude Desktop):

{
"mcpServers": {
"binlog": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/binlog-mcp/src/BinlogMcp"]
}
}
}

Available Tools

ToolDescription
GetCacheStatsGets binlog cache statistics and optionally clears the cache
ListBinlogsLists all binlog files in a directory (with optional recursive search)
GetBuildSummaryGets build summary: result, duration, error/warning counts, projects
GetErrorsExtracts all errors with file, line, column, code, and message
GetWarningsExtracts all warnings with the same detail as errors
GetTargetsGets target execution details sorted by duration (slowest first)
GetTasksGets task execution details with aggregation by task type
GetCriticalPathIdentifies targets on the critical path that determined build duration
GetProjectDependenciesGets project dependency graph, build order, and parallel execution info
SearchBinlogSearches binlog content for messages, errors, warnings, targets, tasks, or properties
GetPropertiesGets MSBuild properties with optional filtering and highlights important ones
GetItemsGets MSBuild item groups (Compile, Reference, PackageReference, etc.)
CompareBinlogsCompares two binlogs showing timing changes, new/fixed errors, and target differences
DiffPropertiesCompares property values between builds - added, removed, changed properties
DiffItemsCompares items between builds - added/removed files, package version changes
DiffTargetExecutionCompares target execution between builds - what ran differently
DiffImportsCompares import chains between builds - .props/.targets file changes
GetIncrementalBuildAnalysisAnalyzes incremental build behavior - executed vs skipped targets
GetNuGetRestoreAnalysisAnalyzes NuGet restore - packages, timing, and any restore issues
GetAssemblyReferencesGets assembly and project references with metadata
GetPerformanceReportComprehensive performance analysis - bottlenecks, slow targets/tasks, optimization hints
GetCompilerPerformanceDetailed C#/VB/F# compilation timing analysis
GetParallelismAnalysisBuild parallelism efficiency - concurrent operations, sequential bottlenecks
GetSlowOperationsAnalyzes slow file I/O operations (Copy, Move, Delete, Exec)
GetProjectPerformancePer-project timing rollup - identify which projects are slowest
ComparePerformanceFocused performance comparison between builds - timing regressions/improvements
GetParallelismBlockersIdentifies what's blocking parallelism - serialization points, dependency bottlenecks
AnalyzeTargetDeep dive into a single target - tasks, parameters, I/O, timing breakdown
GetFailureDiagnosisAnalyzes build failures - categorizes errors, identifies root causes, suggests fixes
GetDuplicateFileWritesDetects files written multiple times during build (wasteful I/O)
GetPropertyReassignmentsFinds MSBuild properties set multiple times (conflicts/overrides)
GetRedundantOperationsDetects tasks running with identical inputs (wasted work)
GetUnusedProjectOutputsFinds projects built but whose outputs aren't referenced (dead code)
GetTargetDependencyGraphAnalyzes target dependencies, finds circular and redundant deps
GetWarningTrendsAnalysisCategorizes warnings, suggests bulk fixes and suppressions
GetFileAccessPatternsIdentifies frequently read files and caching opportunities
GetSdkFrameworkMismatchDetects SDK/framework version conflicts across projects
GetTargetExecutionReasonsShows why targets executed (DependsOnTargets, BeforeTargets, AfterTargets)
GetSkippedTargetsLists targets that were skipped and explains why
GetPropertyOriginTraces property values back to their source file and location
GetImportChainShows the import hierarchy (.props/.targets files) for projects
TracePropertyFull property evaluation trace: initial → each assignment → final
TraceItemTrack items through build (consumed, transformed, output)
GetItemTransformsShow item transformations within targets
GetMSBuildTaskCallsShow MSBuild task invocations between projects
GetEnvironmentVariablesExtract environment variables used during the build
GetItemMetadataDeep dive into item metadata (versions, HintPaths, CopyLocal settings)
GetTargetInputsOutputsShow target incremental build inputs/outputs for debugging re-runs
GetTimelineExport timeline data for external visualization tools
GetEvaluatedProjectShows flattened project view - final properties, items, imports after evaluation
ListEmbeddedSourceFilesLists all embedded source files in the binlog's source archive (.csproj, .props, .targets, etc.)
GetEmbeddedSourceFileReads the content of a specific embedded source file from the binlog

Output Formats

21 high-value tools support multiple output formats via a format parameter:

FormatDescription
jsonDefault. Structured JSON for programmatic use
markdownHuman-readable reports with tables and bullet lists
csvTabular data for spreadsheet import
timelineJSON format for timing visualization

Tools supporting formats: GetBuildSummary, GetErrors, GetWarnings, GetTargets, GetTasks, GetCriticalPath, GetPerformanceReport, GetParallelismAnalysis, GetFailureDiagnosis, CompareBinlogs, DiffProperties, DiffTargetExecution, GetProjectDependencies, GetAssemblyReferences, GetProperties, GetItems, GetEvaluatedProject, GetProjectPerformance, ComparePerformance, GetParallelismBlockers, AnalyzeTarget.

Performance

BinlogMcp indexes a binlog once into a memory-mapped columnar sidecar and answers every subsequent query from that index. Analysis of very large binlogs is fast and bounded in memory.

Measured on a 1 GB binlog (80,313,218 records, 67 M messages, 64 M items):

Object tree (BinaryLog.ReadBuild)Streaming index
First analysis~100 GB RAM, did not complete56 s, 6.2 GB peak
Subsequent runsfull reparse0.10 s (memory-mapped open)
Full-text search of 67 M messagesnot feasible~0.9 s
All 36 analysis tools, end to endnot feasible~35 s total, 10 GB peak

How it works

  1. One streaming pass. The indexer uses BinaryLog.ReadRecords, which deserializes each record lazily and retains nothing, instead of BinaryLog.ReadBuild, which materializes every project, target, task, message, item and property as a live object graph.
  2. Messages are never pre-formatted.BuildEventArgs.Message formats its text from a format string plus arguments on demand. Doing that for every record in the sample binlog produces about 40 billion characters - roughly 80 GB of strings, and the bulk of the original memory cost. The index stores the format string and its arguments as interned string ids instead, which is about 25x smaller, and formats a message only when it appears in a query result.
  3. Columnar, zero-copy layout. The sidecar's on-disk layout is its in-memory layout, so opening an index is a file mapping plus a few pointer casts rather than a deserialization pass. Parent links are stored as packed integer scope handles, so resolving "which project owns this row" is an array lookup rather than a walk up a tree.
  4. Two-pass search. Text search first marks which of the ~3 million distinct interned strings match the query, then scans the message columns testing that bit vector - integer work only. Cost scales with distinct strings, not with the 67 million message rows.

The sidecar file

The index is written next to the binlog as <name>.binlog.binlogidx, and is rebuilt automatically whenever the binlog changes. Expect it to be several times the size of the binlog: it is stored uncompressed so it can be memory-mapped and scanned without decoding. If the binlog's directory is not writable, the sidecar falls back to a cache directory under %TEMP%.

Add *.binlogidx to .gitignore if you keep binlogs in a repository.

Building an index ahead of time

# Build (or rebuild) the index and print statistics
BinlogMcp index path/to/build.binlog [--force]
# Print statistics for an existing index
BinlogMcp index-stats path/to/build.binlog
# Time a full-text search
BinlogMcp index-search path/to/build.binlog "Copying file"

Configuration (optional):

  • BINLOG_INDEX_DIR - Directory to write sidecar indexes to (default: next to the binlog)
  • BINLOG_INDEX_PERSIST=false - Never write sidecars next to the binlog; use the temp cache instead
  • BINLOG_CACHE_SIZE=10 - Maximum indexes to keep mapped (default: 10)
  • BINLOG_CACHE_ENABLED=false - Disable the in-process index cache
  • BINLOG_MAX_RESPONSE_CHARS=4000000 - Global cap on the size of any single tool response

Use GetCacheStats to view cache status or clear it.

Result limits

Tools that can return large result sets accept a limit parameter, default 200 and capped at 5000. Responses include a truncated flag and the true total count when results were cut off. A global response-size cap acts as a backstop: a query that would still exceed it returns a short error suggesting a smaller limit or a narrower filter, rather than a payload no client can consume.

Regression testing on large binlogs

LargeBinlogSmokeTests runs every tool against a large binlog and fails if any tool errors, takes longer than 30 seconds, or returns more than 5 MB. It skips silently unless a binlog is supplied:

# PowerShell$env:BINLOGMCP_LARGE_BINLOG = "path\to\big.binlog"
dotnet test tests/BinlogMcp.Tests --filter "FullyQualifiedName~LargeBinlogSmokeTests"

Set BINLOGMCP_SMOKE_LOG to a file path to watch per-tool timings while the run is in progress.

Example Usage

Once configured, you can ask your AI assistant questions like:

  • "List the binlog files in C:\builds"
  • "What errors are in the latest build?"
  • "Which targets took the longest to execute?"
  • "What's on the critical path of this build?"

Generating Binlog Files

To create a binlog from any MSBuild/dotnet build:

dotnet build -bl # Creates msbuild.binlog
dotnet build -bl:mybuild.binlog # Custom filename
msbuild MySolution.sln -bl # Works with msbuild too

Dependencies

License

MIT

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - AndyGerlicher/BinlogMCP · GitHub
Skip to content

Repository files navigation

BinlogMcp

An MCP (Model Context Protocol) server for reading and analyzing MSBuild binary log files (.binlog).

Overview

This server exposes 54 tools that allow AI assistants to analyze MSBuild binary logs, including:

  • Build Info - Summaries, errors, warnings, properties, items
  • Performance - Slowest targets/tasks, compiler timing, parallelism analysis, I/O bottlenecks
  • Dependencies - Project graph, assembly references, NuGet packages
  • Comparison - Diff two builds, incremental build analysis
  • Diagnostics - Failure diagnosis with root cause detection and fix suggestions
  • Debugging - Target execution reasons, skipped targets, property origins, import chains
  • Evaluation - Flattened project view showing final properties, items, and imports

Standalone Tools

BinlogMCP Client - Interactive Build Investigator

An interactive REPL for analyzing MSBuild binlogs, powered by AIDavid - a virtual MSBuild debugging expert inspired by David Federman's debugging methodology. Uses the GitHub Copilot SDK for AI-powered analysis.

# Start interactive session with a binlog
dotnet run --project src/BinlogMcp.Client -- ./build.binlog
# Or launch and provide the path when prompted
dotnet run --project src/BinlogMcp.Client

Requirements: Authenticate with GitHub CLI first: gh auth login

Once loaded, you'll see an interactive prompt:


▐█▌ BinlogMCP ───────────────────────────────────
🔨 Build Log Investigator
inspired by dfederm.com/debugging-msbuild
msbuild.binlog loaded
50 analysis tools ready
───────────────────────────────────────────────────
Quick start:
[1] diagnose Automated build analysis
[2] visualize timeline Gantt chart of execution
[3] visualize slowest Slowest targets chart
[4] help All commands
Or ask: "Why did this build fail?"
───────────────────────────────────────────────────
binlog>

Interactive Commands:

  • diagnose - Run automated AIDavid diagnosis
  • visualize timeline - Open Gantt chart of build execution in browser
  • visualize slowest - Open bar chart of slowest targets
  • set baseline <path> - Set a baseline binlog for comparisons
  • compare - Compare current build with baseline
  • visualize comparison - Visual comparison chart (requires baseline)
  • help - Show available commands
  • exit - Exit the program

Or just ask questions naturally:

  • "Why did this build fail?"
  • "What targets took the longest?"
  • "Show me the errors"
  • "What version of Newtonsoft.Json is being used?"

The client maintains conversation history, so you can ask follow-up questions that reference previous answers.

Model Configuration:

  • The default model is claude-opus-4.7, configured in the session setup.

Logging: All LLM and tool interactions are logged to binlog-client.log in the current directory.

Requires GitHub CLI authentication (gh auth login) for Copilot SDK model access.

Casing Analysis

Detects and fixes path casing mismatches in MSBuild source files. On Windows, incorrect casing in paths (e.g., ..\librarya\ instead of ..\LibraryA\) can cause cache issues with NuGet and other tools.

Exposed as MCP tools — invoke them through the Client (e.g., ask "fix the casing issues in this binlog") or any MCP host:

  • GetCasingMismatches — scans a binlog for paths whose casing doesn't match disk and returns the definition site (source file + property/item) for each.
  • FixCasingMismatch — applies an XML-aware fix to a specific source file. Supports dryRun and a repoRoot safety guard that blocks edits outside the repo.

Requirements

  • .NET 10 SDK (pinned via global.json with rollForward: latestFeature)

Building

dotnet build

The repo uses Central Package Management (Directory.Packages.props), Nerdbank.GitVersioning, ReferenceTrimmer, and TreatWarningsAsErrors. All builds must be warning-free.

Running

dotnet run --project src/BinlogMcp

Testing

# Run unit tests
dotnet test tests/BinlogMcp.Tests

The interactive client (BinlogMcp.Client) uses the GitHub Copilot SDK and requires gh auth login.

MCP Configuration

Add to your MCP client configuration (e.g., Claude Desktop):

{
"mcpServers": {
"binlog": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/binlog-mcp/src/BinlogMcp"]
}
}
}

Available Tools

ToolDescription
GetCacheStatsGets binlog cache statistics and optionally clears the cache
ListBinlogsLists all binlog files in a directory (with optional recursive search)
GetBuildSummaryGets build summary: result, duration, error/warning counts, projects
GetErrorsExtracts all errors with file, line, column, code, and message
GetWarningsExtracts all warnings with the same detail as errors
GetTargetsGets target execution details sorted by duration (slowest first)
GetTasksGets task execution details with aggregation by task type
GetCriticalPathIdentifies targets on the critical path that determined build duration
GetProjectDependenciesGets project dependency graph, build order, and parallel execution info
SearchBinlogSearches binlog content for messages, errors, warnings, targets, tasks, or properties
GetPropertiesGets MSBuild properties with optional filtering and highlights important ones
GetItemsGets MSBuild item groups (Compile, Reference, PackageReference, etc.)
CompareBinlogsCompares two binlogs showing timing changes, new/fixed errors, and target differences
DiffPropertiesCompares property values between builds - added, removed, changed properties
DiffItemsCompares items between builds - added/removed files, package version changes
DiffTargetExecutionCompares target execution between builds - what ran differently
DiffImportsCompares import chains between builds - .props/.targets file changes
GetIncrementalBuildAnalysisAnalyzes incremental build behavior - executed vs skipped targets
GetNuGetRestoreAnalysisAnalyzes NuGet restore - packages, timing, and any restore issues
GetAssemblyReferencesGets assembly and project references with metadata
GetPerformanceReportComprehensive performance analysis - bottlenecks, slow targets/tasks, optimization hints
GetCompilerPerformanceDetailed C#/VB/F# compilation timing analysis
GetParallelismAnalysisBuild parallelism efficiency - concurrent operations, sequential bottlenecks
GetSlowOperationsAnalyzes slow file I/O operations (Copy, Move, Delete, Exec)
GetProjectPerformancePer-project timing rollup - identify which projects are slowest
ComparePerformanceFocused performance comparison between builds - timing regressions/improvements
GetParallelismBlockersIdentifies what's blocking parallelism - serialization points, dependency bottlenecks
AnalyzeTargetDeep dive into a single target - tasks, parameters, I/O, timing breakdown
GetFailureDiagnosisAnalyzes build failures - categorizes errors, identifies root causes, suggests fixes
GetDuplicateFileWritesDetects files written multiple times during build (wasteful I/O)
GetPropertyReassignmentsFinds MSBuild properties set multiple times (conflicts/overrides)
GetRedundantOperationsDetects tasks running with identical inputs (wasted work)
GetUnusedProjectOutputsFinds projects built but whose outputs aren't referenced (dead code)
GetTargetDependencyGraphAnalyzes target dependencies, finds circular and redundant deps
GetWarningTrendsAnalysisCategorizes warnings, suggests bulk fixes and suppressions
GetFileAccessPatternsIdentifies frequently read files and caching opportunities
GetSdkFrameworkMismatchDetects SDK/framework version conflicts across projects
GetTargetExecutionReasonsShows why targets executed (DependsOnTargets, BeforeTargets, AfterTargets)
GetSkippedTargetsLists targets that were skipped and explains why
GetPropertyOriginTraces property values back to their source file and location
GetImportChainShows the import hierarchy (.props/.targets files) for projects
TracePropertyFull property evaluation trace: initial → each assignment → final
TraceItemTrack items through build (consumed, transformed, output)
GetItemTransformsShow item transformations within targets
GetMSBuildTaskCallsShow MSBuild task invocations between projects
GetEnvironmentVariablesExtract environment variables used during the build
GetItemMetadataDeep dive into item metadata (versions, HintPaths, CopyLocal settings)
GetTargetInputsOutputsShow target incremental build inputs/outputs for debugging re-runs
GetTimelineExport timeline data for external visualization tools
GetEvaluatedProjectShows flattened project view - final properties, items, imports after evaluation
ListEmbeddedSourceFilesLists all embedded source files in the binlog's source archive (.csproj, .props, .targets, etc.)
GetEmbeddedSourceFileReads the content of a specific embedded source file from the binlog

Output Formats

21 high-value tools support multiple output formats via a format parameter:

FormatDescription
jsonDefault. Structured JSON for programmatic use
markdownHuman-readable reports with tables and bullet lists
csvTabular data for spreadsheet import
timelineJSON format for timing visualization

Tools supporting formats: GetBuildSummary, GetErrors, GetWarnings, GetTargets, GetTasks, GetCriticalPath, GetPerformanceReport, GetParallelismAnalysis, GetFailureDiagnosis, CompareBinlogs, DiffProperties, DiffTargetExecution, GetProjectDependencies, GetAssemblyReferences, GetProperties, GetItems, GetEvaluatedProject, GetProjectPerformance, ComparePerformance, GetParallelismBlockers, AnalyzeTarget.

Performance

BinlogMcp indexes a binlog once into a memory-mapped columnar sidecar and answers every subsequent query from that index. Analysis of very large binlogs is fast and bounded in memory.

Measured on a 1 GB binlog (80,313,218 records, 67 M messages, 64 M items):

Object tree (BinaryLog.ReadBuild)Streaming index
First analysis~100 GB RAM, did not complete56 s, 6.2 GB peak
Subsequent runsfull reparse0.10 s (memory-mapped open)
Full-text search of 67 M messagesnot feasible~0.9 s
All 36 analysis tools, end to endnot feasible~35 s total, 10 GB peak

How it works

  1. One streaming pass. The indexer uses BinaryLog.ReadRecords, which deserializes each record lazily and retains nothing, instead of BinaryLog.ReadBuild, which materializes every project, target, task, message, item and property as a live object graph.
  2. Messages are never pre-formatted.BuildEventArgs.Message formats its text from a format string plus arguments on demand. Doing that for every record in the sample binlog produces about 40 billion characters - roughly 80 GB of strings, and the bulk of the original memory cost. The index stores the format string and its arguments as interned string ids instead, which is about 25x smaller, and formats a message only when it appears in a query result.
  3. Columnar, zero-copy layout. The sidecar's on-disk layout is its in-memory layout, so opening an index is a file mapping plus a few pointer casts rather than a deserialization pass. Parent links are stored as packed integer scope handles, so resolving "which project owns this row" is an array lookup rather than a walk up a tree.
  4. Two-pass search. Text search first marks which of the ~3 million distinct interned strings match the query, then scans the message columns testing that bit vector - integer work only. Cost scales with distinct strings, not with the 67 million message rows.

The sidecar file

The index is written next to the binlog as <name>.binlog.binlogidx, and is rebuilt automatically whenever the binlog changes. Expect it to be several times the size of the binlog: it is stored uncompressed so it can be memory-mapped and scanned without decoding. If the binlog's directory is not writable, the sidecar falls back to a cache directory under %TEMP%.

Add *.binlogidx to .gitignore if you keep binlogs in a repository.

Building an index ahead of time

# Build (or rebuild) the index and print statistics
BinlogMcp index path/to/build.binlog [--force]
# Print statistics for an existing index
BinlogMcp index-stats path/to/build.binlog
# Time a full-text search
BinlogMcp index-search path/to/build.binlog "Copying file"

Configuration (optional):

  • BINLOG_INDEX_DIR - Directory to write sidecar indexes to (default: next to the binlog)
  • BINLOG_INDEX_PERSIST=false - Never write sidecars next to the binlog; use the temp cache instead
  • BINLOG_CACHE_SIZE=10 - Maximum indexes to keep mapped (default: 10)
  • BINLOG_CACHE_ENABLED=false - Disable the in-process index cache
  • BINLOG_MAX_RESPONSE_CHARS=4000000 - Global cap on the size of any single tool response

Use GetCacheStats to view cache status or clear it.

Result limits

Tools that can return large result sets accept a limit parameter, default 200 and capped at 5000. Responses include a truncated flag and the true total count when results were cut off. A global response-size cap acts as a backstop: a query that would still exceed it returns a short error suggesting a smaller limit or a narrower filter, rather than a payload no client can consume.

Regression testing on large binlogs

LargeBinlogSmokeTests runs every tool against a large binlog and fails if any tool errors, takes longer than 30 seconds, or returns more than 5 MB. It skips silently unless a binlog is supplied:

# PowerShell$env:BINLOGMCP_LARGE_BINLOG = "path\to\big.binlog"
dotnet test tests/BinlogMcp.Tests --filter "FullyQualifiedName~LargeBinlogSmokeTests"

Set BINLOGMCP_SMOKE_LOG to a file path to watch per-tool timings while the run is in progress.

Example Usage

Once configured, you can ask your AI assistant questions like:

  • "List the binlog files in C:\builds"
  • "What errors are in the latest build?"
  • "Which targets took the longest to execute?"
  • "What's on the critical path of this build?"

Generating Binlog Files

To create a binlog from any MSBuild/dotnet build:

dotnet build -bl # Creates msbuild.binlog
dotnet build -bl:mybuild.binlog # Custom filename
msbuild MySolution.sln -bl # Works with msbuild too

Dependencies

License

MIT

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - AndyGerlicher/BinlogMCP · GitHub
Skip to content

Repository files navigation

BinlogMcp

An MCP (Model Context Protocol) server for reading and analyzing MSBuild binary log files (.binlog).

Overview

This server exposes 54 tools that allow AI assistants to analyze MSBuild binary logs, including:

  • Build Info - Summaries, errors, warnings, properties, items
  • Performance - Slowest targets/tasks, compiler timing, parallelism analysis, I/O bottlenecks
  • Dependencies - Project graph, assembly references, NuGet packages
  • Comparison - Diff two builds, incremental build analysis
  • Diagnostics - Failure diagnosis with root cause detection and fix suggestions
  • Debugging - Target execution reasons, skipped targets, property origins, import chains
  • Evaluation - Flattened project view showing final properties, items, and imports

Standalone Tools

BinlogMCP Client - Interactive Build Investigator

An interactive REPL for analyzing MSBuild binlogs, powered by AIDavid - a virtual MSBuild debugging expert inspired by David Federman's debugging methodology. Uses the GitHub Copilot SDK for AI-powered analysis.

# Start interactive session with a binlog
dotnet run --project src/BinlogMcp.Client -- ./build.binlog
# Or launch and provide the path when prompted
dotnet run --project src/BinlogMcp.Client

Requirements: Authenticate with GitHub CLI first: gh auth login

Once loaded, you'll see an interactive prompt:


▐█▌ BinlogMCP ───────────────────────────────────
🔨 Build Log Investigator
inspired by dfederm.com/debugging-msbuild
msbuild.binlog loaded
50 analysis tools ready
───────────────────────────────────────────────────
Quick start:
[1] diagnose Automated build analysis
[2] visualize timeline Gantt chart of execution
[3] visualize slowest Slowest targets chart
[4] help All commands
Or ask: "Why did this build fail?"
───────────────────────────────────────────────────
binlog>

Interactive Commands:

  • diagnose - Run automated AIDavid diagnosis
  • visualize timeline - Open Gantt chart of build execution in browser
  • visualize slowest - Open bar chart of slowest targets
  • set baseline <path> - Set a baseline binlog for comparisons
  • compare - Compare current build with baseline
  • visualize comparison - Visual comparison chart (requires baseline)
  • help - Show available commands
  • exit - Exit the program

Or just ask questions naturally:

  • "Why did this build fail?"
  • "What targets took the longest?"
  • "Show me the errors"
  • "What version of Newtonsoft.Json is being used?"

The client maintains conversation history, so you can ask follow-up questions that reference previous answers.

Model Configuration:

  • The default model is claude-opus-4.7, configured in the session setup.

Logging: All LLM and tool interactions are logged to binlog-client.log in the current directory.

Requires GitHub CLI authentication (gh auth login) for Copilot SDK model access.

Casing Analysis

Detects and fixes path casing mismatches in MSBuild source files. On Windows, incorrect casing in paths (e.g., ..\librarya\ instead of ..\LibraryA\) can cause cache issues with NuGet and other tools.

Exposed as MCP tools — invoke them through the Client (e.g., ask "fix the casing issues in this binlog") or any MCP host:

  • GetCasingMismatches — scans a binlog for paths whose casing doesn't match disk and returns the definition site (source file + property/item) for each.
  • FixCasingMismatch — applies an XML-aware fix to a specific source file. Supports dryRun and a repoRoot safety guard that blocks edits outside the repo.

Requirements

  • .NET 10 SDK (pinned via global.json with rollForward: latestFeature)

Building

dotnet build

The repo uses Central Package Management (Directory.Packages.props), Nerdbank.GitVersioning, ReferenceTrimmer, and TreatWarningsAsErrors. All builds must be warning-free.

Running

dotnet run --project src/BinlogMcp

Testing

# Run unit tests
dotnet test tests/BinlogMcp.Tests

The interactive client (BinlogMcp.Client) uses the GitHub Copilot SDK and requires gh auth login.

MCP Configuration

Add to your MCP client configuration (e.g., Claude Desktop):

{
"mcpServers": {
"binlog": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/binlog-mcp/src/BinlogMcp"]
}
}
}

Available Tools

ToolDescription
GetCacheStatsGets binlog cache statistics and optionally clears the cache
ListBinlogsLists all binlog files in a directory (with optional recursive search)
GetBuildSummaryGets build summary: result, duration, error/warning counts, projects
GetErrorsExtracts all errors with file, line, column, code, and message
GetWarningsExtracts all warnings with the same detail as errors
GetTargetsGets target execution details sorted by duration (slowest first)
GetTasksGets task execution details with aggregation by task type
GetCriticalPathIdentifies targets on the critical path that determined build duration
GetProjectDependenciesGets project dependency graph, build order, and parallel execution info
SearchBinlogSearches binlog content for messages, errors, warnings, targets, tasks, or properties
GetPropertiesGets MSBuild properties with optional filtering and highlights important ones
GetItemsGets MSBuild item groups (Compile, Reference, PackageReference, etc.)
CompareBinlogsCompares two binlogs showing timing changes, new/fixed errors, and target differences
DiffPropertiesCompares property values between builds - added, removed, changed properties
DiffItemsCompares items between builds - added/removed files, package version changes
DiffTargetExecutionCompares target execution between builds - what ran differently
DiffImportsCompares import chains between builds - .props/.targets file changes
GetIncrementalBuildAnalysisAnalyzes incremental build behavior - executed vs skipped targets
GetNuGetRestoreAnalysisAnalyzes NuGet restore - packages, timing, and any restore issues
GetAssemblyReferencesGets assembly and project references with metadata
GetPerformanceReportComprehensive performance analysis - bottlenecks, slow targets/tasks, optimization hints
GetCompilerPerformanceDetailed C#/VB/F# compilation timing analysis
GetParallelismAnalysisBuild parallelism efficiency - concurrent operations, sequential bottlenecks
GetSlowOperationsAnalyzes slow file I/O operations (Copy, Move, Delete, Exec)
GetProjectPerformancePer-project timing rollup - identify which projects are slowest
ComparePerformanceFocused performance comparison between builds - timing regressions/improvements
GetParallelismBlockersIdentifies what's blocking parallelism - serialization points, dependency bottlenecks
AnalyzeTargetDeep dive into a single target - tasks, parameters, I/O, timing breakdown
GetFailureDiagnosisAnalyzes build failures - categorizes errors, identifies root causes, suggests fixes
GetDuplicateFileWritesDetects files written multiple times during build (wasteful I/O)
GetPropertyReassignmentsFinds MSBuild properties set multiple times (conflicts/overrides)
GetRedundantOperationsDetects tasks running with identical inputs (wasted work)
GetUnusedProjectOutputsFinds projects built but whose outputs aren't referenced (dead code)
GetTargetDependencyGraphAnalyzes target dependencies, finds circular and redundant deps
GetWarningTrendsAnalysisCategorizes warnings, suggests bulk fixes and suppressions
GetFileAccessPatternsIdentifies frequently read files and caching opportunities
GetSdkFrameworkMismatchDetects SDK/framework version conflicts across projects
GetTargetExecutionReasonsShows why targets executed (DependsOnTargets, BeforeTargets, AfterTargets)
GetSkippedTargetsLists targets that were skipped and explains why
GetPropertyOriginTraces property values back to their source file and location
GetImportChainShows the import hierarchy (.props/.targets files) for projects
TracePropertyFull property evaluation trace: initial → each assignment → final
TraceItemTrack items through build (consumed, transformed, output)
GetItemTransformsShow item transformations within targets
GetMSBuildTaskCallsShow MSBuild task invocations between projects
GetEnvironmentVariablesExtract environment variables used during the build
GetItemMetadataDeep dive into item metadata (versions, HintPaths, CopyLocal settings)
GetTargetInputsOutputsShow target incremental build inputs/outputs for debugging re-runs
GetTimelineExport timeline data for external visualization tools
GetEvaluatedProjectShows flattened project view - final properties, items, imports after evaluation
ListEmbeddedSourceFilesLists all embedded source files in the binlog's source archive (.csproj, .props, .targets, etc.)
GetEmbeddedSourceFileReads the content of a specific embedded source file from the binlog

Output Formats

21 high-value tools support multiple output formats via a format parameter:

FormatDescription
jsonDefault. Structured JSON for programmatic use
markdownHuman-readable reports with tables and bullet lists
csvTabular data for spreadsheet import
timelineJSON format for timing visualization

Tools supporting formats: GetBuildSummary, GetErrors, GetWarnings, GetTargets, GetTasks, GetCriticalPath, GetPerformanceReport, GetParallelismAnalysis, GetFailureDiagnosis, CompareBinlogs, DiffProperties, DiffTargetExecution, GetProjectDependencies, GetAssemblyReferences, GetProperties, GetItems, GetEvaluatedProject, GetProjectPerformance, ComparePerformance, GetParallelismBlockers, AnalyzeTarget.

Performance

BinlogMcp indexes a binlog once into a memory-mapped columnar sidecar and answers every subsequent query from that index. Analysis of very large binlogs is fast and bounded in memory.

Measured on a 1 GB binlog (80,313,218 records, 67 M messages, 64 M items):

Object tree (BinaryLog.ReadBuild)Streaming index
First analysis~100 GB RAM, did not complete56 s, 6.2 GB peak
Subsequent runsfull reparse0.10 s (memory-mapped open)
Full-text search of 67 M messagesnot feasible~0.9 s
All 36 analysis tools, end to endnot feasible~35 s total, 10 GB peak

How it works

  1. One streaming pass. The indexer uses BinaryLog.ReadRecords, which deserializes each record lazily and retains nothing, instead of BinaryLog.ReadBuild, which materializes every project, target, task, message, item and property as a live object graph.
  2. Messages are never pre-formatted.BuildEventArgs.Message formats its text from a format string plus arguments on demand. Doing that for every record in the sample binlog produces about 40 billion characters - roughly 80 GB of strings, and the bulk of the original memory cost. The index stores the format string and its arguments as interned string ids instead, which is about 25x smaller, and formats a message only when it appears in a query result.
  3. Columnar, zero-copy layout. The sidecar's on-disk layout is its in-memory layout, so opening an index is a file mapping plus a few pointer casts rather than a deserialization pass. Parent links are stored as packed integer scope handles, so resolving "which project owns this row" is an array lookup rather than a walk up a tree.
  4. Two-pass search. Text search first marks which of the ~3 million distinct interned strings match the query, then scans the message columns testing that bit vector - integer work only. Cost scales with distinct strings, not with the 67 million message rows.

The sidecar file

The index is written next to the binlog as <name>.binlog.binlogidx, and is rebuilt automatically whenever the binlog changes. Expect it to be several times the size of the binlog: it is stored uncompressed so it can be memory-mapped and scanned without decoding. If the binlog's directory is not writable, the sidecar falls back to a cache directory under %TEMP%.

Add *.binlogidx to .gitignore if you keep binlogs in a repository.

Building an index ahead of time

# Build (or rebuild) the index and print statistics
BinlogMcp index path/to/build.binlog [--force]
# Print statistics for an existing index
BinlogMcp index-stats path/to/build.binlog
# Time a full-text search
BinlogMcp index-search path/to/build.binlog "Copying file"

Configuration (optional):

  • BINLOG_INDEX_DIR - Directory to write sidecar indexes to (default: next to the binlog)
  • BINLOG_INDEX_PERSIST=false - Never write sidecars next to the binlog; use the temp cache instead
  • BINLOG_CACHE_SIZE=10 - Maximum indexes to keep mapped (default: 10)
  • BINLOG_CACHE_ENABLED=false - Disable the in-process index cache
  • BINLOG_MAX_RESPONSE_CHARS=4000000 - Global cap on the size of any single tool response

Use GetCacheStats to view cache status or clear it.

Result limits

Tools that can return large result sets accept a limit parameter, default 200 and capped at 5000. Responses include a truncated flag and the true total count when results were cut off. A global response-size cap acts as a backstop: a query that would still exceed it returns a short error suggesting a smaller limit or a narrower filter, rather than a payload no client can consume.

Regression testing on large binlogs

LargeBinlogSmokeTests runs every tool against a large binlog and fails if any tool errors, takes longer than 30 seconds, or returns more than 5 MB. It skips silently unless a binlog is supplied:

# PowerShell$env:BINLOGMCP_LARGE_BINLOG = "path\to\big.binlog"
dotnet test tests/BinlogMcp.Tests --filter "FullyQualifiedName~LargeBinlogSmokeTests"

Set BINLOGMCP_SMOKE_LOG to a file path to watch per-tool timings while the run is in progress.

Example Usage

Once configured, you can ask your AI assistant questions like:

  • "List the binlog files in C:\builds"
  • "What errors are in the latest build?"
  • "Which targets took the longest to execute?"
  • "What's on the critical path of this build?"

Generating Binlog Files

To create a binlog from any MSBuild/dotnet build:

dotnet build -bl # Creates msbuild.binlog
dotnet build -bl:mybuild.binlog # Custom filename
msbuild MySolution.sln -bl # Works with msbuild too

Dependencies

License

MIT

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - AndyGerlicher/BinlogMCP · GitHub
Skip to content

Repository files navigation

BinlogMcp

An MCP (Model Context Protocol) server for reading and analyzing MSBuild binary log files (.binlog).

Overview

This server exposes 54 tools that allow AI assistants to analyze MSBuild binary logs, including:

  • Build Info - Summaries, errors, warnings, properties, items
  • Performance - Slowest targets/tasks, compiler timing, parallelism analysis, I/O bottlenecks
  • Dependencies - Project graph, assembly references, NuGet packages
  • Comparison - Diff two builds, incremental build analysis
  • Diagnostics - Failure diagnosis with root cause detection and fix suggestions
  • Debugging - Target execution reasons, skipped targets, property origins, import chains
  • Evaluation - Flattened project view showing final properties, items, and imports

Standalone Tools

BinlogMCP Client - Interactive Build Investigator

An interactive REPL for analyzing MSBuild binlogs, powered by AIDavid - a virtual MSBuild debugging expert inspired by David Federman's debugging methodology. Uses the GitHub Copilot SDK for AI-powered analysis.

# Start interactive session with a binlog
dotnet run --project src/BinlogMcp.Client -- ./build.binlog
# Or launch and provide the path when prompted
dotnet run --project src/BinlogMcp.Client

Requirements: Authenticate with GitHub CLI first: gh auth login

Once loaded, you'll see an interactive prompt:


▐█▌ BinlogMCP ───────────────────────────────────
🔨 Build Log Investigator
inspired by dfederm.com/debugging-msbuild
msbuild.binlog loaded
50 analysis tools ready
───────────────────────────────────────────────────
Quick start:
[1] diagnose Automated build analysis
[2] visualize timeline Gantt chart of execution
[3] visualize slowest Slowest targets chart
[4] help All commands
Or ask: "Why did this build fail?"
───────────────────────────────────────────────────
binlog>

Interactive Commands:

  • diagnose - Run automated AIDavid diagnosis
  • visualize timeline - Open Gantt chart of build execution in browser
  • visualize slowest - Open bar chart of slowest targets
  • set baseline <path> - Set a baseline binlog for comparisons
  • compare - Compare current build with baseline
  • visualize comparison - Visual comparison chart (requires baseline)
  • help - Show available commands
  • exit - Exit the program

Or just ask questions naturally:

  • "Why did this build fail?"
  • "What targets took the longest?"
  • "Show me the errors"
  • "What version of Newtonsoft.Json is being used?"

The client maintains conversation history, so you can ask follow-up questions that reference previous answers.

Model Configuration:

  • The default model is claude-opus-4.7, configured in the session setup.

Logging: All LLM and tool interactions are logged to binlog-client.log in the current directory.

Requires GitHub CLI authentication (gh auth login) for Copilot SDK model access.

Casing Analysis

Detects and fixes path casing mismatches in MSBuild source files. On Windows, incorrect casing in paths (e.g., ..\librarya\ instead of ..\LibraryA\) can cause cache issues with NuGet and other tools.

Exposed as MCP tools — invoke them through the Client (e.g., ask "fix the casing issues in this binlog") or any MCP host:

  • GetCasingMismatches — scans a binlog for paths whose casing doesn't match disk and returns the definition site (source file + property/item) for each.
  • FixCasingMismatch — applies an XML-aware fix to a specific source file. Supports dryRun and a repoRoot safety guard that blocks edits outside the repo.

Requirements

  • .NET 10 SDK (pinned via global.json with rollForward: latestFeature)

Building

dotnet build

The repo uses Central Package Management (Directory.Packages.props), Nerdbank.GitVersioning, ReferenceTrimmer, and TreatWarningsAsErrors. All builds must be warning-free.

Running

dotnet run --project src/BinlogMcp

Testing

# Run unit tests
dotnet test tests/BinlogMcp.Tests

The interactive client (BinlogMcp.Client) uses the GitHub Copilot SDK and requires gh auth login.

MCP Configuration

Add to your MCP client configuration (e.g., Claude Desktop):

{
"mcpServers": {
"binlog": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/binlog-mcp/src/BinlogMcp"]
}
}
}

Available Tools

ToolDescription
GetCacheStatsGets binlog cache statistics and optionally clears the cache
ListBinlogsLists all binlog files in a directory (with optional recursive search)
GetBuildSummaryGets build summary: result, duration, error/warning counts, projects
GetErrorsExtracts all errors with file, line, column, code, and message
GetWarningsExtracts all warnings with the same detail as errors
GetTargetsGets target execution details sorted by duration (slowest first)
GetTasksGets task execution details with aggregation by task type
GetCriticalPathIdentifies targets on the critical path that determined build duration
GetProjectDependenciesGets project dependency graph, build order, and parallel execution info
SearchBinlogSearches binlog content for messages, errors, warnings, targets, tasks, or properties
GetPropertiesGets MSBuild properties with optional filtering and highlights important ones
GetItemsGets MSBuild item groups (Compile, Reference, PackageReference, etc.)
CompareBinlogsCompares two binlogs showing timing changes, new/fixed errors, and target differences
DiffPropertiesCompares property values between builds - added, removed, changed properties
DiffItemsCompares items between builds - added/removed files, package version changes
DiffTargetExecutionCompares target execution between builds - what ran differently
DiffImportsCompares import chains between builds - .props/.targets file changes
GetIncrementalBuildAnalysisAnalyzes incremental build behavior - executed vs skipped targets
GetNuGetRestoreAnalysisAnalyzes NuGet restore - packages, timing, and any restore issues
GetAssemblyReferencesGets assembly and project references with metadata
GetPerformanceReportComprehensive performance analysis - bottlenecks, slow targets/tasks, optimization hints
GetCompilerPerformanceDetailed C#/VB/F# compilation timing analysis
GetParallelismAnalysisBuild parallelism efficiency - concurrent operations, sequential bottlenecks
GetSlowOperationsAnalyzes slow file I/O operations (Copy, Move, Delete, Exec)
GetProjectPerformancePer-project timing rollup - identify which projects are slowest
ComparePerformanceFocused performance comparison between builds - timing regressions/improvements
GetParallelismBlockersIdentifies what's blocking parallelism - serialization points, dependency bottlenecks
AnalyzeTargetDeep dive into a single target - tasks, parameters, I/O, timing breakdown
GetFailureDiagnosisAnalyzes build failures - categorizes errors, identifies root causes, suggests fixes
GetDuplicateFileWritesDetects files written multiple times during build (wasteful I/O)
GetPropertyReassignmentsFinds MSBuild properties set multiple times (conflicts/overrides)
GetRedundantOperationsDetects tasks running with identical inputs (wasted work)
GetUnusedProjectOutputsFinds projects built but whose outputs aren't referenced (dead code)
GetTargetDependencyGraphAnalyzes target dependencies, finds circular and redundant deps
GetWarningTrendsAnalysisCategorizes warnings, suggests bulk fixes and suppressions
GetFileAccessPatternsIdentifies frequently read files and caching opportunities
GetSdkFrameworkMismatchDetects SDK/framework version conflicts across projects
GetTargetExecutionReasonsShows why targets executed (DependsOnTargets, BeforeTargets, AfterTargets)
GetSkippedTargetsLists targets that were skipped and explains why
GetPropertyOriginTraces property values back to their source file and location
GetImportChainShows the import hierarchy (.props/.targets files) for projects
TracePropertyFull property evaluation trace: initial → each assignment → final
TraceItemTrack items through build (consumed, transformed, output)
GetItemTransformsShow item transformations within targets
GetMSBuildTaskCallsShow MSBuild task invocations between projects
GetEnvironmentVariablesExtract environment variables used during the build
GetItemMetadataDeep dive into item metadata (versions, HintPaths, CopyLocal settings)
GetTargetInputsOutputsShow target incremental build inputs/outputs for debugging re-runs
GetTimelineExport timeline data for external visualization tools
GetEvaluatedProjectShows flattened project view - final properties, items, imports after evaluation
ListEmbeddedSourceFilesLists all embedded source files in the binlog's source archive (.csproj, .props, .targets, etc.)
GetEmbeddedSourceFileReads the content of a specific embedded source file from the binlog

Output Formats

21 high-value tools support multiple output formats via a format parameter:

FormatDescription
jsonDefault. Structured JSON for programmatic use
markdownHuman-readable reports with tables and bullet lists
csvTabular data for spreadsheet import
timelineJSON format for timing visualization

Tools supporting formats: GetBuildSummary, GetErrors, GetWarnings, GetTargets, GetTasks, GetCriticalPath, GetPerformanceReport, GetParallelismAnalysis, GetFailureDiagnosis, CompareBinlogs, DiffProperties, DiffTargetExecution, GetProjectDependencies, GetAssemblyReferences, GetProperties, GetItems, GetEvaluatedProject, GetProjectPerformance, ComparePerformance, GetParallelismBlockers, AnalyzeTarget.

Performance

BinlogMcp indexes a binlog once into a memory-mapped columnar sidecar and answers every subsequent query from that index. Analysis of very large binlogs is fast and bounded in memory.

Measured on a 1 GB binlog (80,313,218 records, 67 M messages, 64 M items):

Object tree (BinaryLog.ReadBuild)Streaming index
First analysis~100 GB RAM, did not complete56 s, 6.2 GB peak
Subsequent runsfull reparse0.10 s (memory-mapped open)
Full-text search of 67 M messagesnot feasible~0.9 s
All 36 analysis tools, end to endnot feasible~35 s total, 10 GB peak

How it works

  1. One streaming pass. The indexer uses BinaryLog.ReadRecords, which deserializes each record lazily and retains nothing, instead of BinaryLog.ReadBuild, which materializes every project, target, task, message, item and property as a live object graph.
  2. Messages are never pre-formatted.BuildEventArgs.Message formats its text from a format string plus arguments on demand. Doing that for every record in the sample binlog produces about 40 billion characters - roughly 80 GB of strings, and the bulk of the original memory cost. The index stores the format string and its arguments as interned string ids instead, which is about 25x smaller, and formats a message only when it appears in a query result.
  3. Columnar, zero-copy layout. The sidecar's on-disk layout is its in-memory layout, so opening an index is a file mapping plus a few pointer casts rather than a deserialization pass. Parent links are stored as packed integer scope handles, so resolving "which project owns this row" is an array lookup rather than a walk up a tree.
  4. Two-pass search. Text search first marks which of the ~3 million distinct interned strings match the query, then scans the message columns testing that bit vector - integer work only. Cost scales with distinct strings, not with the 67 million message rows.

The sidecar file

The index is written next to the binlog as <name>.binlog.binlogidx, and is rebuilt automatically whenever the binlog changes. Expect it to be several times the size of the binlog: it is stored uncompressed so it can be memory-mapped and scanned without decoding. If the binlog's directory is not writable, the sidecar falls back to a cache directory under %TEMP%.

Add *.binlogidx to .gitignore if you keep binlogs in a repository.

Building an index ahead of time

# Build (or rebuild) the index and print statistics
BinlogMcp index path/to/build.binlog [--force]
# Print statistics for an existing index
BinlogMcp index-stats path/to/build.binlog
# Time a full-text search
BinlogMcp index-search path/to/build.binlog "Copying file"

Configuration (optional):

  • BINLOG_INDEX_DIR - Directory to write sidecar indexes to (default: next to the binlog)
  • BINLOG_INDEX_PERSIST=false - Never write sidecars next to the binlog; use the temp cache instead
  • BINLOG_CACHE_SIZE=10 - Maximum indexes to keep mapped (default: 10)
  • BINLOG_CACHE_ENABLED=false - Disable the in-process index cache
  • BINLOG_MAX_RESPONSE_CHARS=4000000 - Global cap on the size of any single tool response

Use GetCacheStats to view cache status or clear it.

Result limits

Tools that can return large result sets accept a limit parameter, default 200 and capped at 5000. Responses include a truncated flag and the true total count when results were cut off. A global response-size cap acts as a backstop: a query that would still exceed it returns a short error suggesting a smaller limit or a narrower filter, rather than a payload no client can consume.

Regression testing on large binlogs

LargeBinlogSmokeTests runs every tool against a large binlog and fails if any tool errors, takes longer than 30 seconds, or returns more than 5 MB. It skips silently unless a binlog is supplied:

# PowerShell$env:BINLOGMCP_LARGE_BINLOG = "path\to\big.binlog"
dotnet test tests/BinlogMcp.Tests --filter "FullyQualifiedName~LargeBinlogSmokeTests"

Set BINLOGMCP_SMOKE_LOG to a file path to watch per-tool timings while the run is in progress.

Example Usage

Once configured, you can ask your AI assistant questions like:

  • "List the binlog files in C:\builds"
  • "What errors are in the latest build?"
  • "Which targets took the longest to execute?"
  • "What's on the critical path of this build?"

Generating Binlog Files

To create a binlog from any MSBuild/dotnet build:

dotnet build -bl # Creates msbuild.binlog
dotnet build -bl:mybuild.binlog # Custom filename
msbuild MySolution.sln -bl # Works with msbuild too

Dependencies

License

MIT

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - AndyGerlicher/BinlogMCP · GitHub
Skip to content

Repository files navigation

BinlogMcp

An MCP (Model Context Protocol) server for reading and analyzing MSBuild binary log files (.binlog).

Overview

This server exposes 54 tools that allow AI assistants to analyze MSBuild binary logs, including:

  • Build Info - Summaries, errors, warnings, properties, items
  • Performance - Slowest targets/tasks, compiler timing, parallelism analysis, I/O bottlenecks
  • Dependencies - Project graph, assembly references, NuGet packages
  • Comparison - Diff two builds, incremental build analysis
  • Diagnostics - Failure diagnosis with root cause detection and fix suggestions
  • Debugging - Target execution reasons, skipped targets, property origins, import chains
  • Evaluation - Flattened project view showing final properties, items, and imports

Standalone Tools

BinlogMCP Client - Interactive Build Investigator

An interactive REPL for analyzing MSBuild binlogs, powered by AIDavid - a virtual MSBuild debugging expert inspired by David Federman's debugging methodology. Uses the GitHub Copilot SDK for AI-powered analysis.

# Start interactive session with a binlog
dotnet run --project src/BinlogMcp.Client -- ./build.binlog
# Or launch and provide the path when prompted
dotnet run --project src/BinlogMcp.Client

Requirements: Authenticate with GitHub CLI first: gh auth login

Once loaded, you'll see an interactive prompt:


▐█▌ BinlogMCP ───────────────────────────────────
🔨 Build Log Investigator
inspired by dfederm.com/debugging-msbuild
msbuild.binlog loaded
50 analysis tools ready
───────────────────────────────────────────────────
Quick start:
[1] diagnose Automated build analysis
[2] visualize timeline Gantt chart of execution
[3] visualize slowest Slowest targets chart
[4] help All commands
Or ask: "Why did this build fail?"
───────────────────────────────────────────────────
binlog>

Interactive Commands:

  • diagnose - Run automated AIDavid diagnosis
  • visualize timeline - Open Gantt chart of build execution in browser
  • visualize slowest - Open bar chart of slowest targets
  • set baseline <path> - Set a baseline binlog for comparisons
  • compare - Compare current build with baseline
  • visualize comparison - Visual comparison chart (requires baseline)
  • help - Show available commands
  • exit - Exit the program

Or just ask questions naturally:

  • "Why did this build fail?"
  • "What targets took the longest?"
  • "Show me the errors"
  • "What version of Newtonsoft.Json is being used?"

The client maintains conversation history, so you can ask follow-up questions that reference previous answers.

Model Configuration:

  • The default model is claude-opus-4.7, configured in the session setup.

Logging: All LLM and tool interactions are logged to binlog-client.log in the current directory.

Requires GitHub CLI authentication (gh auth login) for Copilot SDK model access.

Casing Analysis

Detects and fixes path casing mismatches in MSBuild source files. On Windows, incorrect casing in paths (e.g., ..\librarya\ instead of ..\LibraryA\) can cause cache issues with NuGet and other tools.

Exposed as MCP tools — invoke them through the Client (e.g., ask "fix the casing issues in this binlog") or any MCP host:

  • GetCasingMismatches — scans a binlog for paths whose casing doesn't match disk and returns the definition site (source file + property/item) for each.
  • FixCasingMismatch — applies an XML-aware fix to a specific source file. Supports dryRun and a repoRoot safety guard that blocks edits outside the repo.

Requirements

  • .NET 10 SDK (pinned via global.json with rollForward: latestFeature)

Building

dotnet build

The repo uses Central Package Management (Directory.Packages.props), Nerdbank.GitVersioning, ReferenceTrimmer, and TreatWarningsAsErrors. All builds must be warning-free.

Running

dotnet run --project src/BinlogMcp

Testing

# Run unit tests
dotnet test tests/BinlogMcp.Tests

The interactive client (BinlogMcp.Client) uses the GitHub Copilot SDK and requires gh auth login.

MCP Configuration

Add to your MCP client configuration (e.g., Claude Desktop):

{
"mcpServers": {
"binlog": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/binlog-mcp/src/BinlogMcp"]
}
}
}

Available Tools

ToolDescription
GetCacheStatsGets binlog cache statistics and optionally clears the cache
ListBinlogsLists all binlog files in a directory (with optional recursive search)
GetBuildSummaryGets build summary: result, duration, error/warning counts, projects
GetErrorsExtracts all errors with file, line, column, code, and message
GetWarningsExtracts all warnings with the same detail as errors
GetTargetsGets target execution details sorted by duration (slowest first)
GetTasksGets task execution details with aggregation by task type
GetCriticalPathIdentifies targets on the critical path that determined build duration
GetProjectDependenciesGets project dependency graph, build order, and parallel execution info
SearchBinlogSearches binlog content for messages, errors, warnings, targets, tasks, or properties
GetPropertiesGets MSBuild properties with optional filtering and highlights important ones
GetItemsGets MSBuild item groups (Compile, Reference, PackageReference, etc.)
CompareBinlogsCompares two binlogs showing timing changes, new/fixed errors, and target differences
DiffPropertiesCompares property values between builds - added, removed, changed properties
DiffItemsCompares items between builds - added/removed files, package version changes
DiffTargetExecutionCompares target execution between builds - what ran differently
DiffImportsCompares import chains between builds - .props/.targets file changes
GetIncrementalBuildAnalysisAnalyzes incremental build behavior - executed vs skipped targets
GetNuGetRestoreAnalysisAnalyzes NuGet restore - packages, timing, and any restore issues
GetAssemblyReferencesGets assembly and project references with metadata
GetPerformanceReportComprehensive performance analysis - bottlenecks, slow targets/tasks, optimization hints
GetCompilerPerformanceDetailed C#/VB/F# compilation timing analysis
GetParallelismAnalysisBuild parallelism efficiency - concurrent operations, sequential bottlenecks
GetSlowOperationsAnalyzes slow file I/O operations (Copy, Move, Delete, Exec)
GetProjectPerformancePer-project timing rollup - identify which projects are slowest
ComparePerformanceFocused performance comparison between builds - timing regressions/improvements
GetParallelismBlockersIdentifies what's blocking parallelism - serialization points, dependency bottlenecks
AnalyzeTargetDeep dive into a single target - tasks, parameters, I/O, timing breakdown
GetFailureDiagnosisAnalyzes build failures - categorizes errors, identifies root causes, suggests fixes
GetDuplicateFileWritesDetects files written multiple times during build (wasteful I/O)
GetPropertyReassignmentsFinds MSBuild properties set multiple times (conflicts/overrides)
GetRedundantOperationsDetects tasks running with identical inputs (wasted work)
GetUnusedProjectOutputsFinds projects built but whose outputs aren't referenced (dead code)
GetTargetDependencyGraphAnalyzes target dependencies, finds circular and redundant deps
GetWarningTrendsAnalysisCategorizes warnings, suggests bulk fixes and suppressions
GetFileAccessPatternsIdentifies frequently read files and caching opportunities
GetSdkFrameworkMismatchDetects SDK/framework version conflicts across projects
GetTargetExecutionReasonsShows why targets executed (DependsOnTargets, BeforeTargets, AfterTargets)
GetSkippedTargetsLists targets that were skipped and explains why
GetPropertyOriginTraces property values back to their source file and location
GetImportChainShows the import hierarchy (.props/.targets files) for projects
TracePropertyFull property evaluation trace: initial → each assignment → final
TraceItemTrack items through build (consumed, transformed, output)
GetItemTransformsShow item transformations within targets
GetMSBuildTaskCallsShow MSBuild task invocations between projects
GetEnvironmentVariablesExtract environment variables used during the build
GetItemMetadataDeep dive into item metadata (versions, HintPaths, CopyLocal settings)
GetTargetInputsOutputsShow target incremental build inputs/outputs for debugging re-runs
GetTimelineExport timeline data for external visualization tools
GetEvaluatedProjectShows flattened project view - final properties, items, imports after evaluation
ListEmbeddedSourceFilesLists all embedded source files in the binlog's source archive (.csproj, .props, .targets, etc.)
GetEmbeddedSourceFileReads the content of a specific embedded source file from the binlog

Output Formats

21 high-value tools support multiple output formats via a format parameter:

FormatDescription
jsonDefault. Structured JSON for programmatic use
markdownHuman-readable reports with tables and bullet lists
csvTabular data for spreadsheet import
timelineJSON format for timing visualization

Tools supporting formats: GetBuildSummary, GetErrors, GetWarnings, GetTargets, GetTasks, GetCriticalPath, GetPerformanceReport, GetParallelismAnalysis, GetFailureDiagnosis, CompareBinlogs, DiffProperties, DiffTargetExecution, GetProjectDependencies, GetAssemblyReferences, GetProperties, GetItems, GetEvaluatedProject, GetProjectPerformance, ComparePerformance, GetParallelismBlockers, AnalyzeTarget.

Performance

BinlogMcp indexes a binlog once into a memory-mapped columnar sidecar and answers every subsequent query from that index. Analysis of very large binlogs is fast and bounded in memory.

Measured on a 1 GB binlog (80,313,218 records, 67 M messages, 64 M items):

Object tree (BinaryLog.ReadBuild)Streaming index
First analysis~100 GB RAM, did not complete56 s, 6.2 GB peak
Subsequent runsfull reparse0.10 s (memory-mapped open)
Full-text search of 67 M messagesnot feasible~0.9 s
All 36 analysis tools, end to endnot feasible~35 s total, 10 GB peak

How it works

  1. One streaming pass. The indexer uses BinaryLog.ReadRecords, which deserializes each record lazily and retains nothing, instead of BinaryLog.ReadBuild, which materializes every project, target, task, message, item and property as a live object graph.
  2. Messages are never pre-formatted.BuildEventArgs.Message formats its text from a format string plus arguments on demand. Doing that for every record in the sample binlog produces about 40 billion characters - roughly 80 GB of strings, and the bulk of the original memory cost. The index stores the format string and its arguments as interned string ids instead, which is about 25x smaller, and formats a message only when it appears in a query result.
  3. Columnar, zero-copy layout. The sidecar's on-disk layout is its in-memory layout, so opening an index is a file mapping plus a few pointer casts rather than a deserialization pass. Parent links are stored as packed integer scope handles, so resolving "which project owns this row" is an array lookup rather than a walk up a tree.
  4. Two-pass search. Text search first marks which of the ~3 million distinct interned strings match the query, then scans the message columns testing that bit vector - integer work only. Cost scales with distinct strings, not with the 67 million message rows.

The sidecar file

The index is written next to the binlog as <name>.binlog.binlogidx, and is rebuilt automatically whenever the binlog changes. Expect it to be several times the size of the binlog: it is stored uncompressed so it can be memory-mapped and scanned without decoding. If the binlog's directory is not writable, the sidecar falls back to a cache directory under %TEMP%.

Add *.binlogidx to .gitignore if you keep binlogs in a repository.

Building an index ahead of time

# Build (or rebuild) the index and print statistics
BinlogMcp index path/to/build.binlog [--force]
# Print statistics for an existing index
BinlogMcp index-stats path/to/build.binlog
# Time a full-text search
BinlogMcp index-search path/to/build.binlog "Copying file"

Configuration (optional):

  • BINLOG_INDEX_DIR - Directory to write sidecar indexes to (default: next to the binlog)
  • BINLOG_INDEX_PERSIST=false - Never write sidecars next to the binlog; use the temp cache instead
  • BINLOG_CACHE_SIZE=10 - Maximum indexes to keep mapped (default: 10)
  • BINLOG_CACHE_ENABLED=false - Disable the in-process index cache
  • BINLOG_MAX_RESPONSE_CHARS=4000000 - Global cap on the size of any single tool response

Use GetCacheStats to view cache status or clear it.

Result limits

Tools that can return large result sets accept a limit parameter, default 200 and capped at 5000. Responses include a truncated flag and the true total count when results were cut off. A global response-size cap acts as a backstop: a query that would still exceed it returns a short error suggesting a smaller limit or a narrower filter, rather than a payload no client can consume.

Regression testing on large binlogs

LargeBinlogSmokeTests runs every tool against a large binlog and fails if any tool errors, takes longer than 30 seconds, or returns more than 5 MB. It skips silently unless a binlog is supplied:

# PowerShell$env:BINLOGMCP_LARGE_BINLOG = "path\to\big.binlog"
dotnet test tests/BinlogMcp.Tests --filter "FullyQualifiedName~LargeBinlogSmokeTests"

Set BINLOGMCP_SMOKE_LOG to a file path to watch per-tool timings while the run is in progress.

Example Usage

Once configured, you can ask your AI assistant questions like:

  • "List the binlog files in C:\builds"
  • "What errors are in the latest build?"
  • "Which targets took the longest to execute?"
  • "What's on the critical path of this build?"

Generating Binlog Files

To create a binlog from any MSBuild/dotnet build:

dotnet build -bl # Creates msbuild.binlog
dotnet build -bl:mybuild.binlog # Custom filename
msbuild MySolution.sln -bl # Works with msbuild too

Dependencies

License

MIT

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - AndyGerlicher/BinlogMCP · GitHub
Skip to content

Repository files navigation

BinlogMcp

An MCP (Model Context Protocol) server for reading and analyzing MSBuild binary log files (.binlog).

Overview

This server exposes 54 tools that allow AI assistants to analyze MSBuild binary logs, including:

  • Build Info - Summaries, errors, warnings, properties, items
  • Performance - Slowest targets/tasks, compiler timing, parallelism analysis, I/O bottlenecks
  • Dependencies - Project graph, assembly references, NuGet packages
  • Comparison - Diff two builds, incremental build analysis
  • Diagnostics - Failure diagnosis with root cause detection and fix suggestions
  • Debugging - Target execution reasons, skipped targets, property origins, import chains
  • Evaluation - Flattened project view showing final properties, items, and imports

Standalone Tools

BinlogMCP Client - Interactive Build Investigator

An interactive REPL for analyzing MSBuild binlogs, powered by AIDavid - a virtual MSBuild debugging expert inspired by David Federman's debugging methodology. Uses the GitHub Copilot SDK for AI-powered analysis.

# Start interactive session with a binlog
dotnet run --project src/BinlogMcp.Client -- ./build.binlog
# Or launch and provide the path when prompted
dotnet run --project src/BinlogMcp.Client

Requirements: Authenticate with GitHub CLI first: gh auth login

Once loaded, you'll see an interactive prompt:


▐█▌ BinlogMCP ───────────────────────────────────
🔨 Build Log Investigator
inspired by dfederm.com/debugging-msbuild
msbuild.binlog loaded
50 analysis tools ready
───────────────────────────────────────────────────
Quick start:
[1] diagnose Automated build analysis
[2] visualize timeline Gantt chart of execution
[3] visualize slowest Slowest targets chart
[4] help All commands
Or ask: "Why did this build fail?"
───────────────────────────────────────────────────
binlog>

Interactive Commands:

  • diagnose - Run automated AIDavid diagnosis
  • visualize timeline - Open Gantt chart of build execution in browser
  • visualize slowest - Open bar chart of slowest targets
  • set baseline <path> - Set a baseline binlog for comparisons
  • compare - Compare current build with baseline
  • visualize comparison - Visual comparison chart (requires baseline)
  • help - Show available commands
  • exit - Exit the program

Or just ask questions naturally:

  • "Why did this build fail?"
  • "What targets took the longest?"
  • "Show me the errors"
  • "What version of Newtonsoft.Json is being used?"

The client maintains conversation history, so you can ask follow-up questions that reference previous answers.

Model Configuration:

  • The default model is claude-opus-4.7, configured in the session setup.

Logging: All LLM and tool interactions are logged to binlog-client.log in the current directory.

Requires GitHub CLI authentication (gh auth login) for Copilot SDK model access.

Casing Analysis

Detects and fixes path casing mismatches in MSBuild source files. On Windows, incorrect casing in paths (e.g., ..\librarya\ instead of ..\LibraryA\) can cause cache issues with NuGet and other tools.

Exposed as MCP tools — invoke them through the Client (e.g., ask "fix the casing issues in this binlog") or any MCP host:

  • GetCasingMismatches — scans a binlog for paths whose casing doesn't match disk and returns the definition site (source file + property/item) for each.
  • FixCasingMismatch — applies an XML-aware fix to a specific source file. Supports dryRun and a repoRoot safety guard that blocks edits outside the repo.

Requirements

  • .NET 10 SDK (pinned via global.json with rollForward: latestFeature)

Building

dotnet build

The repo uses Central Package Management (Directory.Packages.props), Nerdbank.GitVersioning, ReferenceTrimmer, and TreatWarningsAsErrors. All builds must be warning-free.

Running

dotnet run --project src/BinlogMcp

Testing

# Run unit tests
dotnet test tests/BinlogMcp.Tests

The interactive client (BinlogMcp.Client) uses the GitHub Copilot SDK and requires gh auth login.

MCP Configuration

Add to your MCP client configuration (e.g., Claude Desktop):

{
"mcpServers": {
"binlog": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/binlog-mcp/src/BinlogMcp"]
}
}
}

Available Tools

ToolDescription
GetCacheStatsGets binlog cache statistics and optionally clears the cache
ListBinlogsLists all binlog files in a directory (with optional recursive search)
GetBuildSummaryGets build summary: result, duration, error/warning counts, projects
GetErrorsExtracts all errors with file, line, column, code, and message
GetWarningsExtracts all warnings with the same detail as errors
GetTargetsGets target execution details sorted by duration (slowest first)
GetTasksGets task execution details with aggregation by task type
GetCriticalPathIdentifies targets on the critical path that determined build duration
GetProjectDependenciesGets project dependency graph, build order, and parallel execution info
SearchBinlogSearches binlog content for messages, errors, warnings, targets, tasks, or properties
GetPropertiesGets MSBuild properties with optional filtering and highlights important ones
GetItemsGets MSBuild item groups (Compile, Reference, PackageReference, etc.)
CompareBinlogsCompares two binlogs showing timing changes, new/fixed errors, and target differences
DiffPropertiesCompares property values between builds - added, removed, changed properties
DiffItemsCompares items between builds - added/removed files, package version changes
DiffTargetExecutionCompares target execution between builds - what ran differently
DiffImportsCompares import chains between builds - .props/.targets file changes
GetIncrementalBuildAnalysisAnalyzes incremental build behavior - executed vs skipped targets
GetNuGetRestoreAnalysisAnalyzes NuGet restore - packages, timing, and any restore issues
GetAssemblyReferencesGets assembly and project references with metadata
GetPerformanceReportComprehensive performance analysis - bottlenecks, slow targets/tasks, optimization hints
GetCompilerPerformanceDetailed C#/VB/F# compilation timing analysis
GetParallelismAnalysisBuild parallelism efficiency - concurrent operations, sequential bottlenecks
GetSlowOperationsAnalyzes slow file I/O operations (Copy, Move, Delete, Exec)
GetProjectPerformancePer-project timing rollup - identify which projects are slowest
ComparePerformanceFocused performance comparison between builds - timing regressions/improvements
GetParallelismBlockersIdentifies what's blocking parallelism - serialization points, dependency bottlenecks
AnalyzeTargetDeep dive into a single target - tasks, parameters, I/O, timing breakdown
GetFailureDiagnosisAnalyzes build failures - categorizes errors, identifies root causes, suggests fixes
GetDuplicateFileWritesDetects files written multiple times during build (wasteful I/O)
GetPropertyReassignmentsFinds MSBuild properties set multiple times (conflicts/overrides)
GetRedundantOperationsDetects tasks running with identical inputs (wasted work)
GetUnusedProjectOutputsFinds projects built but whose outputs aren't referenced (dead code)
GetTargetDependencyGraphAnalyzes target dependencies, finds circular and redundant deps
GetWarningTrendsAnalysisCategorizes warnings, suggests bulk fixes and suppressions
GetFileAccessPatternsIdentifies frequently read files and caching opportunities
GetSdkFrameworkMismatchDetects SDK/framework version conflicts across projects
GetTargetExecutionReasonsShows why targets executed (DependsOnTargets, BeforeTargets, AfterTargets)
GetSkippedTargetsLists targets that were skipped and explains why
GetPropertyOriginTraces property values back to their source file and location
GetImportChainShows the import hierarchy (.props/.targets files) for projects
TracePropertyFull property evaluation trace: initial → each assignment → final
TraceItemTrack items through build (consumed, transformed, output)
GetItemTransformsShow item transformations within targets
GetMSBuildTaskCallsShow MSBuild task invocations between projects
GetEnvironmentVariablesExtract environment variables used during the build
GetItemMetadataDeep dive into item metadata (versions, HintPaths, CopyLocal settings)
GetTargetInputsOutputsShow target incremental build inputs/outputs for debugging re-runs
GetTimelineExport timeline data for external visualization tools
GetEvaluatedProjectShows flattened project view - final properties, items, imports after evaluation
ListEmbeddedSourceFilesLists all embedded source files in the binlog's source archive (.csproj, .props, .targets, etc.)
GetEmbeddedSourceFileReads the content of a specific embedded source file from the binlog

Output Formats

21 high-value tools support multiple output formats via a format parameter:

FormatDescription
jsonDefault. Structured JSON for programmatic use
markdownHuman-readable reports with tables and bullet lists
csvTabular data for spreadsheet import
timelineJSON format for timing visualization

Tools supporting formats: GetBuildSummary, GetErrors, GetWarnings, GetTargets, GetTasks, GetCriticalPath, GetPerformanceReport, GetParallelismAnalysis, GetFailureDiagnosis, CompareBinlogs, DiffProperties, DiffTargetExecution, GetProjectDependencies, GetAssemblyReferences, GetProperties, GetItems, GetEvaluatedProject, GetProjectPerformance, ComparePerformance, GetParallelismBlockers, AnalyzeTarget.

Performance

BinlogMcp indexes a binlog once into a memory-mapped columnar sidecar and answers every subsequent query from that index. Analysis of very large binlogs is fast and bounded in memory.

Measured on a 1 GB binlog (80,313,218 records, 67 M messages, 64 M items):

Object tree (BinaryLog.ReadBuild)Streaming index
First analysis~100 GB RAM, did not complete56 s, 6.2 GB peak
Subsequent runsfull reparse0.10 s (memory-mapped open)
Full-text search of 67 M messagesnot feasible~0.9 s
All 36 analysis tools, end to endnot feasible~35 s total, 10 GB peak

How it works

  1. One streaming pass. The indexer uses BinaryLog.ReadRecords, which deserializes each record lazily and retains nothing, instead of BinaryLog.ReadBuild, which materializes every project, target, task, message, item and property as a live object graph.
  2. Messages are never pre-formatted.BuildEventArgs.Message formats its text from a format string plus arguments on demand. Doing that for every record in the sample binlog produces about 40 billion characters - roughly 80 GB of strings, and the bulk of the original memory cost. The index stores the format string and its arguments as interned string ids instead, which is about 25x smaller, and formats a message only when it appears in a query result.
  3. Columnar, zero-copy layout. The sidecar's on-disk layout is its in-memory layout, so opening an index is a file mapping plus a few pointer casts rather than a deserialization pass. Parent links are stored as packed integer scope handles, so resolving "which project owns this row" is an array lookup rather than a walk up a tree.
  4. Two-pass search. Text search first marks which of the ~3 million distinct interned strings match the query, then scans the message columns testing that bit vector - integer work only. Cost scales with distinct strings, not with the 67 million message rows.

The sidecar file

The index is written next to the binlog as <name>.binlog.binlogidx, and is rebuilt automatically whenever the binlog changes. Expect it to be several times the size of the binlog: it is stored uncompressed so it can be memory-mapped and scanned without decoding. If the binlog's directory is not writable, the sidecar falls back to a cache directory under %TEMP%.

Add *.binlogidx to .gitignore if you keep binlogs in a repository.

Building an index ahead of time

# Build (or rebuild) the index and print statistics
BinlogMcp index path/to/build.binlog [--force]
# Print statistics for an existing index
BinlogMcp index-stats path/to/build.binlog
# Time a full-text search
BinlogMcp index-search path/to/build.binlog "Copying file"

Configuration (optional):

  • BINLOG_INDEX_DIR - Directory to write sidecar indexes to (default: next to the binlog)
  • BINLOG_INDEX_PERSIST=false - Never write sidecars next to the binlog; use the temp cache instead
  • BINLOG_CACHE_SIZE=10 - Maximum indexes to keep mapped (default: 10)
  • BINLOG_CACHE_ENABLED=false - Disable the in-process index cache
  • BINLOG_MAX_RESPONSE_CHARS=4000000 - Global cap on the size of any single tool response

Use GetCacheStats to view cache status or clear it.

Result limits

Tools that can return large result sets accept a limit parameter, default 200 and capped at 5000. Responses include a truncated flag and the true total count when results were cut off. A global response-size cap acts as a backstop: a query that would still exceed it returns a short error suggesting a smaller limit or a narrower filter, rather than a payload no client can consume.

Regression testing on large binlogs

LargeBinlogSmokeTests runs every tool against a large binlog and fails if any tool errors, takes longer than 30 seconds, or returns more than 5 MB. It skips silently unless a binlog is supplied:

# PowerShell$env:BINLOGMCP_LARGE_BINLOG = "path\to\big.binlog"
dotnet test tests/BinlogMcp.Tests --filter "FullyQualifiedName~LargeBinlogSmokeTests"

Set BINLOGMCP_SMOKE_LOG to a file path to watch per-tool timings while the run is in progress.

Example Usage

Once configured, you can ask your AI assistant questions like:

  • "List the binlog files in C:\builds"
  • "What errors are in the latest build?"
  • "Which targets took the longest to execute?"
  • "What's on the critical path of this build?"

Generating Binlog Files

To create a binlog from any MSBuild/dotnet build:

dotnet build -bl # Creates msbuild.binlog
dotnet build -bl:mybuild.binlog # Custom filename
msbuild MySolution.sln -bl # Works with msbuild too

Dependencies

License

MIT

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - AndyGerlicher/BinlogMCP · GitHub
Skip to content

Repository files navigation

BinlogMcp

An MCP (Model Context Protocol) server for reading and analyzing MSBuild binary log files (.binlog).

Overview

This server exposes 54 tools that allow AI assistants to analyze MSBuild binary logs, including:

  • Build Info - Summaries, errors, warnings, properties, items
  • Performance - Slowest targets/tasks, compiler timing, parallelism analysis, I/O bottlenecks
  • Dependencies - Project graph, assembly references, NuGet packages
  • Comparison - Diff two builds, incremental build analysis
  • Diagnostics - Failure diagnosis with root cause detection and fix suggestions
  • Debugging - Target execution reasons, skipped targets, property origins, import chains
  • Evaluation - Flattened project view showing final properties, items, and imports

Standalone Tools

BinlogMCP Client - Interactive Build Investigator

An interactive REPL for analyzing MSBuild binlogs, powered by AIDavid - a virtual MSBuild debugging expert inspired by David Federman's debugging methodology. Uses the GitHub Copilot SDK for AI-powered analysis.

# Start interactive session with a binlog
dotnet run --project src/BinlogMcp.Client -- ./build.binlog
# Or launch and provide the path when prompted
dotnet run --project src/BinlogMcp.Client

Requirements: Authenticate with GitHub CLI first: gh auth login

Once loaded, you'll see an interactive prompt:


▐█▌ BinlogMCP ───────────────────────────────────
🔨 Build Log Investigator
inspired by dfederm.com/debugging-msbuild
msbuild.binlog loaded
50 analysis tools ready
───────────────────────────────────────────────────
Quick start:
[1] diagnose Automated build analysis
[2] visualize timeline Gantt chart of execution
[3] visualize slowest Slowest targets chart
[4] help All commands
Or ask: "Why did this build fail?"
───────────────────────────────────────────────────
binlog>

Interactive Commands:

  • diagnose - Run automated AIDavid diagnosis
  • visualize timeline - Open Gantt chart of build execution in browser
  • visualize slowest - Open bar chart of slowest targets
  • set baseline <path> - Set a baseline binlog for comparisons
  • compare - Compare current build with baseline
  • visualize comparison - Visual comparison chart (requires baseline)
  • help - Show available commands
  • exit - Exit the program

Or just ask questions naturally:

  • "Why did this build fail?"
  • "What targets took the longest?"
  • "Show me the errors"
  • "What version of Newtonsoft.Json is being used?"

The client maintains conversation history, so you can ask follow-up questions that reference previous answers.

Model Configuration:

  • The default model is claude-opus-4.7, configured in the session setup.

Logging: All LLM and tool interactions are logged to binlog-client.log in the current directory.

Requires GitHub CLI authentication (gh auth login) for Copilot SDK model access.

Casing Analysis

Detects and fixes path casing mismatches in MSBuild source files. On Windows, incorrect casing in paths (e.g., ..\librarya\ instead of ..\LibraryA\) can cause cache issues with NuGet and other tools.

Exposed as MCP tools — invoke them through the Client (e.g., ask "fix the casing issues in this binlog") or any MCP host:

  • GetCasingMismatches — scans a binlog for paths whose casing doesn't match disk and returns the definition site (source file + property/item) for each.
  • FixCasingMismatch — applies an XML-aware fix to a specific source file. Supports dryRun and a repoRoot safety guard that blocks edits outside the repo.

Requirements

  • .NET 10 SDK (pinned via global.json with rollForward: latestFeature)

Building

dotnet build

The repo uses Central Package Management (Directory.Packages.props), Nerdbank.GitVersioning, ReferenceTrimmer, and TreatWarningsAsErrors. All builds must be warning-free.

Running

dotnet run --project src/BinlogMcp

Testing

# Run unit tests
dotnet test tests/BinlogMcp.Tests

The interactive client (BinlogMcp.Client) uses the GitHub Copilot SDK and requires gh auth login.

MCP Configuration

Add to your MCP client configuration (e.g., Claude Desktop):

{
"mcpServers": {
"binlog": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/binlog-mcp/src/BinlogMcp"]
}
}
}

Available Tools

ToolDescription
GetCacheStatsGets binlog cache statistics and optionally clears the cache
ListBinlogsLists all binlog files in a directory (with optional recursive search)
GetBuildSummaryGets build summary: result, duration, error/warning counts, projects
GetErrorsExtracts all errors with file, line, column, code, and message
GetWarningsExtracts all warnings with the same detail as errors
GetTargetsGets target execution details sorted by duration (slowest first)
GetTasksGets task execution details with aggregation by task type
GetCriticalPathIdentifies targets on the critical path that determined build duration
GetProjectDependenciesGets project dependency graph, build order, and parallel execution info
SearchBinlogSearches binlog content for messages, errors, warnings, targets, tasks, or properties
GetPropertiesGets MSBuild properties with optional filtering and highlights important ones
GetItemsGets MSBuild item groups (Compile, Reference, PackageReference, etc.)
CompareBinlogsCompares two binlogs showing timing changes, new/fixed errors, and target differences
DiffPropertiesCompares property values between builds - added, removed, changed properties
DiffItemsCompares items between builds - added/removed files, package version changes
DiffTargetExecutionCompares target execution between builds - what ran differently
DiffImportsCompares import chains between builds - .props/.targets file changes
GetIncrementalBuildAnalysisAnalyzes incremental build behavior - executed vs skipped targets
GetNuGetRestoreAnalysisAnalyzes NuGet restore - packages, timing, and any restore issues
GetAssemblyReferencesGets assembly and project references with metadata
GetPerformanceReportComprehensive performance analysis - bottlenecks, slow targets/tasks, optimization hints
GetCompilerPerformanceDetailed C#/VB/F# compilation timing analysis
GetParallelismAnalysisBuild parallelism efficiency - concurrent operations, sequential bottlenecks
GetSlowOperationsAnalyzes slow file I/O operations (Copy, Move, Delete, Exec)
GetProjectPerformancePer-project timing rollup - identify which projects are slowest
ComparePerformanceFocused performance comparison between builds - timing regressions/improvements
GetParallelismBlockersIdentifies what's blocking parallelism - serialization points, dependency bottlenecks
AnalyzeTargetDeep dive into a single target - tasks, parameters, I/O, timing breakdown
GetFailureDiagnosisAnalyzes build failures - categorizes errors, identifies root causes, suggests fixes
GetDuplicateFileWritesDetects files written multiple times during build (wasteful I/O)
GetPropertyReassignmentsFinds MSBuild properties set multiple times (conflicts/overrides)
GetRedundantOperationsDetects tasks running with identical inputs (wasted work)
GetUnusedProjectOutputsFinds projects built but whose outputs aren't referenced (dead code)
GetTargetDependencyGraphAnalyzes target dependencies, finds circular and redundant deps
GetWarningTrendsAnalysisCategorizes warnings, suggests bulk fixes and suppressions
GetFileAccessPatternsIdentifies frequently read files and caching opportunities
GetSdkFrameworkMismatchDetects SDK/framework version conflicts across projects
GetTargetExecutionReasonsShows why targets executed (DependsOnTargets, BeforeTargets, AfterTargets)
GetSkippedTargetsLists targets that were skipped and explains why
GetPropertyOriginTraces property values back to their source file and location
GetImportChainShows the import hierarchy (.props/.targets files) for projects
TracePropertyFull property evaluation trace: initial → each assignment → final
TraceItemTrack items through build (consumed, transformed, output)
GetItemTransformsShow item transformations within targets
GetMSBuildTaskCallsShow MSBuild task invocations between projects
GetEnvironmentVariablesExtract environment variables used during the build
GetItemMetadataDeep dive into item metadata (versions, HintPaths, CopyLocal settings)
GetTargetInputsOutputsShow target incremental build inputs/outputs for debugging re-runs
GetTimelineExport timeline data for external visualization tools
GetEvaluatedProjectShows flattened project view - final properties, items, imports after evaluation
ListEmbeddedSourceFilesLists all embedded source files in the binlog's source archive (.csproj, .props, .targets, etc.)
GetEmbeddedSourceFileReads the content of a specific embedded source file from the binlog

Output Formats

21 high-value tools support multiple output formats via a format parameter:

FormatDescription
jsonDefault. Structured JSON for programmatic use
markdownHuman-readable reports with tables and bullet lists
csvTabular data for spreadsheet import
timelineJSON format for timing visualization

Tools supporting formats: GetBuildSummary, GetErrors, GetWarnings, GetTargets, GetTasks, GetCriticalPath, GetPerformanceReport, GetParallelismAnalysis, GetFailureDiagnosis, CompareBinlogs, DiffProperties, DiffTargetExecution, GetProjectDependencies, GetAssemblyReferences, GetProperties, GetItems, GetEvaluatedProject, GetProjectPerformance, ComparePerformance, GetParallelismBlockers, AnalyzeTarget.

Performance

BinlogMcp indexes a binlog once into a memory-mapped columnar sidecar and answers every subsequent query from that index. Analysis of very large binlogs is fast and bounded in memory.

Measured on a 1 GB binlog (80,313,218 records, 67 M messages, 64 M items):

Object tree (BinaryLog.ReadBuild)Streaming index
First analysis~100 GB RAM, did not complete56 s, 6.2 GB peak
Subsequent runsfull reparse0.10 s (memory-mapped open)
Full-text search of 67 M messagesnot feasible~0.9 s
All 36 analysis tools, end to endnot feasible~35 s total, 10 GB peak

How it works

  1. One streaming pass. The indexer uses BinaryLog.ReadRecords, which deserializes each record lazily and retains nothing, instead of BinaryLog.ReadBuild, which materializes every project, target, task, message, item and property as a live object graph.
  2. Messages are never pre-formatted.BuildEventArgs.Message formats its text from a format string plus arguments on demand. Doing that for every record in the sample binlog produces about 40 billion characters - roughly 80 GB of strings, and the bulk of the original memory cost. The index stores the format string and its arguments as interned string ids instead, which is about 25x smaller, and formats a message only when it appears in a query result.
  3. Columnar, zero-copy layout. The sidecar's on-disk layout is its in-memory layout, so opening an index is a file mapping plus a few pointer casts rather than a deserialization pass. Parent links are stored as packed integer scope handles, so resolving "which project owns this row" is an array lookup rather than a walk up a tree.
  4. Two-pass search. Text search first marks which of the ~3 million distinct interned strings match the query, then scans the message columns testing that bit vector - integer work only. Cost scales with distinct strings, not with the 67 million message rows.

The sidecar file

The index is written next to the binlog as <name>.binlog.binlogidx, and is rebuilt automatically whenever the binlog changes. Expect it to be several times the size of the binlog: it is stored uncompressed so it can be memory-mapped and scanned without decoding. If the binlog's directory is not writable, the sidecar falls back to a cache directory under %TEMP%.

Add *.binlogidx to .gitignore if you keep binlogs in a repository.

Building an index ahead of time

# Build (or rebuild) the index and print statistics
BinlogMcp index path/to/build.binlog [--force]
# Print statistics for an existing index
BinlogMcp index-stats path/to/build.binlog
# Time a full-text search
BinlogMcp index-search path/to/build.binlog "Copying file"

Configuration (optional):

  • BINLOG_INDEX_DIR - Directory to write sidecar indexes to (default: next to the binlog)
  • BINLOG_INDEX_PERSIST=false - Never write sidecars next to the binlog; use the temp cache instead
  • BINLOG_CACHE_SIZE=10 - Maximum indexes to keep mapped (default: 10)
  • BINLOG_CACHE_ENABLED=false - Disable the in-process index cache
  • BINLOG_MAX_RESPONSE_CHARS=4000000 - Global cap on the size of any single tool response

Use GetCacheStats to view cache status or clear it.

Result limits

Tools that can return large result sets accept a limit parameter, default 200 and capped at 5000. Responses include a truncated flag and the true total count when results were cut off. A global response-size cap acts as a backstop: a query that would still exceed it returns a short error suggesting a smaller limit or a narrower filter, rather than a payload no client can consume.

Regression testing on large binlogs

LargeBinlogSmokeTests runs every tool against a large binlog and fails if any tool errors, takes longer than 30 seconds, or returns more than 5 MB. It skips silently unless a binlog is supplied:

# PowerShell$env:BINLOGMCP_LARGE_BINLOG = "path\to\big.binlog"
dotnet test tests/BinlogMcp.Tests --filter "FullyQualifiedName~LargeBinlogSmokeTests"

Set BINLOGMCP_SMOKE_LOG to a file path to watch per-tool timings while the run is in progress.

Example Usage

Once configured, you can ask your AI assistant questions like:

  • "List the binlog files in C:\builds"
  • "What errors are in the latest build?"
  • "Which targets took the longest to execute?"
  • "What's on the critical path of this build?"

Generating Binlog Files

To create a binlog from any MSBuild/dotnet build:

dotnet build -bl # Creates msbuild.binlog
dotnet build -bl:mybuild.binlog # Custom filename
msbuild MySolution.sln -bl # Works with msbuild too

Dependencies

License

MIT

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages