Skip to content

[meta] Updating @kbn/docs-utils, add MCP tools#247688

Draft
clintandrewhall wants to merge 8 commits intomainfrom
feat/kbn-docs-utils
Draft

[meta] Updating @kbn/docs-utils, add MCP tools#247688
clintandrewhall wants to merge 8 commits intomainfrom
feat/kbn-docs-utils

Conversation

@clintandrewhall
Copy link
Copy Markdown
Contributor

@clintandrewhall clintandrewhall commented Dec 31, 2025

Improve @kbn/docs-utils validation, testing, and MCP tooling

Summary

The kbn-docs-utils package builds API documentation from TypeScript source code using ts-morph, and gathers statistics for CI and APM on inline code documentation. The statistics functionality currently checks for three main things:

  1. Missing comments
  2. Use of any in TypeScript code
  3. Missing exports (e.g. types that are used externally but not exported explicitly)

This PR delivers significant improvements to the @kbn/docs-utils package, including new and planned functionality, bug fixes, test coverage, performance optimizations, and more. It also splits the --stats functionality into its own CLI, making it easier for developers and agents to ensure all code is fully documented before a PR is created.

The work follows a phased approach documented in PLAN.md, delivering improved test coverage, modular CLI architecture, enhanced JSDoc validation, performance improvements for single-package builds, and new MCP tooling for AI-assisted documentation remediation.

Note

These commits and PR are based on a feature branch containing several "Phases" of code that will be submitted as separate PRs for ease of review.

This PR was written using Cursor and claude-4.5-opus-high

Tip

#247774 is a test run of this branch against the dashboard plugin.

Status

These are the PRs that have been extracted from this meta PR. Drafts will be marked as ready for review as their predecessors allow:

New Features

Dedicated check_package_docs CLI

A new standalone CLI for validation-only workflows, separate from documentation generation:

node scripts/check_package_docs --plugin|package <id> --check <any|comments|exports|all>

This new CLI enables a faster feedback loop for developers focused on documentation quality, and for AI Agents to raise (and fix) issues before a PR is created.

New Validation Rules

  • @returns tag validation — Detects missing return documentation on non-void functions
  • Parameter count mismatch detection — Flags when JSDoc @param count doesn't match function signature
  • Complex type documentation checks — Validates that object/interface types have adequate descriptions
  • Unnamed exports detection — Identifies exports without proper names that may cause documentation gaps
  • Multiple call signature validation — Improved handling of overloaded function signatures

Flat Stats JSON Output

New --write flag emits machine-readable validation stats for CI and AI integration:

node scripts/check_package_docs --plugin|package <id> --write
  • Writes to <plugin|package>/target/api_docs/stats.json
  • Includes line-anchored GitHub URLs for direct navigation
  • Enables tracking documentation health metrics over time

MCP Tools for AI-Assisted Documentation

Two new MCP tools registered in kbn-mcp-dev-server:

  • check_package_docs — Quick pass/fail validation with actionable vs. pending issue counts
  • fix_package_docs — Detailed issue reporting with source context and mechanical fix templates for agent-assisted remediation

Performance Improvements for Single-Package Builds

Significant performance optimizations for building or validating individual plugins:

  • Selective source file loading — Single-plugin builds now load only source files from the target plugin directory, skipping resolveSourceFileDependencies() for faster initialization
  • Skip aggregate docs — Filtered builds skip plugin directory and deprecation summary generation (these require complete data from all plugins)
  • Preserved cross-references — External plugin references are kept as-is when the target plugin isn't loaded, allowing single-package builds without loading all plugins into memory

Key Improvements

Dramatically Expanded Test Coverage (Phases 1–2)

  • Added comprehensive unit tests for previously untested modules:
    • js_doc_utils.test.ts — JSDoc parsing tests
    • build_api_declaration.test.ts — replacing the minimal original
    • Task-level tests for all CLI modules (setup_project, build_api_map, collect_stats, write_docs, report_metrics)
    • CLI flag parsing tests covering edge cases and validation
  • Enhanced integration tests with fixture validation and expected issue snapshots

Modular CLI Architecture (Phases 2–3)

  • Refactored monolithic build_api_docs_cli.ts into discrete, testable tasks under src/cli/tasks/
  • Created dedicated check_package_docs CLI separating validation from doc generation
  • Improved developer experience with clearer command separation:
    • node scripts/build_api_docs for documentation generation
    • node scripts/check_package_docs for validation-only workflows
  • Added deprecation handling for --stats flag with automatic routing to new CLI

Enhanced Validation and Bug Fixes (Phase 4)

Phase 4 focused on fixing validation bugs and adding new validation rules:

  • Phase 4.1 — Fixed destructured parameter JSDoc handling to support dot-notation (@param options.name)
  • Phase 4.2 — Normalized ReactElement signatures to strip noisy second generic parameter
  • Phase 4.3 — Improved missing comments detection to account for property-level JSDoc tags
  • Phase 4.4 — Added @returns tag validation for non-void functions
  • Phase 4.5 — Improved multiple call signature validation for overloaded functions
  • Phase 4.6 — Added unnamed exports validator to detect exports without proper names

Documentation and Developer Experience (Phase 5)

  • Updated README.md with comprehensive CLI usage documentation
  • Improved CLI output formatting and messaging
  • Added JSDoc examples for destructured parameters following the JSDoc specification
  • Final testing and validation across real plugins

Flat Stats and MCP Tooling (Phase 6)

  • Phase 6.1 — Added --write flag to emit flat stats.json per plugin with:
    • Counts and detailed entries for all validation issues
    • Line-anchored GitHub URLs for direct navigation
    • Machine-readable format for CI integration
  • Phase 6.2 — Created MCP tools for AI-assisted documentation:
    • check_package_docs for quick pass/fail status
    • fix_package_docs for detailed issues with source context and fix templates

Optimized Single-Package Workflows (Phase 7)

  • TypeScript project loading optimized for single-plugin operations
  • Aggregate documentation generation skipped for filtered builds
  • Cross-reference resolution preserves links to unloaded plugins

Bugs Fixed

Destructured Parameter JSDoc Handling

Problem: The system only matched exact parameter names when extracting JSDoc comments. Property-level tags using dot notation (@param options.name) were not recognized, causing false positives for "missing comments" on destructured parameter children.

Fix: Updated getJSDocParamComment in js_doc_utils.ts to support dot-notation property tags per the JSDoc specification. The system now correctly parses nested property access patterns like @param obj.nested.prop.

Missing Property-Level Validation

Problem: When a parameter was an object type, children were created for each property, but validation didn't account for parent parameters having comments or property-level JSDoc tags.

Fix: Updated buildApiDecsForParameters to pass JSDoc context through to child properties. Validation now only flags missing comments if both the parent parameter AND property-level tags are absent.

ReactElement Signature Noise

Problem: ReactElement types included a noisy second generic parameter in their signatures, making the output cluttered and harder to read.

Fix: Normalized ReactElement signatures in get_signature.ts to strip the second generic, restoring clean and expected output. Unskipped the previously failing Test ReactElement signature test.

Inconsistent JSDoc Detection

Problem: The system used exact string matching for JSDoc parameter names, missing variations and edge cases.

Fix: Enhanced js_doc_utils.ts with comprehensive parsing logic and added 380+ lines of unit tests covering edge cases.

Breaking Changes

None. The --stats flag on build_api_docs remains functional but emits a deprecation warning and routes to the new check_package_docs CLI.

Testing

  • All new code includes unit tests
  • Integration tests updated with fixture expectations
  • MCP tools tested against real packages (@kbn/docs-utils, @kbn/content-management-content-editor)
  • Performance improvements tested with single-plugin builds

Closes

  • #107145 — Optional function on interface includes children
  • #120125 — ReactElement signature noise

@clintandrewhall clintandrewhall requested a review from a team December 31, 2025 15:00
@clintandrewhall clintandrewhall requested review from a team as code owners December 31, 2025 15:00
@clintandrewhall clintandrewhall added WIP Work in progress release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting v9.4.0 labels Dec 31, 2025
@clintandrewhall clintandrewhall force-pushed the feat/kbn-docs-utils branch 2 times, most recently from bcef48e to e4b7800 Compare January 2, 2026 03:23
@clintandrewhall clintandrewhall force-pushed the feat/kbn-docs-utils branch 4 times, most recently from 6fe6e96 to 5c57d1f Compare January 2, 2026 17:14
@clintandrewhall clintandrewhall marked this pull request as draft January 2, 2026 17:15
@elasticmachine
Copy link
Copy Markdown
Contributor

elasticmachine commented Jan 2, 2026

🤖 Jobs for this PR can be triggered through checkboxes. 🚧

ℹ️ To trigger the CI, please tick the checkbox below 👇

  • Click to trigger kibana-pull-request for this PR!
  • Click to trigger kibana-deploy-project-from-pr for this PR!
  • Click to trigger kibana-deploy-cloud-from-pr for this PR!
  • Click to trigger kibana-entity-store-performance-from-pr for this PR!

@clintandrewhall clintandrewhall force-pushed the feat/kbn-docs-utils branch 4 times, most recently from 5b4eb3e to e7276f5 Compare January 4, 2026 18:48
@clintandrewhall clintandrewhall force-pushed the feat/kbn-docs-utils branch 3 times, most recently from cd6cdf4 to 263ccfd Compare January 5, 2026 03:38
@elasticmachine
Copy link
Copy Markdown
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

The CI Stats report is too large to be displayed here, check out the CI build annotation for this information.

History

@clintandrewhall clintandrewhall changed the title [feat] Updating @kbn/docs-utils, add MCP tools [meta] Updating @kbn/docs-utils, add MCP tools Jan 23, 2026
- Update collectStatsForApi to check for parent or property-level comments.
- Don't flag as missing if property-level JSDoc exists.
- Add validation for required vs optional parameter documentation.
- Handle interfaces with multiple call signatures.
- Extract parameter documentation from first overload signature.
- Add test cases for overloaded functions.
- Add UnnamedExport type.
- Extend IssuesByPlugin with optional unnamedExports field.
- Update getDeclarationNodesForPluginScope to detect unnamed exports.
- Update getPluginApi to propagate unnamed exports.
- Add --check unnamed CLI flag.
- Add tests for unnamed export detection.
- Improve getLink to use line numbers when available.
- Add printIssueTable helper for consistent output formatting.
- Add printMissingExportsTable helper for missing exports output.
- Refactor existing console output to use helper functions.
clintandrewhall and others added 4 commits February 10, 2026 21:45
- Add --write CLI flag to check_package_docs to emit validation stats as flat JSON.
- Write stats to each plugin's target/api_docs/stats.json.
- Include line-anchored GitHub URLs when line numbers are present.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Create check_package_docs MCP tool for quick validation checks.
- Create fix_package_docs MCP tool for detailed issue reporting with code snippets.
- Both tools registered in kbn-mcp-dev-server.
- Add usage docs and basic tests for the MCP tools.
- Optimize TypeScript project loading for single-plugin builds.
- Add allPlugins to SetupProjectResult for cross-reference resolution.
- Skip aggregate docs for filtered builds.
- Update removeBrokenLinksFromApi to handle cross-package links.
- Update tests for single-plugin project scoping.
- Add APM metrics for missingReturns count.
- Add APM metrics for paramDocMismatches count.
- Add APM metrics for missingComplexTypeInfo count.
- Update passesAllChecks logic to include new fields.
- Add CLI output for new validation fields under comments option.

Co-authored-by: Cursor <cursoragent@cursor.com>
mistic added a commit that referenced this pull request Feb 23, 2026
## Summary

Improves the `missingComments` detection in `kbn-docs-utils` to avoid
false positives on destructured parameter nodes. Previously, a parameter
like `obj` in `crazyFunction(obj: {hi: string})` was flagged as missing
a comment even when its children (`obj.hi`) were individually documented
via JSDoc.

> [!NOTE]
> This PR is a subset of #247688
for ease of review.
>
> This PR was written with Cursor and `claude-4.5-opus-high`.

### Before / After Example

Given this JSDoc-annotated function:

```typescript
/**
 * Who would write such a complicated function?? Ewwww.
 *
 * @param {Object} obj A very crazy parameter.
 * @param {string} obj.hi Greeting on the obj.
 */
export const crazyFunction = (
  obj: { hi: string },
) => { /* ... */ };
```

**Before this PR:**

The `obj` parameter node was flagged as "missing a comment" even though
its child `obj.hi` had a description extracted from `@param obj.hi`:

```json
{
  "missingComments": [
    { "id": "def-public.crazyFunction.$1", "label": "obj" }
  ]
}
// obj flagged even though its children are documented!
```

**After this PR:**

Parameter nodes (identified by `.$` in their `id`) are no longer flagged
when at least one child has a description:

```json
{
  "missingComments": []
}
// obj NOT flagged — child obj.hi has a description ✅
```

### Detection Logic

| Scenario | Flagged? | Reason |
|----------|----------|--------|
| No description, no children with descriptions | Yes | Genuinely
undocumented |
| No description, but child has description | **No** | Parent is
implicitly documented via children |
| Has own description | No | Directly documented |
| Non-parameter node without description | Yes | Not a parameter, normal
rules apply |

### Changes

- Refactor `missingComment` logic in `collectStatsForApi()` in
`stats.ts` to check for child descriptions on parameter nodes
- Un-skip the `does not flag destructured params when @param obj exists`
test
- Simplify the `does not flag destructured parameter children when
documented` test to assert the correct behavior directly

### Impact

- Reduces false positives in `missingComments` for plugins with
well-documented destructured parameters

Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Tiago Costa <tiago.costa@elastic.co>
bhapas pushed a commit to bhapas/kibana that referenced this pull request Feb 25, 2026
## Summary

Improves the `missingComments` detection in `kbn-docs-utils` to avoid
false positives on destructured parameter nodes. Previously, a parameter
like `obj` in `crazyFunction(obj: {hi: string})` was flagged as missing
a comment even when its children (`obj.hi`) were individually documented
via JSDoc.

> [!NOTE]
> This PR is a subset of elastic#247688
for ease of review.
>
> This PR was written with Cursor and `claude-4.5-opus-high`.

### Before / After Example

Given this JSDoc-annotated function:

```typescript
/**
 * Who would write such a complicated function?? Ewwww.
 *
 * @param {Object} obj A very crazy parameter.
 * @param {string} obj.hi Greeting on the obj.
 */
export const crazyFunction = (
  obj: { hi: string },
) => { /* ... */ };
```

**Before this PR:**

The `obj` parameter node was flagged as "missing a comment" even though
its child `obj.hi` had a description extracted from `@param obj.hi`:

```json
{
  "missingComments": [
    { "id": "def-public.crazyFunction.$1", "label": "obj" }
  ]
}
// obj flagged even though its children are documented!
```

**After this PR:**

Parameter nodes (identified by `.$` in their `id`) are no longer flagged
when at least one child has a description:

```json
{
  "missingComments": []
}
// obj NOT flagged — child obj.hi has a description ✅
```

### Detection Logic

| Scenario | Flagged? | Reason |
|----------|----------|--------|
| No description, no children with descriptions | Yes | Genuinely
undocumented |
| No description, but child has description | **No** | Parent is
implicitly documented via children |
| Has own description | No | Directly documented |
| Non-parameter node without description | Yes | Not a parameter, normal
rules apply |

### Changes

- Refactor `missingComment` logic in `collectStatsForApi()` in
`stats.ts` to check for child descriptions on parameter nodes
- Un-skip the `does not flag destructured params when @param obj exists`
test
- Simplify the `does not flag destructured parameter children when
documented` test to assert the correct behavior directly

### Impact

- Reduces false positives in `missingComments` for plugins with
well-documented destructured parameters

Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Tiago Costa <tiago.costa@elastic.co>
qn895 pushed a commit to qn895/kibana that referenced this pull request Mar 11, 2026
## Summary

Improves the `missingComments` detection in `kbn-docs-utils` to avoid
false positives on destructured parameter nodes. Previously, a parameter
like `obj` in `crazyFunction(obj: {hi: string})` was flagged as missing
a comment even when its children (`obj.hi`) were individually documented
via JSDoc.

> [!NOTE]
> This PR is a subset of elastic#247688
for ease of review.
>
> This PR was written with Cursor and `claude-4.5-opus-high`.

### Before / After Example

Given this JSDoc-annotated function:

```typescript
/**
 * Who would write such a complicated function?? Ewwww.
 *
 * @param {Object} obj A very crazy parameter.
 * @param {string} obj.hi Greeting on the obj.
 */
export const crazyFunction = (
  obj: { hi: string },
) => { /* ... */ };
```

**Before this PR:**

The `obj` parameter node was flagged as "missing a comment" even though
its child `obj.hi` had a description extracted from `@param obj.hi`:

```json
{
  "missingComments": [
    { "id": "def-public.crazyFunction.$1", "label": "obj" }
  ]
}
// obj flagged even though its children are documented!
```

**After this PR:**

Parameter nodes (identified by `.$` in their `id`) are no longer flagged
when at least one child has a description:

```json
{
  "missingComments": []
}
// obj NOT flagged — child obj.hi has a description ✅
```

### Detection Logic

| Scenario | Flagged? | Reason |
|----------|----------|--------|
| No description, no children with descriptions | Yes | Genuinely
undocumented |
| No description, but child has description | **No** | Parent is
implicitly documented via children |
| Has own description | No | Directly documented |
| Non-parameter node without description | Yes | Not a parameter, normal
rules apply |

### Changes

- Refactor `missingComment` logic in `collectStatsForApi()` in
`stats.ts` to check for child descriptions on parameter nodes
- Un-skip the `does not flag destructured params when @param obj exists`
test
- Simplify the `does not flag destructured parameter children when
documented` test to assert the correct behavior directly

### Impact

- Reduces false positives in `missingComments` for plugins with
well-documented destructured parameters

Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Tiago Costa <tiago.costa@elastic.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:skip Skip the PR/issue when compiling release notes v9.4.0 WIP Work in progress

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants