44 *
55 * Demonstrates client-side SDK usage for the Skills Extension SEP:
66 *
7- * 1. READ_RESOURCE_TOOL — Host-provided tool for model-driven loading
8- * 2. listSkills() — Discover all skills, show prefix + name
9- * 3. readSkillContent() — Load a multi-segment skill by path
10- * 4. readSkillManifest() — Get file inventory with SHA256 hashes
11- * 5. readSkillDocument() — Load a supporting file via resource template
12- * 6. fetchSkillMetadata()— SEP-2093: metadata without content
13- * 7. listSkillsScoped() — SEP-2093: URI-scoped listing
7+ * 1. READ_RESOURCE_TOOL — Host-provided tool for model-driven loading
8+ * 2. listSkillsFromIndex() — Discover skills via skill://index.json
9+ * 3. listSkills() — Discover all skills via resources/list
10+ * 4. readSkillContent() — Load a multi-segment skill by path
11+ * 5. readSkillManifest() — Get file inventory with SHA256 hashes
12+ * 6. readSkillDocument() — Load a supporting file via resource template
1413 *
1514 * Connects to the skills-server via stdio (spawns as child process).
1615 *
@@ -24,11 +23,10 @@ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
2423import {
2524 READ_RESOURCE_TOOL ,
2625 listSkills ,
26+ listSkillsFromIndex ,
2727 readSkillContent ,
2828 readSkillManifest ,
2929 readSkillDocument ,
30- fetchSkillMetadata ,
31- listSkillsScoped ,
3230 buildSkillsSummary ,
3331} from "@modelcontextprotocol/ext-skills/client" ;
3432import { buildSkillUri } from "@modelcontextprotocol/ext-skills" ;
@@ -88,9 +86,31 @@ async function main() {
8886 console . log ( JSON . stringify ( READ_RESOURCE_TOOL , null , 2 ) ) ;
8987
9088 // -----------------------------------------------------------------------
91- // 2. List all skills — show multi-segment paths with prefix + name
89+ // 2. Discover skills via skill://index.json (SEP enumeration)
9290 // -----------------------------------------------------------------------
93- header ( "2. listSkills() — Discover Skills" ) ;
91+ header ( "2. listSkillsFromIndex() — skill://index.json Discovery" ) ;
92+
93+ console . log ( "Per the SEP, servers whose skill set is enumerable SHOULD expose" ) ;
94+ console . log ( "a skill://index.json resource following the Agent Skills discovery format.\n" ) ;
95+
96+ const indexSkills = await listSkillsFromIndex ( client ) ;
97+ if ( indexSkills ) {
98+ console . log ( `Found ${ indexSkills . length } skill(s) in index:\n` ) ;
99+ for ( const skill of indexSkills ) {
100+ console . log ( ` Name: ${ skill . name } ` ) ;
101+ console . log ( ` Skill Path: ${ skill . skillPath } ` ) ;
102+ console . log ( ` URI: ${ skill . uri } ` ) ;
103+ console . log ( ` Description: ${ skill . description } ` ) ;
104+ console . log ( ) ;
105+ }
106+ } else {
107+ console . log ( "Server does not expose skill://index.json (enumeration is optional)" ) ;
108+ }
109+
110+ // -----------------------------------------------------------------------
111+ // 3. List all skills via resources/list — show multi-segment paths
112+ // -----------------------------------------------------------------------
113+ header ( "3. listSkills() — Discover Skills via resources/list" ) ;
94114
95115 const skills = await listSkills ( client ) ;
96116 console . log ( `Found ${ skills . length } skill(s):\n` ) ;
@@ -112,9 +132,9 @@ async function main() {
112132 console . log ( buildSkillsSummary ( skills ) ) ;
113133
114134 // -----------------------------------------------------------------------
115- // 3 . Read a multi-segment skill
135+ // 4 . Read a multi-segment skill
116136 // -----------------------------------------------------------------------
117- header ( "3 . readSkillContent() — Load Multi-Segment Skill" ) ;
137+ header ( "4 . readSkillContent() — Load Multi-Segment Skill" ) ;
118138
119139 const refundSkill = skills . find ( ( s ) => s . skillPath === "acme/billing/refunds" ) ;
120140 if ( refundSkill ) {
@@ -131,9 +151,9 @@ async function main() {
131151 }
132152
133153 // -----------------------------------------------------------------------
134- // 4 . Read skill manifest
154+ // 5 . Read skill manifest
135155 // -----------------------------------------------------------------------
136- header ( "4 . readSkillManifest() — File Inventory" ) ;
156+ header ( "5 . readSkillManifest() — File Inventory" ) ;
137157
138158 if ( refundSkill ) {
139159 const manifest = await readSkillManifest ( client , refundSkill . skillPath ) ;
@@ -148,9 +168,9 @@ async function main() {
148168 }
149169
150170 // -----------------------------------------------------------------------
151- // 5 . Read a supporting file via resource template
171+ // 6 . Read a supporting file via resource template
152172 // -----------------------------------------------------------------------
153- header ( "5 . readSkillDocument() — Supporting File" ) ;
173+ header ( "6 . readSkillDocument() — Supporting File" ) ;
154174
155175 if ( refundSkill ) {
156176 const docPath = "templates/refund-email-template.md" ;
@@ -171,40 +191,6 @@ async function main() {
171191 }
172192 }
173193
174- // -----------------------------------------------------------------------
175- // 6. SEP-2093: Fetch metadata without content
176- // -----------------------------------------------------------------------
177- header ( "6. fetchSkillMetadata() — SEP-2093 Metadata" ) ;
178-
179- if ( refundSkill ) {
180- console . log ( `Fetching metadata for: ${ refundSkill . uri } \n` ) ;
181- const metadata = await fetchSkillMetadata ( client , refundSkill . uri ) ;
182- if ( metadata ) {
183- console . log ( "Metadata (no content transferred):" ) ;
184- console . log ( JSON . stringify ( metadata , null , 2 ) ) ;
185- } else {
186- console . log ( "Server does not support resources/metadata (SEP-2093)" ) ;
187- }
188- }
189-
190- // -----------------------------------------------------------------------
191- // 7. SEP-2093: Scoped listing
192- // -----------------------------------------------------------------------
193- header ( "7. listSkillsScoped() — resources/list with URI Scoping" ) ;
194-
195- console . log ( 'Listing skills under "skill://acme/" (SKILL.md entries only):\n' ) ;
196- const acmeSkills = await listSkillsScoped ( client , "skill://acme/" ) ;
197- if ( acmeSkills ) {
198- console . log ( `Found ${ acmeSkills . length } skill(s) under acme/:\n` ) ;
199- for ( const skill of acmeSkills ) {
200- console . log ( ` ${ skill . skillPath } (name: ${ skill . name } )` ) ;
201- }
202- } else {
203- console . log (
204- "Server does not support skills/list" ,
205- ) ;
206- }
207-
208194 // -----------------------------------------------------------------------
209195 // Summary
210196 // -----------------------------------------------------------------------
@@ -213,10 +199,8 @@ async function main() {
213199 console . log ( "Features demonstrated:" ) ;
214200 console . log ( " [SEP] Skills Extension — skill:// resource convention" ) ;
215201 console . log ( " [SEP] Multi-segment paths (prefix + name = last segment)" ) ;
202+ console . log ( " [SEP] skill://index.json — well-known discovery index" ) ;
216203 console . log ( " [SEP-2133] Extension declaration: io.modelcontextprotocol/skills" ) ;
217- console . log ( " [SEP-2093] resources/metadata — metadata without content" ) ;
218- console . log ( " [SEP-2093] resources/list(uri=...) — URI-scoped listing" ) ;
219- console . log ( " [SEP-2093] Per-resource capabilities via _meta" ) ;
220204 console . log ( ) ;
221205 } finally {
222206 await client . close ( ) ;
0 commit comments