Support the Skills extension (SEP-2640)
维护者通常 3 天内回复
评估
这个 Issue 还没有评估数据。
描述
Summary
Add support for the Skills extension (SEP-2640, io.modelcontextprotocol/skills) to rmcp. The extension adds three methods: skills/list, skills/get, and the optional resources/directory/read. This issue covers both the server side and the client side.
- Spec: https://github.com/modelcontextprotocol/ext-skills/blob/main/specification/stable/skills.mdx
- Extension tracking issue: modelcontextprotocol/ext-skills#155
- Downstream: aaif-goose/goose#12068 needs the client side.
Requirements
A server built with rmcp can:
- Declare the extension in
capabilities.extensions, withdirectoryReadonly when it servesresources/directory/read. - Answer
skills/listandskills/getwith typed results, andresources/directory/readwhen declared. - Serve the files of a skill through
resources/read, so that the bytes match the size and digest in the manifest. - Return the error codes that the spec defines:
-32601for a method it does not serve,-32602for an unknown skill or a non-directory URI. - Send
ttlMsandcacheScopeto peers on protocol version 2026-07-28.
A client built with rmcp can:
- Detect the extension and its
directoryReadsetting from the server capabilities. - Call the three methods through typed
Peermethods, and receive server errors unchanged. - Verify a fetched file against the size and digest in the manifest.
Both sides pass the sep-2640-* conformance scenarios.
The spec targets protocol revision 2026-07-28 or later. rmcp also serves the methods to peers on an older revision and removes the cache hints from those responses, the same as the TypeScript, Python, and Go SDKs do. This needs the legacy strip helper to clear ttlMs and cacheScope as well as resultType, which also closes the same gap for the existing list results.
Proposal
This is how I plan to design and implement it. The choices below are open for discussion.
PR 1: protocol surface
Everything the spec defines, wired the same way as the tasks extension and without a feature flag.
- Model types for the skill manifest and the three methods in
model/skill.rs, with the matchingClientRequestandServerResultvariants.ReadResourceDirectoryResultis a type alias forListResourcesResult, andServerResultreuses the existingListResourcesResultvariant for it. No new directory variant: the two schemas are identical and the untaggedServerResultcannot tell them apart (see #771). - Three
ServerHandlermethods with capability-gated dispatch. Dispatch checks what the result object alone can show: the skill URI matches the request, the name matches the last URI segment, the manifest containsSKILL.mdand no duplicate URIs, and every digest has thesha256:form. A result that fails these checks returns-32603. Whether the bytes behind each URI match the manifest is checked by the catalog (PR 2) and by the host that reads them, not by dispatch. enable_skills()andenable_skills_with_directory_read()on the capability builder, with the matchingsupports_*getters. Skills requests fail with-32603when the server declares skills withoutresources, because the extension serves its files throughresources/read.- The matching
Peermethods for the client. They accept a 2026-07-28 response that omits the cache hints, the same aslist_toolsdoes today; the TypeScript and Go clients reject such a response, rmcp does not.SkillResource::verify(&[u8])checks the size and thesha256:digest of one file. Frontmatter verification againstskills/getis left to the host.sha2becomes a regular dependency of rmcp: it is pure Rust, already in the tree forrequest-state, and a client must not have to enable a filesystem feature to verify a download. - Integration tests through
Peerover a real transport: pagination acrossskills/list, a-32602fromskills/getarriving unchanged,read_resource_directorynot sent whendirectoryReadis absent, the directory result arriving asListResourcesResult, andverifyfailing on a wrong size and on a wrong digest. - Conformance fixtures with a nested skill, a subdirectory, and a
"dynamic"skill, and the scenarios inconformance.yml.
PR 2: filesystem catalog
Behind a skills-fs feature. SkillCatalog::from_dir walks a directory tree and builds the manifests.
- The catalog is a snapshot. It holds the file bytes and their digests, so
resources/readserves the same bytes that the manifest describes, even if the files change on disk later. reload()builds a new snapshot and swaps it in. If the rebuild fails, the old snapshot stays.- The walk rejects paths that leave the root, including through symlinks, and validates that each skill name matches its directory name. It warns at 512 files or 16 MiB.
- A nested skill appears in the listing on its own, and its files also appear in the manifest of the parent skill.
Follow-ups, not blocking
- PR 1 adds the two new results to the hand-written lists in
strip_result_type_for_legacy_peerandfill_missing_cache_hints. A non-breaking refactor right after PR 1 replaces both lists with a trait on each cacheable result and a dispatch thatts_union!generates, since the macro already enumerates everyServerResultvariant. - A
ResultEnvelope { result_type, meta, ttl_ms, cache_scope }flattened into each cacheable result, with the result structs marked#[non_exhaustive], so that the next mixin field from the spec is not a major release. Breaking, so it waits for the next major batch. - An
Extensiontrait for declaring and reading extension capabilities, so that each extension adds one impl instead of four functions. Skills and tasks move onto it. Non-breaking.
Acceptance
- The
sep-2640-*conformance checks pass on the fixture server. The PR body lists the numbers. - Goose can list, fetch, and verify remote skills through
Peerwithout custom requests. - For PR 2: a file served through
resources/readalways matches the manifest, a path outside the root is never served, and the files of a nested skill are listed in both manifests.
- 主要语言
- Rust
- 星标
- 4.1k
- 派生
- 680
- 平均合并
- 3 天 20 小时
- 30 天内合并 PR
- 32
环境准备
在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
modelcontextprotocol/rust-sdk 的其他 Issue
-
auth: refresh_token() requests offline_access that was never granted, so refreshes fail with invalid_scope可能已有人在做 @jstar0 于 20 天前认领。 未关闭bug P1 ready for work T-security T-transport
难度 2/5 1-3 小时 新手友好度 65/100
modelcontextprotocol/rust-sdk#1330 ·
维护者通常 3 天内回复
-
Enterprise-managed auth: ID-JAG `resource` claim should be optional可能已有人在做 @gocamille 于 1 天前认领。 未关闭bug P1 ready for work T-security T-transport
modelcontextprotocol/rust-sdk#1404 · 2 条评论 · 已指派 1 人 ·
维护者通常 3 天内回复
-
Auto discovery timeout rejects a late probe response during legacy initialization可能已有人在做 @gocamille 于 1 天前认领。 未关闭bug P1 ready for work T-service
modelcontextprotocol/rust-sdk#1400 · 1 条评论 · 已指派 1 人 ·
维护者通常 3 天内回复
-
URL mode elicitation requires elicitationId, which the 2026-07-28 schema removed可能已有人在做 @gocamille 于 2 天前认领。 未关闭bug P1 ready for work T-model
modelcontextprotocol/rust-sdk#1399 · 1 条评论 · 已指派 1 人 ·
维护者通常 3 天内回复
-
stdio transport: a request over the maximum line length gets no answer可能已有人在做 @gocamille 于 3 天前认领。 未关闭bug P1 ready for work T-transport
modelcontextprotocol/rust-sdk#1395 · 1 条评论 · 已指派 1 人 ·
维护者通常 3 天内回复
查看 modelcontextprotocol/rust-sdk 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 72/100
BurntSushi/jiff#668 ·
-
难度 2/5 1-3 小时 新手友好度 68/100
router-for-me/EasyCLIProxyAPI#534 ·
维护者通常 1 天内回复
-
bug
难度 2/5 1-3 小时 新手友好度 74/100
astral-sh/astral-codec#244 ·
维护者通常 1 天内回复
-
ready-for-agent
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复
-
bug dependencies kind:fix priority: P3 ready-for-agent
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 1 天内回复