Skip to content

Add experimental MCP skills extension support (SEP-2640)#207

Open
jancurn wants to merge 4 commits intomainfrom
claude/implement-mcp-skills-lYFVi
Open

Add experimental MCP skills extension support (SEP-2640)#207
jancurn wants to merge 4 commits intomainfrom
claude/implement-mcp-skills-lYFVi

Conversation

@jancurn
Copy link
Copy Markdown
Member

@jancurn jancurn commented Apr 28, 2026

Summary

Implements support for the experimental MCP skills extension (io.modelcontextprotocol/skills, SEP-2640), adding two new CLI commands (skills-list and skills-get) that provide sugar over the existing resources primitive for discovering and reading Agent Skills.

Key Changes

  • New skills command module (src/cli/commands/skills.ts):

    • Implements skill discovery via skill://index.json with fallback to resource scanning for skill://*/SKILL.md URIs
    • listSkills(): Discovers and lists skills exposed by the server
    • getSkill(): Reads a skill's SKILL.md content by name or URI
    • resolveSkillUri(): Converts user-friendly skill names to full skill:// URIs
    • Includes parsing and validation logic for the skills index format
  • CLI integration (src/cli/index.ts):

    • Added skills-list command with discovery strategy documentation
    • Added skills-get <name> command with --raw flag for markdown-only output
    • Registered commands in parser's KNOWN_SESSION_COMMANDS
  • Output formatting (src/cli/output.ts):

    • formatSkills(): Renders skill list with names, descriptions, and types
    • formatSkillDetail(): Displays skill content with URI and MIME type metadata
    • Updated formatServerDetails() to advertise skills capability when server declares the extension
  • Documentation:

    • Updated README.md and CHANGELOG.md with new commands
    • Comprehensive help text explaining skill discovery, URI forms, and --raw mode

Implementation Details

  • Skills are discovered using a two-tier strategy: first attempts the well-known skill://index.json index; if unavailable, falls back to scanning all resources for skill://**/SKILL.md patterns (per spec requirement to not treat absent index as proof of no skills)
  • Skill name resolution supports bare names (git-workflow), nested paths (acme/billing/refunds), and full URIs
  • Graceful error handling: malformed index entries are silently dropped; missing index triggers fallback rather than failure
  • Output modes support both human-readable formatting and JSON for programmatic use
  • --raw flag enables piping skill markdown directly to other tools without formatting overhead

https://claude.ai/code/session_01PyzCAbMiMXTbLrFXUP3nQJ

claude added 4 commits April 28, 2026 22:33
Implements the experimental `io.modelcontextprotocol/skills` extension as
sugar over the existing Resources primitive. Skills are markdown documents
(SKILL.md + YAML frontmatter) served under `skill://` URIs, with optional
discovery via `skill://index.json`.

- `skills-list` reads the well-known index, falling back to scanning
  resources for `skill://*/SKILL.md` URIs (per spec, an absent index does
  not imply zero skills)
- `skills-get <name>` reads the SKILL.md; `--raw` prints just the markdown
  for piping to LLMs or files
- Session overview surfaces `skills` under capabilities when the server
  advertises `capabilities.extensions["io.modelcontextprotocol/skills"]`
- JSON output is documented for both commands so AI agents can consume it
Coverage:
- Unit: parseIndex (well-formed, malformed, drops bad entries, JSON
  errors), skillsFromResources (URI matching, nested paths, ignores
  non-skill-md files), resolveSkillUri (bare names, nested paths, full
  URIs, trailing slashes), extractTextContent, discoverSkills (index
  path, fallback path, paginated resource scan)
- Unit: formatSkills (count, descriptions, types, empty state),
  formatSkillDetail (markdown body, missing MIME, blob fallback,
  truncation), formatServerDetails capability surfacing under both
  `capabilities.extensions` (per spec) and `capabilities.experimental`
  (SDK-preserved escape hatch)
- Unit: parser suggests `skills-list` for `skills`/`list-skills`
- E2E: opt-in `WITH_SKILLS=true` server flag exposes skill:// resources
  and advertises the extension capability. Three scenarios covered:
  index-path discovery, no-index fallback (`SKILLS_NO_INDEX=true`), and
  no-extension server. Verifies --json shapes, --raw mode, nested skill
  paths, full-URI input, and that --json+--raw still emits the full
  ReadResourceResult so `jq -r '.contents[0].text'` works.

Implementation tweak: capability detection now also accepts
`capabilities.experimental[skills]` since current MCP SDKs strip
unknown capability fields like `extensions`. Test server advertises
under both keys for forward compatibility.

Internal helpers (parseIndex, skillsFromResources, extractTextContent,
discoverSkills) are exported with `@internal` markers for testability.
Conflict resolution:
- CHANGELOG: kept the skills entry alongside main's trimmed
  auto-discover entry; dropped the test:conformance entry that main
  removed as internal.

Spec alignment (SEP-2640 draft updates):
- The current draft makes `name` conditionally required: required for
  `type: "skill-md"` entries but optional for `type:
  "mcp-resource-template"` namespaces. `parseIndex` previously dropped
  all nameless entries; now it keeps nameless templates and derives a
  display name from the URL (segment before `SKILL.md`, else last path
  segment).
- Updated tests: split the "drops malformed entries" case to
  distinguish skill-md (drop) from template (keep with derived name);
  added explicit cases for both URL shapes.

Other spec points reviewed; no implementation change needed:
- Capability key is `extensions` (per spec); mcpc already checks both
  `extensions` (per spec) and `experimental` (SDK-preserved escape
  hatch since current MCP SDKs strip unknown capability fields).
- Alternative schemes (e.g. `github://`) in the index are only
  reachable via the index path; mcpc's resource-scan fallback is
  unchanged and correctly limited to `skill://*/SKILL.md` (per spec,
  alt-scheme skills MUST be listed in the index).
Main centralized CLI colors into a `theme` object (#230). The session
commands help block in cli/index.ts uses `chalk.cyan(...)`; the resolved
form uses `theme.cyan(...)` to match. Also updated the chalk mock in
skills.test.ts to expose `hex()` so the `theme` module-load expressions
in src/cli/output.ts work under jest (mirrors the mock shape now used
in output.test.ts).
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.

3 participants