feat(skills): add Skills-over-MCP host support (prototype)#1
Draft
feat(skills): add Skills-over-MCP host support (prototype)#1
Conversation
Adds the namespaced `extensions` field to `ServerCapabilities` so servers can declare extension capabilities under reverse-DNS keys (e.g. `io.modelcontextprotocol/skills`). Mirrors the existing `experimental` field shape but is the spec-recognized location for post-experimental extension declarations.
Implements the Codex host side of draft SEP openai#69 (`io.modelcontextprotocol/skills`). Each MCP server with `mcp_skills = true` in its config is asked for `skill://index.json` at connect time; listed `skill-md` entries have their SKILL.md frontmatter (name, description, optional short-description) fetched and merged into the existing filesystem-skills catalog with source annotations. The model surface is unchanged — skills served by MCP appear in the catalog as `(uri: <scheme>://..., server: <name>)` instead of `(file: ...)`, and bodies are fetched on demand via the pre-existing `read_mcp_resource(server, uri)` built-in tool. No new model-facing tool is added. Design choices: - URI scheme detection is generic (`<scheme>://`); servers may publish domain-native schemes such as `github://` instead of `skill://`. - Filesystem skills win on name collision; the masked MCP entry is logged with a user-visible warning. - `$Mention` of an MCP skill pushes a `SkillInstructions` item naming the exact `read_mcp_resource(server, uri)` call so first-turn activation is deterministic rather than catalog-heuristic-dependent. - A single session-scoped `McpConnectionManager` is shared between skill discovery and per-turn tool use (rather than a throwaway manager for discovery), avoiding duplicate stdio subprocess boots. - `mcp-resource-template` entries and `resources/subscribe` are deferred per the SEP's MAY/SHOULD wording; entries with unrecognized `type` are logged-and-skipped as the SEP requires. Server-side capability declaration under `capabilities.extensions["io.modelcontextprotocol/skills"]` (or the transitional `capabilities.experimental` location) is observed for logging only — discovery is not gated on it, again per SEP guidance. Tested against `olaservo/github-mcp-server@add-agent-skills` shipping the `pull-requests` skill; 35 unit tests cover catalog rendering, collision masking, URI validation, and frontmatter parsing.
ce9368d to
5a293c3
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.
Summary
Host-side implementation of the Skills-over-MCP SEP
(modelcontextprotocol/experimental-ext-skills#69,
io.modelcontextprotocol/skills). Skills served by connected MCPservers under
skill://(or any<scheme>://the server publishes)are discovered at session init, merged into the same
## Skillsmarkdown block that already lives inside
user_instructions, andloaded on demand through codex's existing
read_mcp_resource(server, uri)tool.SkillsManager, onerenderer, one dedup-by-name pass, one
SkillMetadata.codex-rs/core/src/tools/changed.mcp_skills, per MCP server, defaulttrue.Config
Catalog format
URI-backed entries render as
(uri: <scheme>://..., server: <name>)instead of
(file: ...). When any MCP skill is present a conditionalpreamble is prepended naming the read tool, the server-name
requirement, and the URI-rewrite prohibition. Filesystem-only sessions
see no prompt diff from upstream.
Code pointers
core/src/skills/mcp_loader.rs— new. Fetchesskill://index.jsonand per-entry SKILL.md viaresources/read;parses frontmatter through
loader::parse_skill_frontmatter_text;builds
SkillMetadatawithSkillScope::Mcp. Paralleljoin_allacross servers and per-server entries, 10s per-read timeout, 2048-byte
URI cap, control-character rejection. Entry
name/descriptionareadvisory — frontmatter is authoritative.
core/src/skills/loader.rs—parse_skill_frontmatter_textextracted from
parse_skill_fileso filesystem and MCP share oneYAML + length validation path.
core/src/skills/model.rs/protocol/src/protocol.rs—SkillMetadatagainsuri: Option<String>+server_name: Option<String>;SkillScope::Mcpvariant;SkillLoadOutcome:: add_mcp_skillswith filesystem-wins collision policy.core/src/skills/render.rs— branches onskill.uri.zip(skill.server_name); conditional preamble.core/src/skills/injection.rs—$Mentionof an MCP skill emits aSkillInstructionsitem naming the exactread_mcp_resource(server, uri)call instead of inlining SKILL.md.core/src/codex.rs—spawn_mcp_managerinitializes one sharedMcpConnectionManager;merge_mcp_skillsruns against it beforeuser_instructionsis frozen intoSessionConfiguration. Atx_mcp/rx_mcpforwarder preservesSessionConfiguredas thefirst event on the main stream.
core/src/config/types.rs—McpServerConfig.mcp_skills: bool(default
true), threaded through the customDeserializeimpl.core/src/mcp_connection_manager.rs/mcp-types/src/lib.rs—ServerCapabilitiesgainsextensions: Option<serde_json::Value>per SEP-2133; logs at
info!when a server declaresio.modelcontextprotocol/skillsunderextensionsorexperimental. Discovery is not gated on this log.Tests
codex-coreunit tests (4mcp_loader, 4render, 1config::types).codex-corelib tests, clippy, and rustfmt allclean.
olaservo/github-mcp-server@add-agent-skillswithgpt-5.1-codex-max: first tool call isread_mcp_resource({"server":"github-skills","uri":"skill://pull-requests/SKILL.md"}),model then cites the three-step review workflow
(
pull_request_review_write (create)→add_comment_to_pending_review→pull_request_review_write (submit_pending)) — names that exist only in SKILL.md, proving thebody reached the model.
mcp_skills = falseremoves the entry +preamble on the next rollout.
Known caveats / follow-ups
rmcpv0.12 dropscapabilities.extensionsduring deserializationbefore codex sees it, so the capability log fires only when a server
mirrors the declaration under
experimental. Discovery works eitherway per the SEP.
SkillMetadatastuffs the URI intopathplus separateuri+server_namefields to keep the diff additive against ~20 consumersites; a
SkillSource::File | ::Mcpenum would be cleaner.type: "mcp-resource-template"entries, a per-skill TUItoggle,
resources/subscribeon the index, eager-to-filesystemmaterialization.
Repo pointers
skills-over-mcp