Skip to content

Include compiler error details (file, line, column) in Build action structured response#426

Merged
jongalloway merged 7 commits intomainfrom
copilot/include-compiler-error-messages
Apr 4, 2026
Merged

Include compiler error details (file, line, column) in Build action structured response#426
jongalloway merged 7 commits intomainfrom
copilot/include-compiler-error-messages

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 3, 2026

The dotnet_project Build action returned error/warning counts but not the actual diagnostic messages, forcing AI agents to re-parse raw CLI output to identify what failed and where.

Changes

New types

  • BuildDiagnosticfile, line, column, code, message, severity for each compiler/MSBuild diagnostic
  • BuildResult — structured build summary: success, project, configuration, errorCount, warningCount, summary, errors, warnings

Parsing

  • ErrorResultFactory.ParseBuildOutput(rawOutput, project, configuration) — parses the raw DotNetCommandExecutor text output into a BuildResult, extracting diagnostics via the existing CompilerErrorRegex
  • ErrorResult gains File?, Line?, Column? fields, now populated in ParseErrorLine from regex captures

Build action

DotnetProject (Build path) now returns BuildResult as StructuredContent alongside the unchanged raw text:

{
  "success": false,
  "project": "NewsletterApp.csproj",
  "configuration": "Release",
  "errorCount": 1,
  "warningCount": 0,
  "summary": "Build FAILED (1 error(s), 0 warning(s))",
  "errors": [
    {
      "file": "NewsletterApp.Rendering.cs",
      "line": 9,
      "column": 51,
      "code": "CS0246",
      "message": "The type or namespace name 'IRenderable' could not be found (are you missing a using directive or an assembly reference?)",
      "severity": "error"
    }
  ]
}

Tests

  • Unit tests for ParseBuildOutput (success, failure with errors/warnings, null/empty input) and ErrorResult location fields
  • ConsolidatedProjectToolTests: asserts StructuredContent is always present on Build responses
  • BuildErrorScenarioTests: updated to verify structured errors array with file/line/column/code/message
  • McpScenarioClient.CallToolAsync() added to expose CallToolResult (including StructuredContent) in scenario tests

Copilot AI linked an issue Apr 3, 2026 that may be closed by this pull request
@jongalloway jongalloway marked this pull request as ready for review April 3, 2026 16:58
Copilot AI and others added 4 commits April 3, 2026 17:10
…ne, column, code, message)

Agent-Logs-Url: https://github.com/jongalloway/dotnet-mcp/sessions/570f2997-b3f4-4ce6-b332-fee45087c67c

Co-authored-by: jongalloway <68539+jongalloway@users.noreply.github.com>
Agent-Logs-Url: https://github.com/jongalloway/dotnet-mcp/sessions/570f2997-b3f4-4ce6-b332-fee45087c67c

Co-authored-by: jongalloway <68539+jongalloway@users.noreply.github.com>
…tructured response

Agent-Logs-Url: https://github.com/jongalloway/dotnet-mcp/sessions/570f2997-b3f4-4ce6-b332-fee45087c67c

Co-authored-by: jongalloway <68539+jongalloway@users.noreply.github.com>
Copilot AI changed the title [WIP] Update build action to include compiler error messages in response Include compiler error details (file, line, column) in Build action structured response Apr 3, 2026
Copilot AI requested a review from jongalloway April 3, 2026 17:21
@jongalloway jongalloway requested a review from Copilot April 3, 2026 17:37
Comment thread DotNetMcp/Errors/ErrorResultFactory.cs Fixed
Comment thread DotNetMcp/Errors/ErrorResultFactory.cs Fixed
Comment thread DotNetMcp/Errors/ErrorResultFactory.cs Fixed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances the dotnet_project Build action by returning structured build diagnostics (file/line/column/code/message/severity) alongside the existing raw CLI output, enabling callers to consume compiler/MSBuild errors without re-parsing text output.

Changes:

  • Added BuildDiagnostic and BuildResult types and implemented ErrorResultFactory.ParseBuildOutput(...) to extract per-diagnostic details from build output.
  • Updated dotnet_project Build action to always attach a BuildResult as StructuredContent.
  • Extended tests (unit + scenario) to validate structured build outputs and added a scenario client API to return full CallToolResult.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
DotNetMcp/Tools/Cli/DotNetCliTools.Project.Consolidated.cs Attaches BuildResult structured content for Build action responses.
DotNetMcp/Errors/ErrorResultFactory.cs Parses build output into BuildResult and populates ErrorResult file/line/column fields.
DotNetMcp/Errors/ErrorResult.cs Adds file/line/column to ErrorResult; introduces BuildDiagnostic and BuildResult DTOs.
DotNetMcp.Tests/Tools/ConsolidatedProjectToolTests.cs Asserts Build responses include structured content.
DotNetMcp.Tests/Scenarios/McpScenarioClient.cs Adds API to return full CallToolResult (incl. structured content) in scenario tests.
DotNetMcp.Tests/Scenarios/BuildErrorScenarioTests.cs Updates scenario to validate structured errors[] diagnostics details.
DotNetMcp.Tests/Errors/ErrorResultFactoryTests.cs Adds unit tests for ParseBuildOutput and ErrorResult location fields.
.config/dotnet-tools.json Adds dotnet-ef tool entry to the local tool manifest.
Comments suppressed due to low confidence (1)

DotNetMcp/Errors/ErrorResultFactory.cs:731

  • ParseBuildOutput defaults exitCode to 0, so if the output doesn't contain an "Exit Code:" line (e.g., when DotnetProject.Build returns a validation error like "Error: ..." before invoking dotnet), the resulting BuildResult will incorrectly report Success=true. Track whether an exit code was found and fall back to other signals (e.g., any parsed error diagnostics, "Build FAILED" outcome, or leading "Error:") to set Success=false when appropriate.
        // Determine exit code from the trailing "Exit Code: N" line.
        var exitCode = 0;
        foreach (var line in lines)
        {
            var trimmed = line.TrimStart();
            if (trimmed.StartsWith("Exit Code:", StringComparison.OrdinalIgnoreCase))
            {
                var codeStr = trimmed.Substring("Exit Code:".Length).Trim();
                if (int.TryParse(codeStr, out var parsed))
                    exitCode = parsed;
                break;
            }
        }

        var success = exitCode == 0;

Comment thread DotNetMcp/Errors/ErrorResultFactory.cs Outdated
Comment on lines +815 to +818
return new BuildResult
{
Success = success,
Project = string.IsNullOrWhiteSpace(project) ? null : project,
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BuildResult.Project is forwarded from the requested/auto-discovered project path, which can be an absolute local path (WorkspaceDiscovery returns full paths). Consider sanitizing/redacting this value (similar to File/Message) before putting it into structured content to avoid leaking user machine paths.

Suggested change
return new BuildResult
{
Success = success,
Project = string.IsNullOrWhiteSpace(project) ? null : project,
static string? SanitizeProjectForStructuredContent(string? projectValue)
{
if (string.IsNullOrWhiteSpace(projectValue))
{
return null;
}
return System.IO.Path.IsPathRooted(projectValue)
? System.IO.Path.GetFileName(projectValue)
: projectValue;
}
return new BuildResult
{
Success = success,
Project = SanitizeProjectForStructuredContent(project),

Copilot uses AI. Check for mistakes.
Comment thread DotNetMcp/Errors/ErrorResultFactory.cs Outdated
Comment on lines +686 to +689
// Regex to match "Build FAILED" or "Build succeeded" outcome line.
[GeneratedRegex(@"Build\s+(FAILED|succeeded)", RegexOptions.IgnoreCase)]
private static partial Regex BuildOutcomeRegex();

Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BuildOutcomeRegex() is declared but not used by ParseBuildOutput. If you intended to use it as a fallback when the "Exit Code:" line is missing, wire it in; otherwise remove it to avoid dead code and potential analyzer warnings.

This issue also appears on line 716 of the same file.

Suggested change
// Regex to match "Build FAILED" or "Build succeeded" outcome line.
[GeneratedRegex(@"Build\s+(FAILED|succeeded)", RegexOptions.IgnoreCase)]
private static partial Regex BuildOutcomeRegex();

Copilot uses AI. Check for mistakes.
Comment thread .config/dotnet-tools.json Outdated
Comment on lines +5 to +11
"dotnet-ef": {
"version": "10.0.5",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The local tool manifest (.config/dotnet-tools.json) was modified to add dotnet-ef. This repo’s guidance is to keep the manifest stable and not change tool entries/versions unless explicitly requested; please revert this change if it was incidental (e.g., from running dotnet tool commands).

Suggested change
"dotnet-ef": {
"version": "10.0.5",
"commands": [
"dotnet-ef"
],
"rollForward": false
}

Copilot uses AI. Check for mistakes.
@jongalloway
Copy link
Copy Markdown
Owner

@copilot apply changes based on the comments in this thread

…ath, fix CodeQL LINQ/ternary hints

Agent-Logs-Url: https://github.com/jongalloway/dotnet-mcp/sessions/c59670df-878a-42a5-b128-84a0288337ae

Co-authored-by: jongalloway <68539+jongalloway@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 3, 2026

@copilot apply changes based on the comments in this thread

Applied all review feedback in commit 33be3a1:

  • Removed BuildOutcomeRegex() — it was declared but never used
  • Sanitized BuildResult.Project — added SanitizeProjectPath() that reduces absolute paths to filename-only (e.g. /home/user/projects/MyApp.csprojMyApp.csproj) while keeping relative paths unchanged
  • CodeQL "Missed opportunity to use Select" — exit code extraction now uses lines.Select(...).FirstOrDefault(...) and the compiler match loop uses lines.Select(line => CompilerErrorRegex().Match(line)).Where(m => m.Success)
  • CodeQL "Missed ternary opportunity"if/else summary assignment replaced with a single ternary expression
  • Reverted .config/dotnet-tools.json — dotnet-ef entry removed again (it had crept back in the final squash commit)

…lute path detection

Agent-Logs-Url: https://github.com/jongalloway/dotnet-mcp/sessions/c59670df-878a-42a5-b128-84a0288337ae

Co-authored-by: jongalloway <68539+jongalloway@users.noreply.github.com>
@jongalloway jongalloway merged commit a05597d into main Apr 4, 2026
4 checks passed
@jongalloway jongalloway deleted the copilot/include-compiler-error-messages branch April 4, 2026 01:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build action should include compiler error messages in the response

4 participants