Skip to content

[Demo] SEP-2640 Skills over MCP: bundled + per-repo + discovery#2428

Draft
olaservo wants to merge 11 commits intogithub:mainfrom
olaservo:add-agent-skills
Draft

[Demo] SEP-2640 Skills over MCP: bundled + per-repo + discovery#2428
olaservo wants to merge 11 commits intogithub:mainfrom
olaservo:add-agent-skills

Conversation

@olaservo
Copy link
Copy Markdown
Contributor

@olaservo olaservo commented May 5, 2026

Summary

Server-side demo of SEP-2640 (Skills extension to MCP). Implements the SEP's full discovery surface and verifies the autonomous-agent discovery loop end-to-end against anthropics/skills.

Builds on top of #2374 (catalogue + Instructions cleanup) and #2129 (per-repo resource template). Supersedes the closed #2360. WIP demo fork, not intended for upstream merge as-is.

What's in this branch

  • 28 bundled SKILL.md skills at skill://github/<name>/SKILL.md via //go:embed (25 from feat: replace server instructions with skill resources #2374, 2 deepened — review-pr and handle-notifications — and 1 meta-skill discover-mcp-skills).
  • skill://index.json advertising both type: "skill-md" and type: "mcp-resource-template" entries (agentskills.io v0.2.0 schema). Two of the SEP's three index entry types in one server.
  • Per-repo template skill://{owner}/{repo}/{skill_name}/{+file_path} reading any file inside any discovered skill in any GitHub repo. _manifest from feat: add skill:// resource templates for Agent Skills discovery #2129 dropped as non-SEP.
  • list_repo_skills tool wrapping tree discovery so autonomous agents can enumerate (workaround for the SEP's UI-only completion/complete gap; documented as such).
  • Cleanup: removes the legacy InstructionsFunc / WithServerInstructions machinery (~308 lines). Skills are the only guidance surface.
  • New non-default skills toolset gates the per-repo bits.

Verified end-to-end

Live stdio JSON-RPC test:

  • initialize declares io.modelcontextprotocol/skills extension at protocol 2025-11-25.
  • resources/list → 29 skill:// entries; skill://index.json validates against v0.2.0 schema with 28 skill-md + 1 mcp-resource-template.
  • tools/call list_repo_skills(owner=anthropics, repo=skills) → 18 skills with valid skill:// URLs.
  • resources/read round-trips both SKILL.md (8 KB) and a relative file forms.md (12 KB) for anthropics/skills/pdf through the per-file template handler.

Test plan

  • go build ./... and go test ./... clean
  • --toolsets=default excludes per-repo template + list_repo_skills
  • --toolsets=default,skills (or =all) exposes them
  • Live discovery loop verified against anthropics/skills

Branch shape

11 commits on top of main: 4 historical (Registry + 2 original skills + content polish) + 7 focused new commits. The new ones are split by concern: cleanup, URI prefix, rename + drop gating, import 25, per-repo template + skills toolset, list_repo_skills tool, discover-mcp-skills meta-skill.

🤖 Generated with Claude Code

olaservo and others added 11 commits April 19, 2026 19:58
Introduce a reusable `skills` package that lets an MCP server publish
server-bundled Agent Skills (SKILL.md files shipped in the binary) per
the skills-over-MCP SEP (SEP-2133):

  - skills.Bundled describes one skill (name, description, embedded
    content, optional icons, optional enabled predicate for runtime
    gating on toolsets/feature-flags/headers)
  - skills.Registry collects entries, declares the
    `io.modelcontextprotocol/skills` extension capability on the server,
    and installs each SKILL.md as an MCP resource plus a
    skill://index.json discovery document conforming to the
    agentskills.io/discovery/0.2.0 schema

The package has no GitHub-specific state — any MCP server author can
drop it in to publish bundled skills with a small amount of wiring.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ship a SKILL.md at skills/pull-requests/SKILL.md that documents the
pending-review workflow for submitting a multi-comment GitHub pull
request review (pull_request_review_write → add_comment_to_pending_review
→ submit_pending). The skill file lives at the repo root so it is also
usable as a plain agent skill by any consumer that scans the repo
(Claude Code, the agent-skills CLI), independent of this server.

Register the skill via skills.Registry in NewMCPServer, gated on the
pull_requests toolset being enabled. Both stdio and HTTP transports
pick it up since both routes through NewMCPServer. The pull_requests
toolset's inline server instructions are unchanged — skill-aware hosts
discover the skill through the extension capability, skill://index.json,
and resources/list; older hosts continue to receive the same inline
instructions they always have.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The bundled skill now reads differently from the inline server
instructions rather than mirroring them, showing the point of
progressive disclosure: a skill-aware host spends no extra context on
every request but can pull the deeper version on demand.

Restructure into "When to use", "Workflow" (numbered steps), and
"Caveats" sections per the agentskills.io spec's recommended body
shape. Add content that is *not* in the inline instructions:
- when to skip this flow (single top-level comment / approve without
  inline feedback)
- the pending-ness hinges on omitting `event` in step 1
- specific line-ref parameter names (path, line, side, startLine,
  startSide)
- the concrete `APPROVE | REQUEST_CHANGES | COMMENT` event values
- pending reviews are invisible to the PR author and can be deleted
  via `method: "delete_pending"`

Update the embedded-content test to check for the new `## Workflow`
section header and a second tool-name presence assertion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ship a second bundled skill that walks the agent through systematic
GitHub notifications triage: enumerate with list_notifications,
partition by reason (review_requested / mention / assign /
security_alert — high; author / comment / state_change — medium;
ci_activity / subscribed — low), act on high-priority items, then
dismiss with state "done" or "read" per the skill's rule.

Demonstrates:
- Multiple bundled skills in one server (registry now has two entries).
- Per-skill toolset gating — pull-requests gates on pull_requests,
  inbox-triage gates on the non-default notifications toolset, so
  enabling one does not force the other.
- Cross-skill reference (the inbox-triage workflow points at the
  pull-requests skill when handling review_requested items).
- Skills teaching workflow judgment (priority buckets) that tool
  descriptions alone cannot encode.

Tests cover the symmetric structural checks, per-toolset registration
paths, the multi-skill index.json shape, and the capability declaration
firing on either toolset.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ions machinery

Skills are the only guidance surface going forward; the per-toolset
inline instruction system is no longer needed. This removes ~308 lines
of toolset instruction generation.

- Delete pkg/github/toolset_instructions.go (5 generate*ToolsetInstructions
  helpers), pkg/inventory/instructions.go (generateInstructions aggregator),
  and pkg/inventory/instructions_test.go (~265 lines of tests).
- Remove the InstructionsFunc field from inventory.ToolsetMetadata, and
  drop it from the 5 toolsets that used it (Context, Issues, PullRequests,
  Discussions, Projects).
- Remove the generateInstructions field, WithServerInstructions() method,
  and the conditional in Builder.Build() that called generateInstructions(r).
- Remove the instructions field and Instructions() method from Inventory.
- Drop the .WithServerInstructions() call from NewStdioMCPServer
  (internal/ghmcp/server.go) and from DefaultInventoryFactory (pkg/http/handler.go).
- Drop `Instructions: inv.Instructions(),` from the serverOpts assembled
  in NewMCPServer (pkg/github/server.go).

Inspired by the cleanup in github#2374.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per SEP-2640, the bundled-skill URI structure is
skill://<skill-path>/<file-path>, where preceding segments before the
final name are an organizational prefix chosen by the server. This
commit moves from the flat skill://<name>/SKILL.md form to the
prefixed skill://github/<name>/SKILL.md form, matching the convention
used in github#2374.

Single-line change to skills.Bundled.URI(). Tests already build URIs
through this helper, so they pick up the change automatically — no
test edits needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ll gating

Renames the two original skills to the names Sam uses in
github#2374, and switches them from toolset-gated
loading to always-on, matching how upstream's skills load.

- pull-requests → review-pr
- inbox-triage  → handle-notifications

Both renames preserve the original content (parameter-level workflow
detail for review-pr; High/Medium/Low priority taxonomy + read/done
semantics for handle-notifications). Only the names change, plus the
cross-reference inside handle-notifications/SKILL.md (was → review-pr).

Load consistency:
- Drop the per-skill `Enabled func() bool` closures so both skills
  register unconditionally, matching upstream's "everything always
  available" semantics.
- Drop the per-skill `Icons` field. The `light-bulb` octicon used by
  pull-requests didn't resolve in this fork's icon set anyway, and
  shipping no icons is the simpler, more consistent default.
- The Registry's `Enabled` closure mechanism stays in place for future
  use; just no shipped skill currently exercises it. A new
  Test_DeclareSkillsExtensionIfEnabled subtest covers the
  empty-registry path directly.

Tests:
- Test_PullRequestsSkill_EmbeddedContent → Test_ReviewPRSkill_EmbeddedContent
- Test_InboxTriageSkill_EmbeddedContent → Test_HandleNotificationsSkill_EmbeddedContent
- Test_BundledSkills_Registration (toolset-gating subtests) collapsed into
  Test_BundledSkills_RegisterRegardlessOfToolset.
- Test_DeclareSkillsExtensionIfEnabled simplified from 4 subtests to 3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Imports the workflow-oriented skill catalogue from
github#2374 as standalone SKILL.md files served via
the existing Registry. Each skill covers a discrete GitHub workflow
the model can pull on demand rather than loading all guidance up-front.

Imported skills (25): get-context, explore-repo, search-code,
trace-history, create-pr, self-review-pr, address-pr-feedback,
merge-pr, triage-issues, create-issue, manage-sub-issues, debug-ci,
trigger-workflow, security-audit, fix-dependabot, research-vulnerability,
manage-project, prepare-release, manage-repo, manage-labels,
contribute-oss, browse-discussions, delegate-to-copilot,
discover-github, share-snippet.

Skipped from github#2374 (2): review-pr and handle-notifications — those
names are now used by the renamed-and-deepened skills from the prior
commit, so the catalogue ends up with github#2374's names + this fork's
deeper content for those two.

Each skill is a `skills/<name>/SKILL.md` file embedded via //go:embed,
plus a single Registry.Add() call in pkg/github/bundled_skills.go.
The `allowed-tools` frontmatter list is included verbatim from github#2374
as advisory metadata (not enforced; not surfaced via resource _meta).

Tests: adds Test_BundledSkills_NoDuplicateURIs,
Test_BundledSkills_AllFrontmatterValid, and
Test_BundledSkills_AllReadable — these scale across the full catalogue
and protect against regressions when adding more skills.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the SEP-2640-aligned per-repo Agent Skills surface: a single
parameterized MCP resource template that lets any GitHub repo expose
its skills/ directory through the same skill:// URI scheme used for
bundled skills.

Template:
  skill://{owner}/{repo}/{skill_name}/{+file_path}

`{+file_path}` is RFC 6570 reserved expansion, so a multi-segment
relative path inside the skill directory (e.g. references/GUIDE.md)
round-trips through the template as a single value. SKILL.md and any
relative references mentioned inside it both resolve via this one
template handler.

Discovery on the server:
- Recognizes the four agentskills.io directory conventions:
  skills/<name>/SKILL.md, skills/<namespace>/<name>/SKILL.md,
  plugins/<plugin>/skills/<name>/SKILL.md, and root-level
  <name>/SKILL.md (excluding hidden + convention-prefix dirs).
- Skill discovery happens at request time via the Git Trees API.
- skill:// completion is wired through CompletionsHandler so MCP
  hosts can offer interactive autocomplete on owner/repo/skill_name.

Index integration:
- skills.Registry extended with BundledTemplate + AddTemplate +
  EnabledTemplates so skill://index.json now publishes both
  type:"skill-md" entries (the 27 bundled skills) and a single
  type:"mcp-resource-template" entry (the per-repo template).
- IndexEntry.Name is now omitempty since the SEP example shows
  template entries without a name.
- DeclareCapability fires for either type of entry being enabled.

Toolset gating:
- New non-default `skills` toolset gates the per-repo template's
  index entry. With --toolsets=default the per-repo surface is hidden;
  with --toolsets=default,skills (or --toolsets=all) it's published.
- The per-repo template is defined in pkg/github/skills_resource.go;
  registered via AllResources so the inventory wires it up alongside
  repo:// templates.

Adapted from the resource-template work in
github#2129. The non-SEP _manifest endpoint from
that PR is intentionally NOT ported — multi-file skill discovery is
handled by the SEP's per-file URI resolution, not a manifest JSON.

Tests cover: template definition, file handler with SKILL.md, file
handler with multi-segment relative path, missing-arg errors, path
traversal rejection, agentskills.io convention discovery,
URI parsing, completion handler, and the index-entry presence/absence
based on toolset gating.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The per-repo MCP resource template added in the previous commit lets
agents READ skills in any GitHub repo, but discovering which skills
exist requires completion/complete — and that's a client-UI feature
only, not accessible to the model. Headless agents have no way to
enumerate skills in a repo they don't already know about.

This adds a small read-only tool that wraps the existing
discoverSkills() function and returns each discovered skill's name
plus a ready-to-use skill:// URL the model can pass straight to
resources/read.

Returned shape:
  {
    "owner": "anthropics",
    "repo":  "skills",
    "skills": [
      { "name": "pdf",  "url": "skill://anthropics/skills/pdf/SKILL.md" },
      ...
    ],
    "totalCount": 18
  }

Returning the URL alongside the name is the killer feature — the
model gets URIs ready for the per-file template handler without a
second round-trip.

Gated on the `skills` toolset; --toolsets=default does not expose it.

Caveat: this is a workaround for a SEP-2640 discovery gap, not a
SEP mechanism. The SEP's three documented discovery surfaces
(skill://index.json, server `instructions` URI pointers, and
mcp-resource-template entries surfaced via completion/complete) all
assume either bounded enumeration or client-UI mediation. Once a
host-side complete_resource_template tool pattern emerges, this
server-side tool can be retired.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A meta-skill that teaches the model the discover-then-read workflow
for both bundled (skill://index.json → skill://github/<name>/SKILL.md)
and per-repo (list_repo_skills → skill://<owner>/<repo>/<name>/SKILL.md
→ relative file resolution) skill surfaces.

Sits in skill://index.json alongside the workflow-oriented skills, so
an autonomous agent loading the index sees this skill in the catalogue
and can self-bootstrap into the discovery loop. Trigger phrases include
"what skills do you have?", "use the skill from repo X", and "are there
skills for this in any repo?".

Always-on (no toolset gating) — the bundled-skill discovery half is
useful regardless of which toolsets are enabled. The per-repo half
depends on list_repo_skills being available, which the SKILL.md body
calls out explicitly as a caveat.

Closes the autonomous-agent discovery loop: from a cold start an
agent can read the index, find this skill, follow it to enumerate
+ read any repo's skills, and resolve relative references — all
without needing a human to drive completion UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant