From 87cd7086a482f9198bbbae032fc484318a9925f4 Mon Sep 17 00:00:00 2001 From: Sambhav Kothari Date: Sun, 11 Oct 2026 13:43:36 +0100 Subject: [PATCH] Align skills spec types with the 2026-07-28 base schema Named params for skills/get and resources/directory/read, cacheable directory results, *ResultResponse types, optional _meta on Skill, full _meta in request examples. Records the decision and re-anchors index.md. Fixes #156 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01M8b7Vuu2jRefMhoZB3BrrX --- docs/decisions.md | 42 ++++++++++++ index.md | 10 +-- specification/stable/skills.mdx | 118 +++++++++++++++++++++++++++----- 3 files changed, 148 insertions(+), 22 deletions(-) diff --git a/docs/decisions.md b/docs/decisions.md index 3d572e3..ebf0c8f 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -366,3 +366,45 @@ The page also did not state its protocol-revision baseline, so dropping the SEP' - [conformance#330](https://github.com/modelcontextprotocol/conformance/pull/330), the SEP-2640 conformance suite. - [SEP-2549](https://modelcontextprotocol.io/seps/2549-TTL-for-list-results), which defines `CacheableResult`. - SEP-2640, "Retrieval via `skills/get`", final semantics bullet (the "left open" sentence this entry resolves). + +--- + +### 2026-10-11: Align the spec page's types and examples with the `2026-07-28` base schema + +**Status:** Proposed. On acceptance, applied to `specification/stable/skills.mdx` by [PR #157](https://github.com/modelcontextprotocol/ext-skills/pull/157), as the 2026-09-08 and [PR #147](https://github.com/modelcontextprotocol/ext-skills/pull/147) corrections were, rather than through a draft revision. + +**Context:** [`specification/stable/skills.mdx`](../specification/stable/skills.mdx) states that its referenced types are those of the `2026-07-28` base schema and that every request **MUST** carry the required request metadata (`_meta`). [Issue #156](https://github.com/modelcontextprotocol/ext-skills/issues/156) reports that `ReadResourceDirectoryRequest` does not compile against that schema: it extends `PaginatedRequest` but declares an inline `params` without the `_meta` that `PaginatedRequestParams` inherits from `RequestParams` (`TS2430`). + +Auditing the whole page against the base schema's conventions found further departures: + +1. `GetSkillRequest` extends the open `Request` type with an inline `params: { uri }`, so a `skills/get` request without `_meta` type-checks. The base schema's concrete requests extend `JSONRPCRequest` with a named params interface. +2. `ReadResourceDirectoryResult` extends only `PaginatedResult`. Every base list-shaped result (`resources/list`, `resources/templates/list`, `tools/list`, `prompts/list`) also extends `CacheableResult`, making `ttlMs` and `cacheScope` required. It is the only paginated result on the page without them. +3. The base schema defines a `*ResultResponse` type for each method. The page defines none. +4. Base entity types (`Resource`, `Tool`, `Prompt`) carry an optional `_meta: MetaObject`. `Skill` does not. +5. Request examples omit `_meta`, where every base request example includes the required `io.modelcontextprotocol/protocolVersion` and `io.modelcontextprotocol/clientCapabilities` (and `clientInfo`). +6. The page uses `Request` without listing it among the base types it references. + +**Decision:** Bring the page into line with the base schema's conventions, accepting that some changes tighten what a conformant implementation sends: + +1. `skills/get`: `GetSkillRequestParams extends RequestParams` with `uri`; `GetSkillRequest extends JSONRPCRequest`; `GetSkillResultResponse.result` is `GetSkillResult`. The method does not take input responses (see Rationale). +2. `resources/directory/read`: `ReadResourceDirectoryRequestParams extends PaginatedRequestParams` with `uri`; `ReadResourceDirectoryResult extends PaginatedResult, CacheableResult`, so `ttlMs` and `cacheScope` are **REQUIRED**. It stays list-shaped and does not take input responses, matching the base list methods. +3. Add `ListSkillsResultResponse`, `GetSkillResultResponse` and `ReadResourceDirectoryResultResponse`. +4. Add optional `_meta?: MetaObject` to `Skill`. Keys defined by this extension use the `io.modelcontextprotocol.skills/` prefix. +5. Every request example carries the full required `_meta`, and the "examples omit `_meta` for brevity" sentence is replaced. Directory-read result examples carry `ttlMs` and `cacheScope`. +6. The Protocol Revision sentence lists every base type the page references. + +**Rationale:** The page targets `2026-07-28` and says so, so its types should be the ones an implementer gets by extending that schema in the usual way. Where the page and the base schema disagree, implementers generating types from both get incompatible shapes, and conformance tooling cannot check the extension's methods the way it checks base methods. + +Changes that alter conformance, rather than only correcting the rendering: + +- **`ttlMs` and `cacheScope` become required on `resources/directory/read` results.** A server that omits them is non-conformant under the new text. This mirrors the 2026-09-08 decision for `skills/list` and `skills/get`. +- **`_meta` on requests** was already required by the page's text; only the types and examples change. + +`skills/get` does not take input responses. In the base schema only content-producing methods (`resources/read`, `prompts/get`, `tools/call`) do; `skills/get` returns metadata, and a server needing input before releasing content can request it on `resources/read`. + +The wire format of a successful exchange is otherwise unchanged. `skills/list` already matched the base convention and is unchanged apart from its response type. + +**References:** +- [Issue #156](https://github.com/modelcontextprotocol/ext-skills/issues/156) from @paulbalandan, which reports the compile error and proposes named params interfaces for both requests. +- Base schema `2026-07-28`: `RequestParams`, `RequestMetaObject`, `PaginatedRequestParams` and `CacheableResult`. +- [2026-09-08 entry](#2026-09-08-stable-spec-page-caching-attributes-on-skills-list-and-skills-get-and-the-resources-capability-dependency), the previous alignment of the page's types with the base schema. diff --git a/index.md b/index.md index 7298974..222fd76 100644 --- a/index.md +++ b/index.md @@ -9,15 +9,15 @@ title: Overview - + - + - + - + - + For verification requirements and the skill-loading lifecycle, see [Integrity and Verification](/specification/stable/skills#integrity-and-verification). diff --git a/specification/stable/skills.mdx b/specification/stable/skills.mdx index 824c66b..9c71c42 100644 --- a/specification/stable/skills.mdx +++ b/specification/stable/skills.mdx @@ -28,9 +28,9 @@ This extension is identified as: `io.modelcontextprotocol/skills`. ## Protocol Revision -This page specifies the extension against base protocol revision `2026-07-28` or later. Type names it references without defining (`Result`, `PaginatedRequest`, `PaginatedResult`, `CacheableResult`, `Resource`, `Cursor`) are those of the base schema at that revision. +This page specifies the extension against base protocol revision `2026-07-28` or later. Type names it references without defining (`MetaObject`, `JSONRPCRequest`, `JSONRPCResultResponse`, `RequestParams`, `PaginatedRequest`, `PaginatedRequestParams`, `PaginatedResult`, `CacheableResult`, `Resource`) are those of the base schema at that revision. -For brevity, request examples omit `_meta`. Every request **MUST** include the required [request metadata](https://modelcontextprotocol.io/specification/2026-07-28/basic/index#_meta). +Every request **MUST** include the required [request metadata](https://modelcontextprotocol.io/specification/2026-07-28/basic/index#_meta) in `params._meta`. The request types below require it, and the request examples show it. ## Capability Negotiation @@ -184,6 +184,12 @@ interface Skill { * that stable digests cannot be published. */ resources: SkillResource[] | "dynamic"; + + /** + * See the base protocol's notes on `_meta` usage. Keys defined by this + * extension use the `io.modelcontextprotocol.skills/` prefix. + */ + _meta?: MetaObject; } ``` @@ -257,7 +263,16 @@ interface ListSkillsRequest extends PaginatedRequest { "jsonrpc": "2.0", "id": 4, "method": "skills/list", - "params": {} + "params": { + "_meta": { + "io.modelcontextprotocol/protocolVersion": "2026-07-28", + "io.modelcontextprotocol/clientInfo": { + "name": "ExampleClient", + "version": "1.0.0" + }, + "io.modelcontextprotocol/clientCapabilities": {} + } + } } ``` @@ -267,6 +282,10 @@ interface ListSkillsRequest extends PaginatedRequest { interface ListSkillsResult extends PaginatedResult, CacheableResult { skills: Skill[]; } + +interface ListSkillsResultResponse extends JSONRPCResultResponse { + result: ListSkillsResult; +} ``` ```json @@ -343,12 +362,14 @@ A server declaring this extension **MUST** implement the `skills/get` method, wh ### Request ```typescript -interface GetSkillRequest extends Request { +interface GetSkillRequestParams extends RequestParams { + /** URI of the skill's SKILL.md. */ + uri: string; +} + +interface GetSkillRequest extends JSONRPCRequest { method: "skills/get"; - params: { - /** URI of the skill's SKILL.md. */ - uri: string; - }; + params: GetSkillRequestParams; } ``` @@ -358,6 +379,14 @@ interface GetSkillRequest extends Request { "id": 5, "method": "skills/get", "params": { + "_meta": { + "io.modelcontextprotocol/protocolVersion": "2026-07-28", + "io.modelcontextprotocol/clientInfo": { + "name": "ExampleClient", + "version": "1.0.0" + }, + "io.modelcontextprotocol/clientCapabilities": {} + }, "uri": "skill://pdf-processing/SKILL.md" } } @@ -369,6 +398,10 @@ interface GetSkillRequest extends Request { interface GetSkillResult extends CacheableResult { skill: Skill; } + +interface GetSkillResultResponse extends JSONRPCResultResponse { + result: GetSkillResult; +} ``` ```json @@ -489,13 +522,14 @@ A _directory resource_ is a resource whose `mimeType` is `inode/directory`. In a ### Request ```typescript +interface ReadResourceDirectoryRequestParams extends PaginatedRequestParams { + /** URI of the directory resource to read. */ + uri: string; +} + interface ReadResourceDirectoryRequest extends PaginatedRequest { method: "resources/directory/read"; - params: { - /** URI of the directory resource to read. */ - uri: string; - cursor?: Cursor; - }; + params: ReadResourceDirectoryRequestParams; } ``` @@ -505,6 +539,14 @@ interface ReadResourceDirectoryRequest extends PaginatedRequest { "id": 7, "method": "resources/directory/read", "params": { + "_meta": { + "io.modelcontextprotocol/protocolVersion": "2026-07-28", + "io.modelcontextprotocol/clientInfo": { + "name": "ExampleClient", + "version": "1.0.0" + }, + "io.modelcontextprotocol/clientCapabilities": {} + }, "uri": "skill://pdf-processing/templates" } } @@ -513,10 +555,14 @@ interface ReadResourceDirectoryRequest extends PaginatedRequest { ### Response ```typescript -interface ReadResourceDirectoryResult extends PaginatedResult { +interface ReadResourceDirectoryResult extends PaginatedResult, CacheableResult { /** Resource metadata of the directory's direct children. */ resources: Resource[]; } + +interface ReadResourceDirectoryResultResponse extends JSONRPCResultResponse { + result: ReadResourceDirectoryResult; +} ``` ```json @@ -541,7 +587,9 @@ interface ReadResourceDirectoryResult extends PaginatedResult { "name": "regional", "mimeType": "inode/directory" } - ] + ], + "ttlMs": 300000, + "cacheScope": "public" } } ``` @@ -554,6 +602,7 @@ Semantics: - The result contains every direct child of the directory. Files carry their ordinary `Resource` metadata and subdirectories are listed as directory resources (`mimeType: "inode/directory"`). The listing is not recursive, and clients descend by calling the method again on a child directory. - An empty directory yields an empty `resources` array. - Pagination mirrors `resources/list`. When the result includes `nextCursor`, the client passes it back as `cursor` to retrieve the next page. +- `ReadResourceDirectoryResult` extends `CacheableResult`, so `ttlMs` and `cacheScope` are **REQUIRED**, as they are on `resources/list`, and carry the same semantics. They describe the freshness of the directory listing, not of the held entry, and do not alter [Directory Reads and the Held Entry](#directory-reads-and-the-held-entry). - A server that declares `directoryRead` **MUST** support the method for every directory within the skill namespaces it serves as individual files. - The method itself is not skill-specific, and a server **MAY** support it on any directory resource it serves, under any scheme. @@ -580,7 +629,16 @@ Consider a host connected to a server it labels `docs-server`, which declares th "jsonrpc": "2.0", "id": 2, "method": "skills/list", - "params": {} + "params": { + "_meta": { + "io.modelcontextprotocol/protocolVersion": "2026-07-28", + "io.modelcontextprotocol/clientInfo": { + "name": "ExampleClient", + "version": "1.0.0" + }, + "io.modelcontextprotocol/clientCapabilities": {} + } + } } ``` @@ -652,6 +710,14 @@ Later the model asks to load the skill. The host obtains user approval, binding "id": 3, "method": "resources/read", "params": { + "_meta": { + "io.modelcontextprotocol/protocolVersion": "2026-07-28", + "io.modelcontextprotocol/clientInfo": { + "name": "ExampleClient", + "version": "1.0.0" + }, + "io.modelcontextprotocol/clientCapabilities": {} + }, "uri": "skill://pdf-processing/SKILL.md" } } @@ -686,6 +752,14 @@ The instructions reference `templates/`. The model lists the directory, and the "id": 4, "method": "resources/directory/read", "params": { + "_meta": { + "io.modelcontextprotocol/protocolVersion": "2026-07-28", + "io.modelcontextprotocol/clientInfo": { + "name": "ExampleClient", + "version": "1.0.0" + }, + "io.modelcontextprotocol/clientCapabilities": {} + }, "uri": "skill://pdf-processing/templates" } } @@ -713,7 +787,9 @@ The instructions reference `templates/`. The model lists the directory, and the "name": "credit-note.md", "mimeType": "text/markdown" } - ] + ], + "ttlMs": 300000, + "cacheScope": "public" } } ``` @@ -737,6 +813,14 @@ To make `credit-note.md` available, the host refreshes the entry: "id": 6, "method": "skills/get", "params": { + "_meta": { + "io.modelcontextprotocol/protocolVersion": "2026-07-28", + "io.modelcontextprotocol/clientInfo": { + "name": "ExampleClient", + "version": "1.0.0" + }, + "io.modelcontextprotocol/clientCapabilities": {} + }, "uri": "skill://pdf-processing/SKILL.md" } }