Skip to content

feat: add analyze tool for project-scoped cop diagnostics - #32

Merged
Arthurvdv merged 6 commits into
mainfrom
feat/analyze-tool
Sep 21, 2026
Merged

Arthurvdv merged 6 commits into
mainfrom
feat/analyze-tool

Conversation

@Arthurvdv

@Arthurvdv Arthurvdv commented Sep 21, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Adds a native analyze MCP tool that wraps al_compile with onlyErrors=false, enableCodeAnalysis=true and no diagnostic cap, then enriches each diagnostic with the owning analyzer name and whether a native code fix exists.
  • Adds CompileDiagnosticsParser — a pure, stateless parser for almcp's al_compile response JSON that handles camelCase/PascalCase, numeric/string severities, the SourceFile(path@line:col) location format (including paths with parentheses and @), and message warnings.
  • Adds a multi-project CreateProxy overload to AlMcpFixture for integration tests that need diagnostics from more than one AL project.

What changed

  • src/ALCops.Mcp/Models/AnalyzeResult.cs — record types for the tool's JSON output: AnalyzeDiagnostic, AnalyzeSummary, AnalyzeResult.
  • src/ALCops.Mcp/Services/CompileDiagnosticsParser.cs — static parser: Parse (CallToolResult and string overloads), ParseLocation, ExtractWarnings, IsCompilerDiagnostic, Enrich, Filter, Sort, Build. No BC types, no I/O.
  • src/ALCops.Mcp/Tools/AnalyzeTool.cs — the MCP tool endpoint. Resolves the proxy via IServiceProvider so it becomes {error:"ProxyUnavailable"} under --no-proxy instead of a schema leak. Parameters: filePath, folderPath, projectPath, severities, analyzers, ruleIds, limit.
  • tests/ALCops.Mcp.Tests/CompileDiagnosticsParserTests.cs — 26 pure unit tests covering location parsing, JSON deserialization (camelCase, PascalCase, numeric severities, missing code, unknown properties), CallToolResult extraction (structured wins, non-JSON fallback, no-JSON throws), warning extraction, compiler-diagnostic detection, enrichment, filtering (file path, folder prefix, project+file AND, unlocated, severities, analyzers, ruleIds), sorting and build (truncation, summary, key order).
  • tests/ALCops.Mcp.Tests/AnalyzeToolTests.cs — 3 no-almcp unit tests (ProxyUnavailable when no proxy, ProxyUnavailable when almcp unavailable, schema check), 7 [AlMcpFact] integration tests against a two-project workspace (project-scoped, default scope, explicit ProjB, filtered by rule+severity+project, limit truncation, Compiler analyzer filter, invalid limit).
  • tests/ALCops.Mcp.Tests/AlMcpProxyTests.cs — added CreateProxy(CapturingLogger, IReadOnlyList<string>) overload for multi-project fixtures.
  • AGENTS.md, README.md, src/ALCops.Mcp/README.md — updated tool count from four to five, added analyze to tool tables, documented analyze as the preferred verification call, noted the al_compile onlyErrors default.

Behaviour changes

  • New tool analyze available when almcp is present (not under --no-proxy).
  • No changes to existing tools or ForwardAsync.
  • McpHost.cs is untouched; analyze is auto-discovered via WithToolsFromAssembly().

Test plan

  • dotnet build --configuration Release — 0 warnings, 0 errors
  • dotnet test --configuration Release — 216 passed, 0 failed, 0 skipped
  • Parser unit tests (26) cover all parsing paths, edge cases and key ordering
  • No-almcp unit tests verify ProxyUnavailable with message mentioning --no-proxy and "not available"
  • Schema test confirms services and cancellationToken are hidden from the input schema
  • Integration tests run against real almcp with two AL projects (ApplyFixProject + FixAllProject)
  • Project-scoped results contain only diagnostics from the scoped project
  • Filter by ruleId+severity+project returns only matching LC0020 hits, sorted by file
  • limit: 1 produces truncated: true with totalCount > 1
  • analyzers: ["Compiler"] returns only AL#### diagnostics
  • Existing tests unchanged and still passing

Closes #31

Side observation (fixed in this PR)

ApplyFixThenCompileTests passed onlyErrors as a top-level al_compile argument, which almcp ignores; the flag lives inside the options object. The tests still worked because an absent options object also defaults to onlyErrors: false (and disables the diagnostics cap), not because warnings survive an errors-only filter. The tests now pass options: { onlyErrors: false } and the README/AGENTS.md wording names the options object.

🤖 Generated with Claude Code

Arthurvdv and others added 6 commits September 21, 2026 16:50
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Fix 1: separate enrichment project from project scope filter;
  file/folder scoped calls without projectPath now auto-resolve the
  containing project via FindContainingProject (longest prefix match)
  and omit the project scope filter so the file/folder is the only scope
- Fix 2: add IncludeUnlocated to AnalyzeFilter; Filter returns dropped
  count; succeeded=false warning always fires with raw+filtered counts;
  dropped-unlocated hint added when applicable
- Fix 3: rename CompileFailed to ProxyCallFailed with descriptive message
- Fix 4: extract Error() helper in AnalyzeTool for error envelope
- Fix 5: replace hand-rolled ParseLocation scanner with [GeneratedRegex]

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Fix 1: make droppedUnlocated warning independent of succeeded flag
- Fix 2: extract BuildWarnings to CompileDiagnosticsParser, replace tautological tests with four cases calling product code
- Fix 3: validate explicit projectPath against known projects, return UnknownProject error with listed projects
- Fix 4: collapse project-scope-filter if/else-if/else into single expression

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…shape

ApplyFixThenCompileTests passed `onlyErrors` as a top-level al_compile
argument, which almcp ignores; it only worked because an absent `options`
object also defaults to `onlyErrors: false`. Nest it under `options` and
say so in the docs that tell callers to pass `onlyErrors: false`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.

Add an analyze tool for project-scoped diagnostics

1 participant