{{ message }}
[Schema][Server] Add Skills extension (io.modelcontextprotocol/skills) support - #372
Draft
wachterjohannes wants to merge 3 commits into
Draft
wachterjohannes wants to merge 3 commits into
wachterjohannes wants to merge 3 commits into
Conversation
Contributor
Author
Contributor
Author
|
Updated to track the recent SEP-2640 redesign and to round out the index entries:
All green: phpstan (level 6), php-cs-fixer, 812 unit tests, inspector snapshot. Description updated accordingly. Remaining SEP surface, as a follow-up: the optional |
chr-hertel
added a commit
to symfony/ai
that referenced
this pull request
Jul 21, 2026
…or coding agents (wachterjohannes) This PR was squashed before being merged into the main branch. Discussion ---------- [Mate] Add skills:install to install extension skills for coding agents | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | Docs? | yes | Issues | - | License | MIT Agent Skills (`SKILL.md`) shipped by Mate extensions are now installed onto the filesystem where coding agents read them — a polyfill until skills can be served over MCP directly. ### Background — MCP Skills (SEP-2640) This is the **consumer/polyfill side** of the MCP Skills effort: - **SEP-2640** proposes serving Agent Skills over MCP's Resources primitive as `skill://` resources — modelcontextprotocol/modelcontextprotocol#2640. - **#2132** already added skill *content* to the Mate Symfony bridge, anticipating the extension (agentskills.io + SEP-2640 layout) — #2132. - **modelcontextprotocol/php-sdk#372** implements the *serving* half in the PHP SDK (`skill://` resources + discovery index). The missing piece is **getting those skills onto the filesystem**: Claude Code and other agents do not consume MCP-served skills yet (June 2026) — they only read skills from disk. This PR bridges that gap and can be retired once agents consume MCP-served skills end-to-end. ### How it works Extensions declare one or more skills directories via a new `extra.ai-mate.skills` key: ```json { "extra": { "ai-mate": { "scan-dirs": ["src"], "skills": ["skills"] } } } ``` Each immediate subdirectory holding a `SKILL.md` is one skill. Mate **symlinks** each one — under a `mate-` prefixed directory name (e.g. `mate-system-information`) to avoid clashing with skills you maintain from other sources — into `.agents/skills/` (read by Codex, OpenCode and GitHub Copilot) and mirrors it into `.claude/skills/` for Claude Code, which only reads its own directory. The links point into the gitignored `vendor/`, so skills auto-update on `composer update`. ### Usage Skills install automatically as part of `discover`, which already runs after `composer require`, so there's usually nothing to run: ```terminal $ vendor/bin/mate discover ``` For an explicit re-sync: ```terminal $ vendor/bin/mate skills:install ``` The core package ships a built-in `system-information` skill to demonstrate the format and dogfood the mechanism. ### Notes - Documentation added under `docs/components/mate.rst` and `docs/components/mate/creating-extensions.rst`; `CHANGELOG.md` updated. - Covered by tests (installer, command, discovery, and the `discover` auto-sync); PHPStan clean. Commits ------- 6a88faf [Mate] Add skills:install to install extension skills for coding agents
Member
|
Even without mate needing this, this could become interesting - keeping this open! I guess it needs a heavier rebase nowadays tho, since the extension part changed with v0.8.0 |
Contributor
Author
The ext-skills spec moved past PR modelcontextprotocol#372 before it was published as specification/stable/skills.mdx: discovery is no longer a skill://index.json resource but two mandatory RPC methods, skills/list and skills/get, each returning a complete {uri, digest, size} manifest of every file in the skill. This rewrites the extension to match, built directly against current main. McpSkills is now a full ExtensionInterface implementation contributing ListSkillsRequest/Result and GetSkillRequest/Result plus their handlers, backed by a SkillRegistry that SkillProvider populates while it registers skill:// resources. The old discovery-index and archive layer is gone along with SkillDiscoveryIndex/Entry and SkillArchive/Archiver, since no listing ever pointed at them once the index disappeared from the spec. SkillMetadata now requires description, matching the spec's Skill.frontmatter shape. The SKILL.md resource's name comes directly from the frontmatter name instead of a generated slug, since names don't need to be registry-unique. Extra frontmatter fields land under _meta as one io.modelcontextprotocol.skills/ prefixed key each, not one key holding the whole map. SkillProvider also enforces the extension's fixed per-skill limits (512 resources, 16 MiB) and records each file's byte size on its resource definition. Current main already carries the ServerCapabilities empty-extension-payload fix this PR originally introduced, independently.
…atch coverage, deterministic nested-skill registration skills/list and skills/get were only tested by calling the handlers directly, so nothing exercised the actual MessageFactory/StatelessProtocol/Rev2026Codec dispatch path or asserted the mandatory resultType/ttlMs/cacheScope envelope. Added a dispatch test that builds a real server and sends JSON-RPC requests over StatelessProtocol, covering both methods, the -32602 case, and the capability advertisement. SkillProvider also registered a nested skill's own SKILL.md twice as a servable resource: once as an anonymous supporting file of the enclosing skill (name from basename, no description) and once under its own frontmatter as its own top-level skill. Since the registry keeps the last registration for a given URI, which metadata won depended on filesystem sort order between the two directory names. The nested manifest is now registered exactly once, by its own entry, while still being listed in the enclosing skill's resources manifest as the spec requires. Added a nested-skill fixture pinning this. Clarified the McpSkills docblock: addSkillsFromDirectory() and manually enabling the extension are alternatives, not composable — combining them throws because the convenience method always tries to enable its own instance.
wachterjohannes
force-pushed
the
feature/skills-extension
branch
from
September 15, 2026 17:46
ea48413 to
95a4e20
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Skills extension (
io.modelcontextprotocol/skills, SEP-2640)Implements the Skills extension. SEP-2640 reached Final status and merged into the specification on 2026-09-13. A skill is a directory of files, at minimum a
SKILL.mdwith YAML frontmatter, served through the existing Resources primitive underskill://<skill-path>/<file-path>.Builder::addSkillsFromDirectory()walks a directory and registers every skill's files as resources, and enables the extension's two mandatory methods:skills/list, which enumerates the skills a server serves with a complete digest-and-size manifest per skill, andskills/get, which returns a single skill's entry by URI, including skills absent from the listing.The manifest lets a host build its registry, present a skill for approval, and verify every later read without a follow-up call.
skills/listresults carry the base protocol'sttlMs/cacheScopecaching attributes on protocol version2026-07-28and later, per the base list-caching mechanism (SEP-2549). Nested skills, aSKILL.mdinside another skill's directory, are supported per the spec: a nested skill gets its own top-level entry under its own frontmatter, and still appears in the enclosing skill's resource manifest.This PR was reworked from an earlier version built against a draft of the spec that used a discovery-index resource and packed archive distribution. The Core Maintainers removed both during review in favor of a complete resources manifest on every skill entry (see the SEP's Deferred Features appendix for the rationale); this implementation matches the Final spec text as merged.
Not implemented: the optional
resources/directory/readmethod and itsdirectoryReadcapability flag, which this PR does not declare. Adding it later is backward compatible.Adds
symfony/yamlfor frontmatter parsing. Docs are indocs/advanced/extensions.md, and a runnable example server is atexamples/server/skills/. phpstan, php-cs-fixer, and the full test suite (1822 tests) are green, including an inspector stdio snapshot test and a dispatch-level test that sends real JSON-RPC requests through the server and asserts the caching envelope.