Au 06/11/2026, le MCP TypeScript SDK 2.4.0 (23/10/2026) intègre SEP-2640 Skills over MCP dans @modelcontextprotocol/server/ext/skills et client/ext/skills. Le serveur monte des dossiers avec loadSkills(folder) ; le client utilise SkillsClient pour skills/list, skills/get et resources/read. Avant d'injecter SKILL.md dans le contexte, l'hôte doit traiter size + digest SHA-256 + frontmatter du listing comme second contrat — non interchangeable avec inputSchema de tools/list. Retours d'outil : outputSchema et structuredContent. Manuels malveillants : fake skills.
Beaucoup d'équipes voient d'abord les skills comme des dossiers Markdown lus localement. Une fois MCP en jeu, les octets viennent du réseau ou d'un serveur distant — sans digest, c'est la même classe de risque que faire confiance à n'importe quelle description d'outil. Le SDK 2.4.0 encode la vérification côté client ; la couche policy décide encore quels URI de skill charger et si un skill chargé peut déclencher des outils à privilèges élevés.
Ce que le SDK 2.4.0 apporte le 23 oct.
- Serveur :
SkillsExtension.attach(server)exposeskills/list,skills/get,resources/directory/readet le modèleskill://{+path}; côté Node,loadSkills('./skills')scanne les répertoires, skills invalides ignorés par défaut (warn),strictfait échouer tout le paquet. - Client :
SkillsClientaveclist(),get(),read(),readDirectory();readlit par défaut leSKILL.mddu skill. - Protocole : support
2025-11-25et2026-07-28; ce dernier ajoutettlMsetcacheScopesur les pages de listing — champs manquants → erreur SDK. - Stabilité :
attachest@experimental; le reste des API Skills et les schemas danscore/ext/skillssont stable.
En une phrase. Un skill est un « paquet de ressources avec digest », pas un « system prompt sans contrôle ». Les tools restent des « RPC avec inputSchema ».
Métadonnées dans skills/list
Chaque entrée est du JSON : URI, nom affiché, liste de fichiers, pour chaque fichier size et digest (SHA-256), plus le frontmatter parsé depuis SKILL.md. Exemple aligné sur la doc SDK (noms de champs selon SEP-2640 / SDK ; vérifier votre version de protocole à l'intégration) :
{
"skills": [
{
"uri": "skill://deploy/runbook/",
"name": "deploy-runbook",
"description": "Production deploy checklist",
"root": {
"path": "SKILL.md",
"size": 2048,
"digest": "sha256:abc123…",
"mimeType": "text/markdown"
},
"files": [
{
"path": "SKILL.md",
"size": 2048,
"digest": "sha256:abc123…"
},
{
"path": "references/rollback.md",
"size": 890,
"digest": "sha256:def456…"
}
],
"frontmatter": {
"name": "deploy-runbook",
"description": "Production deploy checklist"
}
}
],
"ttlMs": 300000,
"cacheScope": "session"
}
list() pagine jusqu'à absence de cursor ; URI dupliquées ou entrées invalides lèvent SdkError par défaut, ou skipInvalid: true avec tableau invalid. Traitez invalid comme signal de sécurité, pas comme bruit à ignorer.
Ce que SkillsClient.read vérifie
Le client officiel applique trois contrôles avant de remettre le texte à l'agent :
- Appartenance au listing : le chemin demandé doit figurer dans
files; le serveur ne peut pas ajouter des fichiers non déclarés. - size + digest : longueur et hash des octets lus doivent correspondre au listing ; sinon
SkillVerificationError. - Frontmatter SKILL.md : pour le Markdown racine du skill, le frontmatter doit correspondre au listing.
Si la réponse vient du cache client et échoue la vérification, le SDK tente d'abord cacheMode: 'refresh'. Les skills marqués dynamic ignorent listing/size/digest (verified: false) mais vérifient encore le frontmatter — allowlist séparée côté hôte pour les skills dynamic.
{
"read_ok": {
"path": "SKILL.md",
"verified": true,
"text": "---\nname: deploy-runbook\n---\n# Checklist\n"
},
"read_fail_digest": {
"path": "SKILL.md",
"error": "SkillVerificationError",
"reason": "digest mismatch vs skills/list"
},
"read_fail_extra_file": {
"path": "references/evil.sh",
"error": "not in listing.files"
}
}
Division du travail avec JSON Schema
Dans la même session, trois contrats JSON coexistent souvent :
- Tool
inputSchema—argumentsdetools/call; racine object (MCP 2026-07-28). - Tool
outputSchema—structuredContent; voir l'article outputSchema. - Listing de skill — pas un JSON Schema mais du content addressing : digest lie les octets, frontmatter lie les métadonnées. Vous pouvez ajouter un JSON Schema pour un snapshot de manifest hôte ; cela ne remplace pas le digest MCP.
{
"host_manifest_schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"allowed_skill_uris": {
"type": "array",
"items": { "type": "string", "pattern": "^skill://" }
},
"require_verified": { "const": true }
},
"required": ["allowed_skill_uris", "require_verified"],
"additionalProperties": false
},
"snapshot_ok": {
"allowed_skill_uris": ["skill://deploy/runbook/"],
"require_verified": true
}
}
Valider snapshot_ok contre host_manifest_schema attrape les URI mal configurées ; cela n'empêche pas un serveur de mentir dans le listing — read() et le digest restent la ligne de défense.
Ordre d'intégration côté hôte
- Discover :
SkillsClient.list(); sous 2026-07-28 vérifierttlMs/cacheScopepar page. - Policy : filtrer par origin, préfixe (ex.
skill://acme/) ; rejeter les URI hors allowlist. - Load :
read()seulement pour les skills autorisés ; par défaut ne pas injecter siverified: false. - Tools : une fois le texte du skill dans le prompt, les appels d'outil passent encore par validation locale
inputSchema— voir enum / additionalProperties dans fake skills. - Cache : respecter
ttlMs; relister après expiration pour ne pas garder un vieux digest.
Essayer dans JSON Toolbox
{
"tool_call_after_skill": {
"name": "run_deploy_step",
"arguments": "{\"step\":\"rollback\",\"env\":\"prod\"}"
},
"tool_inputSchema": {
"type": "object",
"properties": {
"step": { "type": "string", "enum": ["plan", "apply", "rollback"] },
"env": { "type": "string", "enum": ["staging", "prod"] }
},
"required": ["step", "env"],
"additionalProperties": false
}
}
- Validation Schema :
tool_call_after_skill.argumentscontretool_inputSchema. - MCP Tool : aligner les noms de champs
inputSchema/outputSchema. - Formater le JSON de listing avec Formatage JSON, puis vérifier les champs digest.
- Pour la sortie structurée finale, utiliser Sortie structurée à part — ne pas mélanger avec le texte du skill.
Questions fréquentes
Skills over MCP et inputSchema de tools/call, est-ce la même chose ?
Non — skills via listing + digest ; tools via objet d'arguments JSON Schema.
Faut-il donner le contenu au modèle si le digest ne correspond pas ?
Non — contenu non fiable, journaliser SkillVerificationError.
Quels champs en plus sous le protocole 2026-07-28 pour skills/list ?
ttlMs et cacheScope ; champs manquants → erreur SDK.
Comment cela se complète avec l'article sécurité fake skills ?
Fake skills = surface d'attaque ; cet article = chaîne de vérification SEP-2640 officielle.
SkillsExtension.attach est-il une API stable ?
attach experimental ; SkillsClient stable — encapsuler attach.
En résumé
Au 06/11/2026, MCP TypeScript SDK 2.4.0 fait des skills une extension MCP de premier ordre avec contrat skills/list et vérification digest, au lieu d'une lecture de dossier côté hôte. Intégration agent : list → filtre policy → read() vérifié → seulement alors influence sur le routage ; tout tools/call reste borné par inputSchema. Prochaine étape : serveur loadSkills réel, SkillsClient.read, altérer des octets localement et confirmer le blocage digest — en parallèle de la validation schema des outils du même agent.