Repository navigation
AAP-99339/AAP-99340: Serve AAP skills over MCP per SEP-2640 - #209
Conversation
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Codecov Report❌ Patch coverage is
@@ Coverage Diff @@
## main #209 +/- ##
==========================================
+ Coverage 85.25% 85.50% +0.24%
==========================================
Files 14 16 +2
Lines 1031 1097 +66
Branches 260 284 +24
==========================================
+ Hits 879 938 +59
- Misses 86 88 +2
- Partials 66 71 +5
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Review: AAP-99339 / AAP-99340 — Serve AAP skills over MCP per SEP-2640Approve with changes. The SDK adoption is correct and the conformance claims hold up under independent verification against a live platform. One startup failure mode should be fixed before merge. How I tested thisI built the branch in a clean worktree and exercised it three ways: against a mock AAP backend, against fixture trees designed to break the loader, and against a real AAP instance (gateway 4.8.12, 579 tools) serving the actual Build and suite — Protocol conformance, live instance — The strongest evidence is third-party rather than mine — MCP Inspector's conformance checker against the live server: The open questions in AAP-99339 both resolve cleanly. On derived URIs (R4), I read the SDK source rather than trusting the tests: Failure modes — I built fixture trees mixing good and bad skills. The skip-versus-warn distinction the PR introduces works exactly as described: The server stayed up with its tools intact, and the PR's headline finding — that exceeding the SEP-2640 limits warns rather than skips — reproduces precisely. Reporting those under separate headings is the right call and the log is genuinely useful to an operator. Security — eight traversal and escape vectors ( Off by default — with AAP-99340's wire requirements — The skill actually works — I ran the health-check skill's procedure against the live platform. All of its declared tools returned real data: Finding 1 — an unreadable
|
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
46d7d4c to
acb7c3c
Compare
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Final Review — All findings addressedApproved. All three findings from my previous review have been resolved, plus additional quality improvements. What changed since my reviewFive commits addressing the feedback:
What I verifiedTest suite — 451/452 tests pass (up from 437/438). The 14 new tests all pass:
The one failing test is the same pre-existing OAuth backoff timing flake, unrelated to this PR. Live instance verification — booted against the real AAP gateway (4.8.12, 579 tools):
Finding 3 (minor nits) — not explicitly addressed but acceptable:
Code quality observationsThe refactoring work goes beyond addressing the findings:
The degradation behavior is exactly what I recommended and documented in the README. A build regression in the optional skills layer no longer takes down the whole server. No further review needed. Ready to merge. |
Serves the AAP platform skills over the MCP skills extension (SEP-2640), and makes them findable by clients that have not implemented the extension.
Covers AAP-99339 (serve skills on the SDK) and AAP-99340 (make them findable without the extension), both under AAP-99338.
Skills are off by default. With
skills_pathunset the extension is not advertised,skills/listandskills/getare not registered, and the server behaves exactly as it does today.What changed
@modelcontextprotocol/server^2.0.0→^2.4.0, the first release carrying SEP-2640 (#3047, #3080)src/index.tsattach()per request-built server, pinresources.listChanged, report the catalog at startupsrc/skills-instructions.tssrc/skills-catalog.test.tstests/e2e-skills.test.tsskills_path,skills_uri_prefix,skills_instructions+ env equivalents, documented inaap-mcp.sample.yamlandREADME.mdThe first commit is the SDK bump alone, with no source changes, so it can be confirmed inert independently.
Discovery: why the instructions pointer
The protocol mechanics come from the SDK. The piece it leaves to the server is the second discovery mechanism SEP-2640 defines alongside
skills/list:That is load-bearing, not a nicety. Measured on a cold client session, single prompt "is my AAP platform healthy?", against a server serving a skill whose trigger conditions contain that question near-verbatim:
resources/readIn the unadvertised arm the client answered "everything reports healthy" on a platform with a failing inventory source.
instructionsis base protocol (since 2024-11-05), so it reaches clients that have implemented nothing beyond core MCP, and costs notools/listentry. On by default;skills_instructions: "off"leaves only the SEP-2640 methods.The pointer also tells a model how to address a skill's supporting files, fixing a measured failure where it synthesized
skill://aap/context/output-format.md— dropping the skill segment — for a file it had been told to read (AAP-99041).Two findings worth a reviewer's attention
Exceeding the SEP-2640 limits does not skip a skill. A 600-file skill loads, serves all 601 resources, and warns "some hosts may decline it" — so it works here and is refused at a conforming host instead. Our startup log previously printed every loader warning under
SKIPPED and NOT served, describing such a skill as absent while it was being served.SkillWarningcarries no severity, so skips are now distinguished structurally — by whether the skill reached the catalog — and printed under separate headings.Containment at catalog-build time is structural, not a check.
catalogBuildenumerates a walked tree and assigns files to skills by path prefix; no path is built from untrusted input, so there is nothing to traverse before the read path. The only way to pull in content from outside the tree is a symlink, which the loader refuses outright — any symlink, including one pointing at a sibling inside the same skill, drops the whole skill. That answers the open question on AAP-99339, and is why shared content must be copied into a skill rather than linked.Testing
438 tests across 23 files, build, lint and Prettier clean.
skills/listandskills/getshapes, digest and size agreement, frontmatter fidelity after re-parse, four path-traversal vectors refused, tools still served alongsideThe byte-limit test lowers
limits.bytesrather than writing 16 MiB on every run — same code path, no cost.Verified separately against the real
ansible/aap-skillstree atorigin/main: all three skills load with zero warnings.Not in scope
RBAC-aware filtering (ANSTRAT-2298), OCI distribution, skill content itself (AAP-99040), product documentation (AAP-95462), and the administrative on/off switch (AAP-99341) — this PR reads
skills_pathdirectly and does not add the operator-facing toggle that story defines.Supersedes
feature/skills-instructionsandmabashian/ANSTRAT-2420/skills-shim-poc, both carrying earlier versions of this work against a hand-rolled loader now replaced by the SDK.🤖 Generated with Claude Code