Skip to content

mcp: fixes and improvements for agent tools, lint rules and error capture #358

Closed

Description

@erkamyaman

Context

Fixes and improvements from a code audit of agent tool design, lint rules and error capture, done in October 2026. Roadmap work lives in #340, #341, #342 and #343. Items marked (to confirm) were not reproduced; check them before fixing.

Agent tool design

Problems

Low

  • No tool titles or structured output: no agent.registerTool call in devframe.ts sets title, so MCP clients show raw ids such as pangular:list-http-calls for most tools; only the RPC-backed tools (for example get-components.ts:44, build-meta.ts:28) have one. No tool sets tags or outputSchema, and every live tool returns markdown only. Add a short title and per-inspector tags to each tool, and return structuredContent next to the markdown for the list tools (list-pages, list-http-calls, list-components) so agents get stable ids without parsing text (packages/devtools/src/devframe.ts:909, 1743, 2281).
  • Undeclared page on form tools: form-action and fill-form call unknownFormPage(args), which reads page, but neither inputSchema declares it, so clients never send it and the check is dead. Add page: PAGE_ARGUMENT to both schemas or remove the check (packages/devtools/src/devframe.ts:2798, 2851, 2425).
  • Inconsistent page argument: highlight, inspect-component, defer-blocks and inspect-providers still accept a pageId alias next to page, while the others take only page. Use PAGE_ARGUMENT everywhere and drop the pageId aliases in a minor release (packages/devtools/src/devframe.ts:1761, 1825, 1914, 2100).
  • Uncapped raw resources: the component-tree, signal-graph, injector-tree and ngrx-store resources return JSON.stringify(state, null, 2) of every page, with no size cap and no untrusted-data notice, although the strings come from the page. Cap the size, drop the indentation and add the UNTRUSTED notice (or an _untrusted field) (packages/devtools/src/devframe.ts:1616, 1625, 1634, 1643).
  • Panel-only actions: clear-http-calls, clear-router-navigations, analog-clear-calls and request-component-pick have no agent tool, so an agent can't reset recorded data between repro runs. Add a clear-recordings tool (http, router, analog) gated by the matching actions.*, and list it in ACTION_TOOLS and AGENT_INSPECTOR and in agents/tools.md (packages/devtools/src/devframe.ts:623, 833, 1355, packages/devtools/src/rpc/analog-register.ts:227).
  • analog-call-api path not described: path has no description and nothing says it must be a same-origin path starting with /, so agents guess whether to pass a full URL. Describe path, method and body, and spell out the confirm rule in the schema (packages/devtools/src/rpc/analog-register.ts:351-358).

Improvements

  • Generate AGENT_INSPECTOR, ACTION_TOOLS and PAGE_AGENT_ENTRIES from metadata on each registerTool call (inspector, action, needs page) instead of three hand-kept lists, so a new tool can't be left out (packages/devtools/src/config.ts:407, 495, 548, packages/devtools/src/devframe.ts).
  • Add MCP prompts for common workflows ("debug an invalid form", "why didn't this route load", "find slow change detection"), each chaining list-pages with the inspect and explain tools (packages/devtools/src/devframe.ts).
  • Turn the six resources into per-page resource templates (pangular://page/{pageId}/component-tree) and send resources/list_changed when a page connects or expires, so clients can subscribe instead of polling (packages/devtools/src/devframe.ts:1610-1662).
  • Add a general wait-for tool (app stable, navigation end, HTTP idle, @defer complete) that generalizes wait-for-form and navigate's waitFor: 'stable' (packages/devtools/src/devframe.ts:2730, 2281).
  • Add a "snapshot everything" export tool (component tree, route, forms, HTTP, NgRx) for bug reports, next to the existing export-form and export-navigation (packages/devtools/src/devframe.ts:2241, 2714).
  • Keep tool descriptions under about 600 characters. inspect-forms, navigate and the ngrx-store resource run past 1,000, which costs context in every client's tool list (packages/devtools/src/devframe.ts:1638, 2281, 2437).
  • Add a module and lazy-chunk graph tool through the Vite plugin, as vite-plugin-mcp does (packages/devtools/src/vite.ts).

Already tracked elsewhere

Lint rules and error capture

Problems

Medium

  • email-in-url leaks the email: the finding sets route: emailed.url, so the address the rule warns about is sent to the panel and agents. redactUrl does not mask email addresses, so the same URL also shows in the navigation list. Mask emails in the finding (for example [email]), or report the route pattern only, and consider masking emails in redactUrl too (packages/devtools/src/rpc/router-config-tools.ts:530-536, packages/devtools/src/router.ts:290).

Low

  • forms rejection attribution: while submittingForm is set, any unhandledrejection on the page is recorded as a threw submit event for that form, even when it is unrelated. Attribute only rejections that come from the submission action, for example by wrapping the action's promise (packages/devtools/src/forms-collector.ts:329, 349, 608-622).
  • hydration capture redacts first: the HTTP hydration console patch runs redactMessage over up to 5000 characters on every console.warn and console.error, before isHydrationMessage checks the text. Check first, then redact (packages/devtools/src/http.ts:355-359).
  • impure-pipe-in-for misses *ngFor: forBlocks only matches @for (, so templates that still use *ngFor never get the finding. Also match *ngFor host elements, or parse templates with @angular/compiler parseTemplate (packages/devtools/src/rpc/pipe-lint.ts:108-123).
  • forms NG code regex: setupErrorOf uses /NG0?1\d{3}/ with no word boundary, so it also matches NG1xxx and codes inside longer tokens, while the hydration regex uses \b. Use /\bNG01\d{3}\b[^\n]*/ and share one NG code parser (packages/devtools/src/forms-collector.ts:95-103).

Improvements

  • Server-side errors: capture SSR render errors in the SSR middleware and Vite dev-server errors in the Vite plugin, so agents see compile and SSR failures (packages/devtools/src/ssr-middleware.ts, packages/devtools/src/vite.ts).
  • Template diagnostics: run Angular's extended diagnostics (nullish coalescing on a non-nullable value, signal not invoked in an interpolation, missing control flow import) through the Vite plugin and expose them as a lint-templates agent tool, registered in config.ts (packages/devtools/src/vite.ts, packages/devtools/src/config.ts).
  • Perf collector: PerformanceObserver for LCP, CLS, INP and long tasks, with long tasks matched to change detection cycles, and findings in the shared { rule, severity, fix } shape, including a missing or $index @for track rule (packages/devtools/src/cd-recorder.ts, packages/devtools/src/rpc/cd-tools.ts).
  • Lazy chunk sizes from the Vite or esbuild metafile, reported per lazy route (packages/devtools/src/vite.ts, packages/devtools/src/rpc/router-config-tools.ts).
  • Let users turn rules off in the devtools config (lint: { rules: { 'missing-title': 'off' } }), applied by every lint tool and documented in apps/docs (packages/devtools/src/config.ts, packages/devtools/src/rpc/forms-lint.ts, packages/devtools/src/rpc/pipe-lint.ts, packages/devtools/src/rpc/router-config-tools.ts).
  • JSON and SARIF export of lint findings for CI, through the CLI (packages/devtools/src/cli.ts).

Already tracked elsewhere


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or shows wrong datafeatureA feature request or a pull request that adds one

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions