Skip to content

Support publishing and retrieving Agent Skills over MCP #3655

Description

Proposal

I'd like us to support the Skills over MCP extension so our MCP servers can publish workflow instructions alongside their tools. Start with skills bundled and versioned with Azure MCP Server, with the protocol support structured for reuse by other servers in this repo.

The server supplies the skill. The host discovers, verifies, and loads it. We should not require the server to install files into a client's skills directory or introduce a custom download tool for functionality the extension already defines.

Problem

Tools expose individual operations, but they do not always provide enough guidance for a workflow that spans several operations. Maintaining that guidance separately from the server creates another installation step and allows instructions to drift from the tools they describe.

Shipping skills with the server keeps the instructions and tool implementations aligned. A compatible host can discover the available workflows and load the relevant instructions when needed.

Proposed behavior

The server would declare Resources support and the io.modelcontextprotocol/skills extension, then implement:

  • skills/list to expose skill frontmatter and complete file manifests, including SHA-256 digests and byte sizes.
  • skills/get to retrieve a skill entry directly by URI, including skills not returned by the listing.
  • resources/read to return SKILL.md and supporting files on demand.

Directory reading is optional in the extension and can remain out of the initial implementation unless a supported client requires it.

For example, a deployment diagnostics skill could describe the investigation sequence, reference troubleshooting guidance, and direct the agent to the appropriate MCP tools. The host retrieves the instructions first and supporting files only as needed. Reading a skill does not activate it or execute its scripts.

Local MCP behavior

This should work over stdio as well as HTTP. A locally running server reads bundled skill content and returns it through MCP. It does not need an HTTP endpoint or a shared filesystem with the host, so the same approach works when the server runs in a container or WSL.

Retrieving bundled skills should not require network access. The operations described by a skill may still require Azure connectivity and authorization.

The host owns skill activation, approval, and caching. The server should not write into the user's repository or client-specific skill directories. MCP resource URIs identify published content, not arbitrary paths on the server's filesystem.

Scope and boundaries

Start with static, bundled skills and manifests generated from the exact bytes served. Defer upstream catalogs, independently updated skills, dynamic content, and a separate installation or export experience.

Follow the extension's integrity and origin requirements rather than inventing a parallel trust model. Hosts must retain server identity and skill URI, verify retrieved content, and apply the required approvals. Serving a script does not authorize its execution, and a skill does not grant additional tool permissions.

Client support is a dependency. Confirm the protocol revision, SDK support, and intended host's implementation before committing to the integration. Clients without Skills support must continue to use existing tools normally; exposing resources alone does not provide native skill activation.

Acceptance criteria

  • A packaged example skill can be discovered and retrieved through the extension over stdio and HTTP.
  • Direct lookup works without a preceding list request.
  • Manifests include every published skill file, with digests and byte sizes matching the served content.
  • Resource reads are limited to explicitly published content. Unknown skills and files return the specified protocol errors.
  • Bundled skill retrieval works without network access and does not write to client or repository skill directories.
  • Tests cover discovery, direct lookup, content retrieval, manifest consistency, and rejection of unpublished paths.
  • Existing tool behavior remains unchanged for clients that do not support the extension.
  • Documentation identifies the supported protocol and client prerequisites, local behavior, and the boundary between retrieving, activating, and executing skill content.

References

Activity

  1. added
    needs-team-attentionWorkflow: This issue needs attention from Azure service team or MCP team.
    tools-CoreAZMCP Core functionality that all other tools build on top of
    on Sep 14, 2026
  2. github-actions commented on Sep 14, 2026

    @github-actions
    Contributor

    Thanks for the feedback! We are routing this to the appropriate team for follow-up. cc Alan Zimmer (@alzimmermsft) Vinay Gera (@g2vinay) @microsoft/azure-mcp.

  3. tmeschter commented on Sep 15, 2026

    @tmeschter
    Member

    Per the client support matrix there is very little support for skills-over-MCP at the moment. We would be able to use verification tools to check that we are implementing the standard, but for the clients we currently target with skills there would be no way to test the end-to-end experience.

  4. tmeschter commented on Sep 17, 2026

    @tmeschter
    Member

    Also, the C# MCP SDK does not yet support the proposed spec. The work is being tracked by modelcontextprotocol/csharp-sdk#1863, with a proposed implementation in modelcontextprotocol/csharp-sdk#1864.

  5. RickWinter commented on Oct 16, 2026

    @RickWinter
    MemberAuthor

    Here is an implementation and testing plan for supporting io.modelcontextprotocol/skills (SEP-2640) in Azure MCP Server and aligning with the client runtime support in https://github.com/github/copilot-agent-runtime/pull/25177.

    1. Specification & Client (github/copilot-agent-runtime#25177) Requirements

    Protocol Contract (io.modelcontextprotocol/skills / SEP-2640)

    1. Capability Negotiation (initialize in 2025-11-25 and server/discover in 2026-07-28):
      "capabilities": {
        "resources": {},
        "extensions": {
          "io.modelcontextprotocol/skills": {}
        }
      }
      • Optional for clients: clients that do not understand io.modelcontextprotocol/skills ignore the extension key and continue using tools as normal.
    2. URI Convention:
      • Root skill URI: skill://<skill-path>/SKILL.md, with supporting files at skill://<skill-path>/<relative-path>.
      • The final path segment of <skill-path> must match frontmatter.name (^[a-z0-9]+(-[a-z0-9]+)*$, 1 to 64 characters).
    3. Discovery & Lookup (skills/list, skills/get):
      • skills/list (cursor-paginated) returns Skill entries without downloading full markdown bodies:
        • uri: "skill://<skill-path>/SKILL.md"
        • frontmatter: verbatim JSON object parsed from SKILL.md YAML frontmatter (at minimum name and description <= 1024 chars).
        • resources: static array of { uri, digest: "sha256:<64-lowercase-hex>", size: <raw-byte-length> } covering SKILL.md and every supporting file.
      • skills/get ({ uri }) returns { skill } directly by SKILL.md URI without requiring a prior skills/list call, or JSON-RPC -32602 (InvalidParams) if unknown.
      • Per-skill bounds: <= 512 files (resources.length <= 512) and <= 16 MiB (16,777,216 bytes) total size.
      • Under 2026-07-28, skills/list and skills/get include CacheableResult metadata (resultType: "complete", ttlMs, cacheScope: "public").
    4. Content Retrieval (resources/read, resources/list):
      • Serves SKILL.md and supporting files on demand as TextResourceContents (mimeType: "text/markdown" for .md) or BlobResourceContents. Unknown URIs return -32602 (InvalidParams).

    Client Runtime Expectations (github/copilot-agent-runtime#25177)

    • Static manifest requirement: The runtime rejects "resources": "dynamic" because dynamic skills cannot be integrity-pinned before user consent. Publishing static SkillResource[] manifests is required and allows the client to synthesize directory listings locally from entry.resources without requiring resources/directory/read.
    • Strict 3-way verification on activation:
      1. Prompts user consent bound to (serverName, uri) and the manifest's { uri, digest } set.
      2. Reads SKILL.md via resources/read and verifies:
        • Raw UTF-8 byte length equals manifest.size.
        • sha256:<lowercase-hex> of raw UTF-8 bytes equals manifest.digest.
        • Parsed YAML frontmatter of SKILL.md deep-equals entry.frontmatter from skills/list / skills/get.
      3. Exposes a client-side read_resource tool for supporting files that rejects any URI not listed in entry.resources and verifies size + digest on every read.

    2. Implementation Plan

    SDK Note: Upstream modelcontextprotocol/csharp-sdk#1856 (ModelContextProtocol.Extensions.Skills) is still open and not yet in ModelContextProtocol 2.2.0. We can implement the protocol wiring in Microsoft.Mcp.Core using ModelContextProtocol 2.2.0 public APIs (McpServerOptions.Capabilities.Extensions, Capabilities.Resources, RequestHandlers.Set, Handlers.ReadResourceHandler, and Handlers.ListResourcesHandler) with models matching #1856 so we can swap to the upstream package once released.

    Phase 1: Core Models, Validator & Frontmatter Parser (Microsoft.Mcp.Core)

    • Location: core/Microsoft.Mcp.Core/src/Areas/Server/Skills/
    • AOT-safe Protocol Models & McpSkillsJsonContext:
      • McpSkillCapability, McpSkill, McpSkillResource, ListSkillsRequestParams, ListSkillsResult (inherits PaginatedResult), GetSkillRequestParams, GetSkillResult (inherits CacheableResult).
    • Frontmatter & Integrity Pipeline (SkillPackageBuilder / SkillFrontmatterParser):
      • Zero-dependency, AOT-safe YAML frontmatter parser producing a JsonObject directly from the in-memory SKILL.md UTF-8 bytes.
      • Computes size and sha256:<lowercase-hex> from the exact in-memory UTF-8 byte[] served by resources/read (preventing CRLF/LF mismatches between digest calculation and content delivery).
      • Enforces spec invariants at load time: valid name regex, <skill-path> leaf matches frontmatter.name, non-empty description <= 1024 chars, <= 512 files, <= 16 MiB per skill.

    Phase 2: Secure-by-Default Runtime Handlers & Options (Microsoft.Mcp.Core)

    • ISkillProvider & McpSkillsRuntime (core/Microsoft.Mcp.Core/src/Areas/Server/Skills/):
      • Immutable, ordinal-keyed lookup tables (Dictionary<string, SkillPackage> and Dictionary<string, SkillFileContent> with StringComparer.Ordinal).
      • No runtime filesystem I/O: Serves only pre-registered embedded/in-memory skill bytes; never reads or writes host/client paths.
      • Fail-closed URI validation: Any unknown URI, non-skill:// scheme, or path-traversal sequence (.., \, percent-encoded segments) in skills/get or resources/read immediately throws McpProtocolException with McpErrorCode.InvalidParams (-32602).
      • Namespace filtering: Each SkillPackage can optionally declare its owning service namespace(s) (for example, azurebackup), so --namespace filtering on azmcp server start filters skills consistently with tools while retaining global/cross-service skills.
      • Optional server flag: Add --disable-skills to ServerStartOptions (default false) so operators can disable skill publishing when needed.
    • Wire into ServiceCollectionExtensions.ConfigureMcpServerOptions:
      • When skills are enabled and at least one skill is registered:
        • Set options.Capabilities.Resources ??= new ResourcesCapability() and options.Capabilities.Extensions["io.modelcontextprotocol/skills"] = new JsonObject().
        • Register skills/list and skills/get via options.RequestHandlers.Set(...) with CacheScope.Public and TimeToLive = TimeSpan.FromHours(1).
        • Register options.Handlers.ListResourcesHandler and options.Handlers.ReadResourceHandler.
        • Emit OpenTelemetry activities (ActivityName.ListSkills, ActivityName.GetSkill, ActivityName.ReadSkillResource) with W3C trace context capture matching McpRuntime.

    Phase 3: Bundled Skills in Azure.Mcp.Server

    • EmbeddedSkillProvider:
      • Embeds curated Azure MCP skills (SKILL.md + references/ + scripts/) as assembly resources in Azure.Mcp.Server and registers the provider in servers/Azure.Mcp.Server/src/Program.cs.

    3. Testing Strategy

    1. Unit Tests (Microsoft.Mcp.Core.Tests & Azure.Mcp.Core.Tests):
      • Spec & Frontmatter Validation: Valid/invalid skill names, path-leaf vs. frontmatter.name mismatch, missing name/description, description > 1024 chars, > 512 files limit, > 16 MiB size limit, and YAML frontmatter edge cases (quotes, multiline blocks, nested objects/arrays).
      • Client Conformance / Integrity Check Suite: Run the exact 3 checks from github/copilot-agent-runtime#25177 across every registered skill and supporting file:
        1. Encoding.UTF8.GetByteCount(text) == resource.Size
        2. SHA256(Encoding.UTF8.GetBytes(text)) == resource.Digest
        3. ParseYamlFrontmatter(skillMdText) deep-equals skill.Frontmatter
      • Handler & Security Negative Tests:
        • skills/list deterministic ordering and cursor / nextCursor pagination; invalid cursor returns -32602.
        • skills/get works without prior skills/list; returns -32602 for missing uri, unknown skill, supporting-file URI instead of SKILL.md, or traversal attempts (skill://foo/../bar/SKILL.md, skill://foo/%2e%2e/SKILL.md, skill://foo\bar/SKILL.md).
        • resources/read serves exact UTF-8 text (text/markdown for .md) and binary blobs; returns -32602 for unlisted/unknown URIs.
      • Optionality & Mode Tests:
        • Verify --disable-skills (or zero registered skills) omits io.modelcontextprotocol/skills from capabilities.
        • Verify --namespace filters skills appropriately and all server modes (namespace, all, single, consolidated) preserve existing tool behavior for clients that ignore skills.
    2. Protocol & Transport Integration Tests (Azure.Mcp.Server.Tests):
      • Stdio & HTTP across 2025-11-25 and 2026-07-28:
        • Verify initialize (2025-11-25) and stateless server/discover (2026-07-28) advertise resources and extensions["io.modelcontextprotocol/skills"].
        • Verify 2026-07-28 HTTP routing headers (ValidateMcpRoutingHeadersMiddleware): skills/list and skills/get succeed with Mcp-Method alone; resources/read succeeds with Mcp-Method: resources/read + Mcp-Name: skill://... and is rejected (400) when Mcp-Name is missing.
        • Verify authenticated HTTP mode requires McpAccess authorization on skills/list, skills/get, and resources/read.
    3. AOT & E2E Validation:
      • Run ./eng/scripts/Build-Local.ps1 -BuildNative to verify zero AOT/trim warnings.
      • Validate E2E with COPILOT_MCP_SKILLS=1 discovering, consenting to, integrity-checking, and activating a skill from azmcp server start.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

enhancementNew feature or requestneeds-team-attentionWorkflow: This issue needs attention from Azure service team or MCP team.server-Azure.McpAzure.Mcp.Servertools-CoreAZMCP Core functionality that all other tools build on top of

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions