Skip to content

feat: add dashboard-aware presentation tools to cve-impact and fleet-inventory skills#131

Open
TomerFi wants to merge 3 commits into
RHEcosystemAppEng:mainfrom
TomerFi:feat/dashboard-aware-skills
Open

feat: add dashboard-aware presentation tools to cve-impact and fleet-inventory skills#131
TomerFi wants to merge 3 commits into
RHEcosystemAppEng:mainfrom
TomerFi:feat/dashboard-aware-skills

Conversation

@TomerFi

@TomerFi TomerFi commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary

  • Add load_cve_dashboard to the cve-impact skill workflow, prerequisites, and dependencies
  • Add load_inventory_dashboard to the fleet-inventory skill workflow, prerequisites, and dependencies
  • Both skills instruct the client to call the respective dashboard presentation tool with collected data after fetching results

These presentation tools are implemented in insights-mcp #389. They detect UI support at runtime — rendering a dashboard on UI-capable clients or falling back to text on others.

For full context on the approach investigation and decision, see APPENG-5287 and the MCP UI Integration Strategy ADR.

Validation

validate_skills_tier1.py (cve-impact)          ✅ passed, 0 warnings
validate_skills_tier1.py (fleet-inventory)     ✅ passed, 0 warnings
validate_skills_tier2.py (cve-impact)          ⚠️ passed with 4 warnings (pre-existing, same on main)
validate_skills_tier2.py (fleet-inventory)     ⚠️ passed with 5 warnings (pre-existing, same on main)
validate_skill_doc_links.py (cve-impact)       ✅ 14 links checked, 0 errors
validate_skill_doc_links.py (fleet-inventory)  ✅ 6 links checked, 0 errors
validate_docs_tree_links.py (cve-impact)       ✅ 104 files scanned, 0 errors
validate_docs_tree_links.py (fleet-inventory)  ✅ 104 files scanned, 0 errors

Recordings

CVE Dashboard (cve-impact):

Fleet Inventory Dashboard (fleet-inventory):

Related tickets

…inventory skills

Signed-off-by: Tomer Figenblat <tfigenbl@redhat.com>
@dmartinol

Copy link
Copy Markdown
Collaborator

[Critical] Text fallback path removed from 01-account-cves.md

The old Step 4 contained the complete text-based result handling:

  • Parse response using references/01-cve-response-parser.py (not jq or inline Python)
  • Sort by CVSS score (highest first) or by affected system count
  • Provide summary table: CVE ID, severity, affected systems count, remediation availability

These instructions are removed entirely by this PR. The new Step 4 instructs the agent to call load_cve_dashboard before parsing or printing anything, and the tool description says "falls back to text if unavailable" — but there is now no guidance on what that text fallback looks like. If load_cve_dashboard fails or the client does not support UI, the agent has nothing to follow.

The removed instructions should be preserved as a fallback branch (e.g. "If dashboard unavailable / falls back to text: …").

@dmartinol

Copy link
Copy Markdown
Collaborator

[Moderate] Asymmetric dashboard coverage across CVE flows

The load_cve_dashboard call is added only to flow 01-account-cves.md (account-level). Flows 02-system-all-cves.md and 03-system-remediatable-cves.md collect the same kind of CVE data but receive no dashboard rendering. The user experience varies depending on which flow the agent enters, with no clear justification for the asymmetry.

@dmartinol

Copy link
Copy Markdown
Collaborator

[Architectural] Consider a dedicated presentation skill

Both skills now call dashboard MCP tools directly. This goes against the repo's core principle: "Skills encapsulate tools — never call MCP tools directly; always invoke skills."

A dedicated render-cve-dashboard / render-inventory-dashboard skill (or a single render-dashboard skill parameterized by type) would:

  • Restore the encapsulation invariant
  • Resolve the asymmetric flow coverage naturally — any flow that collects CVE or host data invokes the skill, coverage is automatic
  • Keep the fallback text logic (parse, sort, summary table) in one place rather than per-flow
  • Allow the remediation skill and any future skill collecting CVE/host data to reuse the same presentation layer

The trade-off is one additional skill file per dashboard type.

@TomerFi

TomerFi commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

[Critical] Text fallback path removed from 01-account-cves.md

The old Step 4 contained the complete text-based result handling:

  • Parse response using references/01-cve-response-parser.py (not jq or inline Python)
  • Sort by CVSS score (highest first) or by affected system count
  • Provide summary table: CVE ID, severity, affected systems count, remediation availability

These instructions are removed entirely by this PR. The new Step 4 instructs the agent to call load_cve_dashboard before parsing or printing anything, and the tool description says "falls back to text if unavailable" — but there is now no guidance on what that text fallback looks like. If load_cve_dashboard fails or the client does not support UI, the agent has nothing to follow.

The removed instructions should be preserved as a fallback branch (e.g. "If dashboard unavailable / falls back to text: …").

@dmartinol The fallback is handled server-side — load_cve_dashboard detects whether the client supports MCP Apps. When UI is supported, the tool returns content instructing the model not to print a table. When it's not, the tool returns content instructing the model to print the full CVE table from its prior get_cves response. The model already has the CVE data in context at that point, so it has everything it needs.

@TomerFi

TomerFi commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

[Moderate] Asymmetric dashboard coverage across CVE flows

The load_cve_dashboard call is added only to flow 01-account-cves.md (account-level). Flows 02-system-all-cves.md and 03-system-remediatable-cves.md collect the same kind of CVE data but receive no dashboard rendering. The user experience varies depending on which flow the agent enters, with no clear justification for the asymmetry.

@dmartinol Good catch — flows 02 and 03 use a different tool (get_system_cves) with pagination and client-side filtering, so adding the dashboard call there isn't as straightforward as flow 01. The data shape and accumulation pattern need to be verified against what the dashboard expects. I'll look into it.

@TomerFi

TomerFi commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

[Architectural] Consider a dedicated presentation skill

Both skills now call dashboard MCP tools directly. This goes against the repo's core principle: "Skills encapsulate tools — never call MCP tools directly; always invoke skills."

A dedicated render-cve-dashboard / render-inventory-dashboard skill (or a single render-dashboard skill parameterized by type) would:

  • Restore the encapsulation invariant
  • Resolve the asymmetric flow coverage naturally — any flow that collects CVE or host data invokes the skill, coverage is automatic
  • Keep the fallback text logic (parse, sort, summary table) in one place rather than per-flow
  • Allow the remediation skill and any future skill collecting CVE/host data to reuse the same presentation layer

The trade-off is one additional skill file per dashboard type.

@dmartinol The cve-impact skill already calls MCP tools directly — get_cves, get_cve_details, etc. That's what skills do: they orchestrate tool calls. The "never call MCP tools directly" rule means the agent shouldn't bypass skills to call tools on its own, not that skills can't call tools. load_cve_dashboard is just another tool call within the skill's workflow.

…ashboard support to flows 02 and 03

Signed-off-by: Tomer Figenblat <tfigenbl@redhat.com>
@TomerFi

TomerFi commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

Pushed a new commit: feat: update skills for client-side dashboard data fetching and add dashboard support to flows 02 and 03

  • All three CVE flows and fleet inventory now use the client-side dashboard approach
  • Dashboard is called before the data fetch so the model receives the dashboard's instructions before having data in context
  • Flows 02 (system-level) and 03 (remediatable) now have dashboard support
  • For context on why we moved to client-side fetching, see the insights-mcp team discussion

Recordings with skills on Cursor:

@TomerFi
TomerFi marked this pull request as ready for review July 17, 2026 21:50
@TomerFi
TomerFi requested a review from r2dedios as a code owner July 17, 2026 21:50
**Scope**: devices=all (account-wide) | severities=all, most critical, or selected | remediation=available or does not matter

**Tool**: `vulnerability__get_cves` (single request; no offset pagination in API)
**Tools**: `vulnerability__get_cves` fetcing the data for analysis and `vulnerability__load_cve_dashboard` displaying an interactive dashboard

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

typo in "fetcing"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

- `limit`: From HITL (default 20)


**Before** continuing further, invoke the dashbaord tool to initaite the dashbaord, and examin the instruction returning from the tool.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

typo in "initaite"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@dmartinol

Copy link
Copy Markdown
Collaborator

Code review

Found 3 issues:

  1. Misspelled tool name in code example — the second example block uses vulnerability__load_cve_dashbaord (letters transposed) instead of vulnerability__load_cve_dashboard. An AI agent following this example verbatim will invoke a non-existent MCP tool and fail at runtime.

**Example** (all severities, remediation doesn't matter):
```
vulnerability__load_cve_dashbaord(
impact="7,6,5,4",
sort="-cvss_score",
limit=20,
advisory_available="true,false"
)
```

  1. Same typo propagated into the CRITICAL constraint note in flow 03 — the CRITICAL block was extended with the sentence load_cve_dashbaord takes a string advisory_available, misspelling the tool name in the highest-attention guidance section of the file.

**CRITICAL**: `get_system_cves` does NOT support `advisory_available` as a request parameter. We must paginate through ALL CVEs and filter client-side for `attributes.advisory_available === true`. `load_cve_dashbaord` takes a string `advisory_available`. Do NOT use `get_cves` + `get_cve_systems` per CVE—does not scale.

  1. advisory_available placed in the shared parameters table, contradicting the CRITICAL note in the same file — the PR adds advisory_available: "true" - Only exist in load_cve_dashboard to the Step 4 parameters block shared by both vulnerability__load_cve_dashboard and vulnerability__get_system_cves. The existing CRITICAL note explicitly states "get_system_cves does NOT support advisory_available as a request parameter." Listing it in the shared block — even with an inline qualifier — creates the exact ambiguity the CRITICAL note was written to prevent; a model scanning the parameters list may still pass it to get_system_cves, silently returning unfiltered CVEs.

**Tools**: `vulnerability__load_cve_dashboard` and `vulnerability__get_system_cves` (from lightspeed-mcp)
**Parameters**:
- `system_uuid`: Required (from Step 2)
- `limit`: `100`
- `offset`: `0`, `100`, `200`, ... per pagination strategy
- `advisory_available`: `"true"` - Only exist in `load_cve_dashboard`
**Before** continuing further, invoke the dashbaord tool to initaite the dashbaord, and examin the instruction returning from the tool:
```
vulnerability__load_cve_dashboard(system_uuid="<resolved-uuid>", limit=100, advisory_available="true")
```
**After** the dashbaord is loaded, get the raw data for further analysis.


Please run make validate (or at minimum make validate-mcp-tools) before merging — the validate_mcp_tools.py script checks that every tool name referenced in allowed-tools and flow files resolves against the live MCP server, which would catch the typos above automatically.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

Fix spelling errors in dashboard-related flow files and fleet-inventory
SKILL.md: dashbaord→dashboard, fetcing→fetching, initaite→initiate,
examin→examine, succesful→successful, and load_cve_dashbaord tool name.

Signed-off-by: Tomer Figenblat <tfigenbl@redhat.com>
@TomerFi

TomerFi commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

Hey @dmartinol (or dmartinol's claude ;-) ).

Regarding issues 1 and 2 (typos):

An AI agent following this example verbatim will invoke a non-existent MCP tool and fail at runtime.

First, let me ease your mind — there's not a single LLM that won't be able to interpret "dashboard" from "dashbaord", especially when the tool itself is correctly named in allowed-tools and in the tool spec as exposed by the MCP server. That said, thank you — that was a great catch! Maybe it's worth adding a spelling check as a tool configured in this project and/or as a CI step. This project is mostly markdown — typos are bound to happen.

All typos were fixed in 04bbce5.

Regarding issue 3 (advisory_available in the parameters table):

a model scanning the parameters list may still pass it to get_system_cves, silently returning unfiltered CVEs.

I don't necessarily agree. As you noted yourself, I've added:

advisory_available: "true" - Only exist in load_cve_dashboard

Which clearly states advisory_available is only applicable to load_cve_dashboard. The CRITICAL note you're referring to explains to the agent that it needs to filter advisory_available CVEs client-side after fetching data from get_system_cves. On top of that, the tool spec as exposed by the MCP server doesn't include advisory_available as an argument for get_system_cves — so I sincerely doubt that adding advisory_available: "true" - Only exist in load_cve_dashboard to a section that exemplifies both get_system_cves and load_cve_dashboard will cause the agent to push advisory_available to get_system_cves.

That said, if it would make you feel comfortable, we can beef the instruction up, something like:

advisory_available: "true" - ONLY exist in load_cve_dashboard, DO NOT use with get_system_cves

What do you think?

Regarding "Please run make validate":

Please run make validate (or at minimum make validate-mcp-tools) before merging — the validate_mcp_tools.py script checks that every tool name referenced in allowed-tools and flow files resolves against the live MCP server, which would catch the typos above automatically.

A few things here:

  1. The implication that I pushed a PR without running make validate doesn't make a lot of sense, since I stated the validation results in the PR description. I'd appreciate a bit of credit, thanks.

  2. You are wrong — make validate does not catch these typos. The validate_mcp_tools.py script only checks tool names declared in the allowed-tools frontmatter of SKILL.md files. It does not scan flow files, markdown body content, or code examples. The allowed-tools entries are all correctly spelled, so the validator passes with flying colors. You can verify this yourself by reading the script — specifically parse_frontmatter() which only extracts the allowed-tools: line from YAML frontmatter.

  3. Furthermore, validate_mcp_tools.py quietly reports most of its issues as warnings and still exits 0. Similarly, make validate exits 0 for many errors, reporting them as warnings in a very long output that requires analysis. This cannot be considered a gate for PRs in its current form.


Generated by @TomerFi with the help of AI tools to make sure this message is grammatically correct and delivers the idea.

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.

2 participants