Log decisions around simplifying the V1 SEP and adding skills/get (#110)

* docs: record SEP-2640 v1 scope-down and skills/get as decision records

Consolidates the July 2026 rework of SEP-2640 (post June 24 CM deferral
and June 30 WG scoping decision) into a single ADR for group review:
archives removed, skills/list replacing skill://index.json, per-file
resources manifest, optional directory read, non-privileged schemes,
name-collision handling, and nested-skill consent gating.

Adds a separate ADR for the skills/get method proposed by @aditya-scio
in SEP review, and updates the status lines of the four prior entries
this rework supersedes or amends (2026-04-19, 2026-06-02, 2026-06-05,
2026-06-09).

🦉 Generated with [Claude Code](https://claude.com/claude-code)

* docs: add Discord design-thread references to v1 scope-down ADR

Links Peter's July 8 change announcement, the supporting-file digests
thread (the design discussion behind the per-file resources manifest),
and Sambhav's June 24 method-family sketch that prefigured skills/list
and skills/get.

🦉 Generated with [Claude Code](https://claude.com/claude-code)

* docs: refine context and rationale for skills/get method in SEP-2640 decision
This commit is contained in:
Ola Hungerford 2026-07-29 21:16:44 -07:00 • committed by GitHub
commit 3983f888f1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -186,7 +186,7 @@ For background on the ADR format, see [adr.github.io](https://adr.github.io/).
### 2026-04-19: Archives permitted as server-side packaging optimization
**Status:** Accepted
**Status:** Superseded — archives were removed from SEP-2640 in core-maintainer review; see the 2026-07-16 v1 scope entry below
**Context:** On 2026-03-24, a commit to the Skills Extension SEP (PR #69, [`9e73838c`](https://github.com/modelcontextprotocol/experimental-ext-skills/pull/69/commits/9e73838cda478f3bba4996a06a69d3142fb0a91c)) removed `type: "archive"` from the `skill://index.json` schema with the rationale that archives do not apply when files are individually addressable. On further review, there are four costs not addressed in the original commit: asymmetry with the Agent Skills discovery RFC, which defines both `skill-md` and `archive` distribution types; loss of atomicity across multi-file skill reads; N+1 round trips for hosts that pre-materialize skills; and loss of UNIX file metadata (executable bits, symlinks) that has no representation when each file is served as an individual MCP resource.
@ -204,7 +204,7 @@ For background on the ADR format, see [adr.github.io](https://adr.github.io/).
### 2026-06-02: Reinstate the `digest` field in `skill://index.json`
**Status:** Accepted
**Status:** Superseded — the single per-entry digest was replaced by a per-file `resources` manifest; see the 2026-07-16 v1 scope entry below
**Context:** SEP-2640's `skill://index.json` binding follows the [Agent Skills well-known discovery index](https://github.com/agentskills/agentskills/pull/254) with two stated differences — the `url` field carries a full MCP resource URI, and the per-entry `digest` field is omitted "(integrity is the transport's concern over an authenticated MCP connection)" — plus one MCP-specific addition, the `mcp-resource-template` `type` value. In the upstream index each skill entry carries a `digest` (a `sha256:<hex>` content hash) serving two purposes: (1) integrity — letting an index host attest that a served skill matches what the index advertised, which matters when the index and the skill artifacts live on different hosts (e.g., index on one domain, archives on a CDN); and (2) caching — a client stores the digest, refetches only the index, and skips refetching unchanged skill content, which can run to tens of MB. The same trade-off was argued upstream on [agentskills#254](https://github.com/agentskills/agentskills/pull/254), where Peter Alexander questioned the digest's value over HTTP (standard HTTP caching could cover it) and Jonathan Hefner defended it on cross-domain integrity and lockstep-consistency grounds. Over MCP, purpose (1) does not apply, since the same server serves both the index and the skill resources; and the cleaner long-term answer to (2) — a general resource-freshness mechanism (resource metadata or ETags) — does not exist in the base protocol today. The omission was revisited in the June 2, 2026 Working Session and in the [#skills-over-mcp-wg](https://discord.com/channels/1358869848138059966/1464745826629976084) Discord channel, where the group converged on putting `digest` back.
@ -223,7 +223,7 @@ For background on the ADR format, see [adr.github.io](https://adr.github.io/).
### 2026-06-05: Decouple the index schema from `.well-known`; keep it a file with verbatim frontmatter and per-skill archives
**Status:** Proposed
**Status:** Superseded — the index file was replaced by a `skills/list` method and the `archives` array was removed; verbatim frontmatter carries forward; see the 2026-07-16 v1 scope entry below
**Context:** SEP-2640's index was originally specified as the [Agent Skills `.well-known` discovery index](https://github.com/agentskills/agentskills/pull/254) with a few MCP-specific differences (see 2026-06-02), so that a client consuming the HTTP `.well-known` index could consume `skill://index.json` with the same code. Peter Alexander reported being unable to confirm that the upstream `.well-known` agent-skills discovery spec will land: it has implementations in the wild but no governance momentum into the agentskills.io spec itself. Binding the SEP's index to a stalled upstream blocks progress, so the thread converged on defining the WG's own schema.
@ -251,7 +251,7 @@ For background on the ADR format, see [adr.github.io](https://adr.github.io/).
### 2026-06-09: Directory enumeration via a dedicated `resources/directory/read` method
**Status:** Proposed
**Status:** Proposed — amended 2026-07-16: retained in SEP-2640 v1 as an optional feature gated behind the `directoryRead` capability setting
**Context:** A skill is a directory of files, and hosts that materialize a skill (or otherwise walk its contents) need to enumerate the files under a skill root without already knowing every URI. An earlier SEP draft did this with a scoped `resources/list(uri="skill://…")` call, but the base MCP spec does not guarantee scoped `resources/list`, leaving this extension with a protocol dependency it could not rely on (the SEP's "Why an Index Resource Rather Than `resources/list`?" section records the move away from that approach). The 2026-06-02 Working Session listed "try to get `resources/list(uri)` into the protocol" as an action item; the MCP core maintainer (dsp) was on board, leaving the WG to spec the mechanism. The design was worked out over the following week in the SEP feedback thread and landed in [SEP-2640](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640) on 2026-06-09.
@ -276,3 +276,59 @@ Returning metadata-only (URIs + descriptive fields, no contents) keeps the call
- [#skills-over-mcp-wg Discord](https://discord.com/channels/1358869848138059966/1464745826629976084) — directory-read design thread, 2026-06-04 through 2026-06-09 (Peter Alexander, Sam Kothari, Ola Hungerford).
- [Meeting Notes — Skills Over MCP WG](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/categories/meeting-notes-skills-over-mcp-wg) — June 2, 2026 Working Session (action item: get `resources/list(uri)` into the protocol).
- SEP draft, "Why an Index Resource Rather Than `resources/list`?" — records the earlier scoped-`resources/list` approach this method supersedes for directory enumeration.
---
### 2026-07-15: Add `skills/get` for single-skill entry retrieval
**Status:** Proposed
**Context:**
SEP-2640's `skills/list` may return an empty or partial listing by design — catalogs that are large, gateway-fronted, or generated on demand are unenumerable — and the extension's baseline hands hosts skill URIs that never appeared in any listing (from server instructions, another skill, or the user).
Before `skills/get`, such a skill could be *read* but not *verified*: its entry — frontmatter and per-file digests — existed nowhere reachable, so it could not be content-bound to a user approval even when the underlying content was static and its digests perfectly publishable. Separately, when a single skill's content changed (surfacing as a digest-verification failure, or a user-requested update), the only way to obtain its new digests was to re-enumerate the entire catalog — thousands of entries to learn the new state of one skill.
Aditya (@aditya-scio) raised the gap in [SEP-2640 review](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640#discussion_r3576942360) on 2026-07-14: *"Given a server may return partial listing; I think we should also introduce a `skills/get` so that we can get the resource's manifest (so that the digest can be verified) for a given skill. Otherwise there's no way to fetch it."*
**Decision:** Add a required `skills/get` method to the extension. `skills/get(uri)` — where `uri` names a skill's `SKILL.md` — returns that skill's entry, identical in shape and meaning to a `skills/list` entry (`uri`, `frontmatter`, `resources`), under the same rules:
- Every server declaring `io.modelcontextprotocol/skills` MUST implement `skills/get`, alongside `skills/list`.
- A server MUST answer for every skill it serves, whether or not that skill appears in its `skills/list` result; it answers with an error for URIs it does not serve as skills.
- Dynamically generated skills omit `resources` in a `skills/get` response exactly as they would in a listing, and remain unverifiable by construction.
**Rationale:** The method makes verification independent of the discovery path: a URI alone was already enough to *read* a skill, and `skills/get` turns that same URI into the skill's metadata and digests, so an unlisted skill can be verified, content-bound, and approved on the same terms as a listed one. It makes change pickup proportional to what changed: one entry fetch instead of a full re-enumeration. It also doubles as the skill-identity confirmation the non-privileged-scheme rule needs — a host confirms that an explicitly referenced URI is a skill by asking the server (which answers for skills it serves and errors otherwise), never by inspecting the URI scheme. And because the returned `skill` object reuses the listing entry shape, the method adds no new schema.
---
### 2026-07-16: Scope SEP-2640 down to a v1: required `skills/list` + `skills/get`, per-file digests, no archives
**Status:** Proposed
**Context:** At the [June 24, 2026 core-maintainer meeting](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/2976) the vote on SEP-2640 was deferred with structural concerns: archive delivery was the main sticking point (unpacking complexity and risk, and giving up the governance advantages MCP provides), `skill://index.json` was flagged as a proprietary format outside the official skill spec that complicates permissions and TTL handling, and the proposal was seen as conflating "serve skills over MCP" with a general distribution mechanism, with script-execution risk in the background. The [June 30, 2026 WG session](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/2994) resolved to scope the extension down to the minimal shape the core maintainers would accept — per the lead maintainer's guidance, break it into something small, land it, and layer complexity afterward — deferring archives and resolving the smaller open items (index transport, name conflicts). A [core-maintainer alignment document](https://docs.google.com/document/d/1llJ667kyIu5ZA_-A8U1AntWUxMW65iXaLT-3elfi3J4/edit) was reviewed with the CMs in early July, and the rework landed on the SEP branch as a commit series between July 8 and July 15, 2026. This entry consolidates that v1 shape into a single record for WG review.
**Decision:** SEP-2640 v1 comprises the following changes to the full draft:
1. **Archives removed** ([`af08f6f`](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640/commits/af08f6fe16675351433e7803a5fee3cdd1eb1d9a)). Archive distribution moves to an "Appendix: Deferred Features" that records the CM objections — host-side unpacking is an attack surface disproportionate to the benefit (decompression bombs, path traversal, link escapes, normalization collisions, non-regular entries), and two ways to serve one skill is a compatibility hazard that breaks the flat compatibility floor — so any future reintroduction starts from those objections rather than rediscovering them. A skill is always retrieved as individually addressable resources. Supersedes the 2026-04-19 archives decision and the `archives` array of 2026-06-05.
2. **`skill://index.json` replaced by a `skills/list` method** ([`9b9d299`](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640/commits/9b9d299a49102b44e68e751a7986a0d54baa7ff6)). Same entry schema, different carrier: pagination via the standard `cursor`/`nextCursor` contract, cache-lifetime semantics inherited from [SEP-2549](https://modelcontextprotocol.io/seps/2549-TTL-for-list-results) (directly answering the June 24 TTL/permissions concern), discoverability implied by the extension declaration itself, and uniformity with `tools/list`/`resources/list` client machinery. The listing MAY be empty or partial; hosts MUST NOT treat that as proof a server has no skills. Supersedes the "keep it a file" half of 2026-06-05; the verbatim-frontmatter entry shape carries forward unchanged.
3. **Single skill digest replaced by a per-file `resources` manifest** ([`cff984c`](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640/commits/cff984c3f526d34e06a758e9b4ac8fb5f5aa964d)). Each entry enumerates every file of the skill as `{uri, digest}` pairs; when present the set MUST be complete; user approval content-binds to the whole set; a read of an unlisted file within the skill is a verification failure; dynamically generated skills omit `resources` and accept that hosts may decline them. This closes a gap the CMs asked the WG to resolve — supporting files (references, templates, scripts) carried no digest, so a scanner could vet a `SKILL.md` while its supporting files changed underneath — and, per Peter Alexander's framing in the design thread, gives clients "some atomic unit of things-users-consent-to" while avoiding torn reads on individual resource changes, recovering the atomic-snapshot property archives offered without the unpacking surface. Supersedes the 2026-06-02 single-digest decision.
4. **`skills/get` added for single-skill entry retrieval** ([`d7490ec`](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640/commits/d7490ecd1a250f7bc8c3ebb0d65450dfec274bad)) — recorded separately in the 2026-07-15 entry above.
5. **`resources/directory/read` retained but optional**, gated behind a `directoryRead` capability setting (default `false`); clients MUST NOT call it against a server that has not declared it. Amends the 2026-06-09 decision, which introduced the method unconditionally.
6. **Skill URI schemes are non-privileged** ([`2971db7`](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640/commits/2971db76fe113d486a1dff4ae0b068ab53e89d94)). `skill://` is conventional, not semantic: a host learns that a resource is a skill from a `skills/list` entry or a `skills/get` answer, never from the URI scheme, and the structural constraints (path ends in the skill name, explicit `SKILL.md`) apply to every scheme alike.
7. **Name-collision handling specified** ([`8b97c28`](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640/commits/8b97c28d25c09a0f5acb585d607243ec26d36c37)). A skill's `name` is a label, not an identifier — identity is the `uri`. Hosts MUST NOT assume name uniqueness, MUST disambiguate same-name entries within a listing rather than silently dropping or preferring one, and MUST resolve cross-origin collisions in per-origin namespaces (host-assigned server labels) with no silent shadowing in either direction, including of the host's own filesystem skills. Resolves the name-shadowing open item from June 30.
8. **Nested skills allowed, gated on fresh activation consent** ([`100c5a4`](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640/commits/100c5a40011fe4591a38a3eb3f4ac6d5d424d4c2)). From the enclosing skill's perspective, nested content is ordinary supporting content and a nested `SKILL.md` read that way is ordinary markdown; *activating* a nested skill as a skill in its own right requires fresh, explicit user consent — approval of the enclosing skill does not substitute. Publication stays flat.
Net protocol surface: two required methods (`skills/list`, and potentially `skills/get`) that every server declaring the extension implements, one optional method (`resources/directory/read`) behind a single feature flag, and no other new methods, message types, or schema changes.
**Rationale:**
The scope-down trades breadth for a landable V1 version. Archives were the main source of review churn and their real need (bulk fetch) is preserved as an open follow-up (an optimized batch read, to be compared against archives as a separate resources-as-filesystem track). The June 30 discussion had sketched a "zero new methods" version; that was set aside during CM alignment because the index resource's format was itself a CM objection, and [SEP-2549] (Final for the upcoming release) gives list-shaped methods standardized caching for free — a method is first-class in the protocol where a reserved-URI convention is not.
Keeping optionality to a single feature flag responds to the CM position that optionality within a bounded primitive produces capability matrices and unused features (the sampling/logging lesson). Making name-collision handling normative rather than implementation-defined responds to security findings that same-name skills are a live impersonation surface across harnesses that each break ties differently. Deferred, not rejected: archives, batch read, distribution via well-known URL, and dynamic tool loading remain candidate follow-on iterations, to be informed by implementation experience with this scope.
**References:**
- [June 24, 2026 Core Maintainer meeting notes](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/2976) — vote deferred, four structural concerns.
- [June 30, 2026 WG meeting notes](https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/2994) — scoping decision and open items.
- [Core-maintainer alignment document](https://docs.google.com/document/d/1llJ667kyIu5ZA_-A8U1AntWUxMW65iXaLT-3elfi3J4/edit) — reviewed with the CMs early July 2026.
- [Supporting-file digests thread](https://discord.com/channels/1358869848138059966/1524467339674910901) — design discussion behind the per-file `resources` manifest (Peter Alexander, Cliff Hall, Aditya, Peder), 2026-07-08 through 07-10; registry/CVE-style provenance ideas raised there were explicitly deferred beyond v1.
- [PR #108](https://github.com/modelcontextprotocol/experimental-ext-skills/pull/108) — companion threat-model document, in review.