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 | |
ListSkillsParams
Bases: PaginatedRequestParams
Parameters for skills/list.
Source code in src/mcp/shared/skills.py
138 139 | |
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
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | |
GetSkillParams
Bases: RequestParams
Parameters for skills/get.
Source code in src/mcp/shared/skills.py
166 167 168 169 170 | |
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
173 174 175 176 177 178 179 180 181 182 183 184 | |
ReadDirectoryParams
Bases: PaginatedRequestParams
Parameters for resources/directory/read.
Source code in src/mcp/shared/skills.py
187 188 189 190 191 | |
ReadDirectoryResult
Bases: PaginatedResult
Result of resources/directory/read.
Source code in src/mcp/shared/skills.py
194 195 196 197 | |
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
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | |
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
257 258 259 260 261 262 263 264 265 266 267 268 269 | |
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
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | |