Support the Skills extension (SEP-2640)
Mantenedores costumam responder em até 2 dias
@DaleSeo já está trabalhando nisso.
Desde 23/10/2026.
Avaliação
Esta issue ainda não foi avaliada.
Descrição
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 skips a skill over 512 files or 16 MiB, as the spec asks servers not to serve one.
- 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.
- Linguagem predominante
- Rust
- Estrelas
- 4.1k
- Forks
- 694
- Merge médio
- 3d 14h
- PRs com merge (30d)
- 39
Preparar o ambiente
Inicia o contêiner de desenvolvimento do projeto no navegador, com a sua própria conta do GitHub.
- Sem Dockerfile nem arquivo Docker Compose
- Sem modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de modelcontextprotocol/rust-sdk
-
auth: refresh_token() requests offline_access that was never granted, so refreshes fail with invalid_scopeTalvez já em andamento @jstar0 assumiu há 25 dias. Abertabug P1 ready for work T-security T-transport
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 65/100
modelcontextprotocol/rust-sdk#1330 ·
Mantenedores costumam responder em até 2 dias
-
OAuth discovery drops explicit default ports from advertised issuer identifiersTalvez já em andamento @gocamille assumiu há 2 dias. Abertabug P1 ready for work T-security T-transport
modelcontextprotocol/rust-sdk#1420 · 2 comentários · 1 responsável ·
Mantenedores costumam responder em até 2 dias
-
`register_client` drops `client_secret_expires_at` from the registration responseTalvez já em andamento @gocamille assumiu há 3 dias. Abertabug P2 ready for work T-security
modelcontextprotocol/rust-sdk#1416 · 1 comentário · 1 responsável ·
Mantenedores costumam responder em até 2 dias
-
Typed client calls drop the parse error when a reply misses a required fieldTalvez já em andamento @gocamille assumiu há 3 dias. Abertaenhancement P2 ready for work T-core T-service
modelcontextprotocol/rust-sdk#1415 · 1 comentário · 1 responsável ·
Mantenedores costumam responder em até 2 dias
-
Return merged cache hints from list_all_* client methodsTalvez já em andamento @gocamille assumiu há 4 dias. Abertaenhancement P2 ready for work T-service
modelcontextprotocol/rust-sdk#1411 · 1 comentário · 1 responsável ·
Mantenedores costumam responder em até 2 dias
Todas as issues de modelcontextprotocol/rust-sdk
Issues semelhantes
-
area:docs documentation good first issue priority:medium
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 78/100
rtk-ai/rtk#4958 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
feature
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
calagopus/panel#285 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
[Bug]: streamed Responses API flex_unavailable error maps to 500 InternalServerError instead of 429Abertallm translation
Dificuldade 2/5 Menos de uma hora Facilidade para iniciantes 85/100
BerriAI/litellm#49736 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
question
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 72/100
Mantenedores costumam responder em até 1 dia
-
autoindex tests: denied loopback bind shows only PermissionDenied (255 failures), not the causeAbertafield-report
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 70/100
Mantenedores costumam responder em até 1 dia