You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 6b0870c
Browse filesBrowse the repository at this point in the historyBrowse files
Add ICacheableResult and source-generated cache-hint serialization to
skills/get. Apply the configured hints or zero/private defaults on
2026-07-28 requests, and keep all versioned fields off 2025-11-25 replies.
Read scalar values starting on the next line, preserve folded line breaks
around TAB-led content, and reject comments without whitespace after a
quoted scalar or flow collection. Keep plain hashes, existing chomping
rules and non-JSON number rejection intact.
Add parser, authoring, wire and serialization regressions. Exercise the
new cache fields and authoring cases in the native AOT app. Update the
cache option docs and pin both sample links to their published source.
Copy file name to clipboardExpand all lines: docs/concepts/skills/skills.md
+60-19Lines changed: 60 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,8 +31,19 @@ A skill entry (<xref:ModelContextProtocol.Extensions.Skills.Skill>) is a complet
31
31
that cannot be digested.
32
32
33
33
A host builds its registry from entries alone, then fetches files lazily with `resources/read` and verifies each
34
-
one against the manifest. That verification, and the rule that an unlisted file is a change to the skill, is what
35
-
lets a user's approval bind to specific content.
34
+
one against the manifest. Before loading `SKILL.md`, it must also parse the fetched YAML and compare every
35
+
frontmatter field with the held entry. Digest and size verification alone does not establish that equality.
36
+
37
+
### Responsibility boundaries
38
+
39
+
The protocol carries structured metadata; it does not require a particular parser or provider.
40
+
41
+
| Layer | Responsibility |
42
+
|---|---|
43
+
| Application / catalog | Supply frontmatter identical to the complete frontmatter in the file, and serve matching file bytes and manifests. Structural entry validation does not read or validate the YAML on a catalog's behalf. |
44
+
| Optional automatic authoring helper |`McpServerSkill.Create` / `CreateFromDirectory` without explicit metadata use the bounded `SkillFrontmatter` reader. Unsupported or malformed input is rejected, not replaced with guessed metadata. |
45
+
| Explicit-metadata authoring | Keep the helper's enforced checks. If the bounded reader cannot fully read unsupported YAML, the application must parse and validate the entire frontmatter with a suitable mechanism and supply the correct JSON. |
46
+
| Host | Independently parse fetched `SKILL.md` and compare its frontmatter with the held entry before loading, regardless of server authoring path. Reject unsupported input or use a suitable full parser; server-provided JSON is not verification. |
36
47
37
48
### Serving skills
38
49
@@ -75,7 +86,7 @@ var refunds = McpServerSkill.Create(
All of these validate the skill against the specification and throw <xref:System.ArgumentException> with a
89
+
All of these validate structural entry and file constraints and throw <xref:System.ArgumentException> with a
79
90
specific message when, for example, the frontmatter `name` does not match the URI, `description` exceeds the
80
91
Agent Skills limit of 1024 characters, a resource URI escapes the skill's directory, `SKILL.md` is missing, or
81
92
the skill exceeds the per-skill limits of 512 files or 16 MiB. Frontmatter fields beyond `name`, `description`,
@@ -88,20 +99,28 @@ names containing characters with URI syntax (such as `{`, `?`, or a space) are p
88
99
#### Frontmatter
89
100
90
101
<xref:ModelContextProtocol.Extensions.Skills.SkillFrontmatter> reads the YAML frontmatter of a `SKILL.md` into a
91
-
<xref:System.Text.Json.Nodes.JsonObject> without a YAML library. It accepts the subset of YAML that Agent Skills
92
-
frontmatter uses: block mappings (nested up to 32 levels), block and flow sequences, plain, quoted, and block
102
+
<xref:System.Text.Json.Nodes.JsonObject> without a YAML library. This is an optional bounded reader, not a
103
+
requirement for serving structured metadata through a catalog. It supports block mappings (nested up to 32 levels), block and flow sequences, plain, quoted, and block
93
104
scalars, and comments. Unquoted scalars are resolved per the YAML 1.2 core schema (`null`, booleans, integers, finite
94
-
floats, otherwise strings), matching the YAML libraries used by other SDKs and by hosts. That matters because a
105
+
floats, otherwise strings). YAML parsers can differ in their supported forms and resolution; identical semantics
106
+
across other SDKs or libraries are not assumed. That matters because a
95
107
host verifies a skill by parsing the fetched `SKILL.md` itself and comparing field by field against the published
96
108
entry; a value that one side types as a number and the other as a string is a verification failure. Quote values
97
109
such as version numbers that are meant to be strings.
98
110
99
-
Anchors, aliases, tags, complex keys, nested and multi-line flow collections, and multi-line quoted scalars are
100
-
valid YAML the reader does not support; it rejects them with a <xref:System.FormatException> naming the construct. For such a
101
-
file, the `Create` and `CreateFromDirectory` overloads that take an explicit `JsonObject` supply the frontmatter
102
-
directly. That escape hatch covers only valid-but-unsupported YAML: a file with no frontmatter block, malformed
103
-
YAML, or invalid UTF-8 is rejected regardless, since no host could parse it either. When the reader can parse the
104
-
file, an explicit object must match it exactly, or the skill is rejected at construction rather than by every host.
111
+
Automatic authoring requires the bounded reader to succeed. Unsupported constructs and detected malformed input
112
+
raise an error; no fallback object is invented. Unsupported forms include anchors, aliases, tags, complex keys,
113
+
nested and multi-line flow collections, and multi-line quoted scalars.
114
+
115
+
The explicit `JsonObject` overloads retain UTF-8 and frontmatter-boundary checks, entry/URI validation, and manifest
116
+
digest/size computation from the served bytes. They also reject format errors detected by the reader and reject
117
+
metadata that differs from a frontmatter block the reader can parse completely.
118
+
119
+
**The explicit overloads do not guarantee whole-document YAML validation.** An unsupported construct can stop
120
+
parsing before later content is examined. The application must parse and validate the **entire frontmatter**
121
+
with a suitable mechanism and supply identical JSON before relying on that path. An unsupported-format error
122
+
is not proof that the rest of the document is valid, and acceptance of supplied metadata is not proof of equality.
123
+
This boundary does not relax the specification's requirement that published frontmatter match the file.
105
124
106
125
#### Custom catalogs
107
126
@@ -128,7 +147,9 @@ the caller's <xref:System.Security.Claims.ClaimsPrincipal> when the transport su
128
147
transport does), and any items that incoming-message filters attached to the request.
129
148
130
149
A catalog supplies entries only; the skills' files must still be served as resources, since hosts read them with
131
-
`resources/read`. A catalog may list only part of what it serves, or nothing at all, as long as `GetAsync` answers
150
+
`resources/read`. The application/catalog author must supply frontmatter identical to the file. The transport
151
+
validates entry structure, not full file contents, and does not require use of the optional authoring reader.
152
+
A catalog may list only part of what it serves, or nothing at all, as long as `GetAsync` answers
132
153
for every skill the server serves to the caller. Throw <xref:ModelContextProtocol.McpProtocolException> with
133
154
<xref:ModelContextProtocol.McpErrorCode.InvalidParams> for a cursor the catalog cannot interpret.
134
155
<xref:ModelContextProtocol.Extensions.Skills.InMemoryMcpSkillCatalog> is the built-in implementation over a fixed
@@ -139,14 +160,16 @@ set of entries and can be composed into a custom one.
139
160
A skill whose content is generated on demand cannot publish stable digests. Set its entry's `Resources` to
140
161
<xref:ModelContextProtocol.Extensions.Skills.SkillResources.Dynamic> and serve it through a catalog. Such a skill
141
162
offers no content integrity, and hosts may decline to load it.
163
+
If a host accepts a dynamic skill, parsing and comparing its fetched frontmatter is still required.
142
164
143
165
#### Protocol versions and caching hints
144
166
145
-
`skills/list` results carry the base protocol's `ttlMs` and `cacheScope`list-caching attributes, configured through
167
+
`skills/list`and `skills/get`results carry the base protocol's `ttlMs` and `cacheScope` caching attributes, configured through
146
168
<xref:ModelContextProtocol.Extensions.Skills.McpSkillsOptions>. Those attributes, and `resultType`, are defined
147
169
from protocol revision `2026-07-28`. The SDK emits them only on requests negotiated under that revision or later,
148
170
where they are required and default to `0` and `private` when unset, the same conservative defaults the built-in
149
-
list methods use. On earlier revisions, which reject them as unrecognized keys, they are omitted.
171
+
list methods use. On earlier revisions, which reject them as unrecognized keys, they are omitted. Both methods use
172
+
the same configured hints. Only use `public` when both the listing and individual entries are identical for every caller.
0 commit comments