skills
Wire types and SEP-2640 conformance checks for the Skills extension.
Shared by the server (mcp.server.skills) and client (mcp.client.extensions.skills)
surfaces, mirroring how mcp.shared.extension hosts the identifier grammar
both tiers need. See https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640.
EXTENSION_ID
module-attribute
EXTENSION_ID = 'io.modelcontextprotocol/skills'
The Skills extension identifier, advertised under ServerCapabilities.extensions.
MAX_RESOURCES_PER_SKILL
module-attribute
MAX_RESOURCES_PER_SKILL = 512
SEP-2640 per-skill resource-count threshold (SKILL.md included).
A SHOULD NOT limit, not a hard cap: the spec requires a host to support skills
up to and including 512 entries and permits it to support larger ones, so a
Skill does not reject an over-count manifest.
MAX_TOTAL_SIZE
module-attribute
MAX_TOTAL_SIZE = 16 * 1024 * 1024
SEP-2640 per-skill total-byte-size threshold (16 MiB), summed over resources[].size.
A SHOULD NOT limit, not a hard cap (see MAX_RESOURCES_PER_SKILL); an over-size
manifest is not rejected.
SkillResource
Bases: _SkillModel
One file in a skill's manifest: {uri, digest, size}.
Shape rules are intrinsic: a digest that isn't sha256: + 64 lowercase
hex characters, or a negative size, is rejected at construction.
Source code in src/mcp/shared/skills.py
71 72 73 74 75 76 77 78 79 80 81 82 | |
Frontmatter
module-attribute
A skill's SKILL.md YAML frontmatter, rendered verbatim as JSON.
SkillResources
module-attribute
SkillResources = list[SkillResource] | Literal['dynamic']
A skill's complete resource manifest, or the "dynamic" marker (SEP-2640 Resources).
Skill
Bases: _SkillModel
An entry returned by skills/list or skills/get.
SEP-2640 conformance is intrinsic: constructing (or parsing) a Skill
validates the frontmatter name/description, and — unless resources is
"dynamic" — that every entry names a file within the skill's own directory,
with no duplicates and SKILL.md present. The MAX_RESOURCES_PER_SKILL
(512-entry) and MAX_TOTAL_SIZE (16-MiB) limits are SHOULD NOT thresholds,
not MUST NOT, so an over-limit manifest is accepted.
Source code in src/mcp/shared/skills.py
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | |
ListSkillsParams
Bases: PaginatedRequestParams
Parameters for skills/list.
Source code in src/mcp/shared/skills.py
140 141 | |
ListSkillsResult
Bases: PaginatedResult, CacheableResult
Result of skills/list.
Each skill self-validates; on top of that, constructing (or parsing) this
result rejects two entries that share a uri.
ttl_ms/cache_scope are SEP-2549 fields inherited from CacheableResult;
unlike a core spec method, nothing sieves them off the wire for a
pre-2026-07-28 connection automatically (see mcp.server.skills), so
callers constructing this directly for such a connection must omit them.
Source code in src/mcp/shared/skills.py
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | |
GetSkillParams
Bases: RequestParams
Parameters for skills/get.
Source code in src/mcp/shared/skills.py
168 169 170 171 172 | |
GetSkillResult
Bases: CacheableResult
Result of skills/get.
Like ListSkillsResult, this extends CacheableResult: the stable spec page
makes GetSkillResult carry SEP-2549's ttl_ms/cache_scope, the same
freshness hint resources/read gives. As on skills/list, nothing sieves
these fields off the wire for a pre-2026-07-28 connection automatically (see
mcp.server.skills), so a caller constructing this directly for such a
connection must omit them.
Source code in src/mcp/shared/skills.py
175 176 177 178 179 180 181 182 183 184 185 186 | |
ReadDirectoryParams
Bases: PaginatedRequestParams
Parameters for resources/directory/read.
Source code in src/mcp/shared/skills.py
189 190 191 192 193 | |
ReadDirectoryResult
Bases: PaginatedResult, CacheableResult
Result of resources/directory/read.
Like ListSkillsResult, this carries SEP-2549's ttl_ms/cache_scope, which
mcp.server.skills strips for a pre-2026-07-28 connection.
Source code in src/mcp/shared/skills.py
196 197 198 199 200 201 202 203 | |
skill_name_from_uri
Return the skill name encoded in a SKILL.md resource URI.
Per SEP-2640 Resource Mapping, the final <skill-path> segment equals the
skill's name; for a bare skill://<name>/SKILL.md (no organizational
prefix) that segment is the authority.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/mcp/shared/skills.py
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | |
parse_directory_uri
Split a directory resource URI into (scheme, netloc, path).
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/mcp/shared/skills.py
263 264 265 266 267 268 269 270 271 272 273 274 275 | |
validate_directory_result
validate_directory_result(
uri: str, result: ReadDirectoryResult
) -> None
Validate that each entry in result.resources is a unique direct child of uri.
Checks containment and shape only — that every listed resource is a direct
child of uri with a unique uri. It cannot confirm the listing
is exhaustive, since it has no independent view of the directory's contents.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/mcp/shared/skills.py
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 | |