ci: add MCP tool name validation against live servers#95
Conversation
Adds a CI check that starts each pack's MCP servers (from mcps.json) and cross-references the `allowed-tools` declared in SKILL.md frontmatter against the actual tools exposed by the server. This catches tool name mismatches (e.g., pod_list vs pods_list) that would silently break skills at runtime but pass all static linters. Components: - scripts/validate-mcp-tools.sh: bash script that starts container- based MCP servers via podman, sends JSON-RPC initialize + tools/list, and validates each skill's allowed-tools against the response - .github/workflows/mcp-tool-validation.yml: GitHub Actions workflow using Kind cluster + podman, triggers on changes to mcps.json or SKILL.md files Co-authored-by: Cursor <cursoragent@cursor.com>
Replace bash script with a pure-Python implementation for cross-OS portability. Key improvements: - Response-based MCP communication via subprocess + select (no sleeps) - Explicit image pulling with error handling - JSON-RPC pagination support (follows nextCursor) - Levenshtein-based "did you mean?" suggestions for mismatched tools - Graceful handling of servers that exit immediately (missing creds) - File path and line number in error output - Logging of skipped non-container MCP servers Workflow hardening: - Pin all GitHub Actions to SHA - Add permissions: contents: read - Add concurrency group with cancel-in-progress - Add timeout-minutes: 10 - Explicit KUBECONFIG capture from Kind - Add workflow_dispatch pack input for manual runs - Inline pack detection (remove dependency on detect-changed-packs.sh) Co-authored-by: Cursor <cursoragent@cursor.com>
|
Hey @jordigilh thanks for your contribution to proactively catch these mismtaches! Apart from that, 2 comments on this awesome PR: |
|
Thanks @dmartinol — totally understand the post-Summit freeze. No rush on merging this one. On your two suggestions:
Happy to iterate on both after Summit. Let me know if there's anything else you'd like adjusted in the meantime. |
Thanks for being available to extend this solution! And yes, we'll also extend the coverage of |
There was a problem hiding this comment.
pls also add this step under the validate make target
There was a problem hiding this comment.
Done in 527a2f7. Here's what this commit adds:
-
validate_mcp_tools.pyadded to the mainvalidatetarget — runs automatically withmake validate. -
Graceful prerequisite skip — the script checks for
podmanon PATH and a validKUBECONFIGat startup. If either is missing it prints aSKIP:message and exits 0, somake validate(and thecompliance-checkCI workflow that calls it) never breaks in environments without container tooling. -
Standalone
validate-mcp-toolstarget — for running the check in isolation, with optionalPACK=filter:make validate-mcp-tools PACK=rh-developer. -
Improved suggestions — alongside Levenshtein distance, the suggestion engine now uses substring/prefix matching and component overlap (e.g.
pods-list→pods_list) to catch more mismatches.
|
@dmartinol @r2dedios Thanks for the feedback on integrating this into the Option A: Add it to The script would detect missing prerequisites (no podman, no KUBECONFIG) and exit 0 with a warning instead of failing. This keeps
Option B: Standalone target + keep workflows separate Add
I'm leaning toward Option B since MCP validation is fundamentally a runtime check (starts containers, JSON-RPC handshake) while the other validate steps are static. But happy to go with either — what's your preference? |
Hey @jordigilh, good catch! BTW: other tools we should be considering are the CLI tools that are sometimes referred in the |
- Add validate_mcp_tools.py to the main `validate` Makefile target - Add standalone `validate-mcp-tools` target with PACK= filter support - Add graceful prerequisite detection: script exits 0 with a SKIP message when podman or KUBECONFIG is unavailable, so `make validate` never breaks in environments without container tooling - Improve tool name suggestions with substring/prefix matching and component overlap scoring alongside the existing Levenshtein distance Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
mcps.json) via podman and cross-references theallowed-toolsdeclared inSKILL.mdfrontmatter against the actual tools exposed by the serverpod_listvspods_list) that pass all static linters but silently break skills at runtimeMotivation
While working on PRs #79 and #80, we discovered 6 tool name mismatches between our SKILL.md declarations and the actual MCP server tool registry. These went undetected by the existing
skill-linterandcompliance-checkbecause they only validate static structure, not runtime tool availability.pod_listpods_listpod_logspods_logget_metric_namesget_metric_metadataget_seriesqueryprometheus_queryComponents
scripts/validate-mcp-tools.sh— Starts container-based MCP servers via podman, sends JSON-RPCinitialize+tools/list, and validates each skill'sallowed-tools.github/workflows/mcp-tool-validation.yml— GitHub Actions workflow using Kind cluster + podman, triggers on changes tomcps.jsonorSKILL.mdfilesTest plan
rh-developerpack — correctly detected 6 mismatches inincident-triage(pre-fix) and passeddebug-scc/debug-rbac(post-fix)Made with Cursor