@@ -14,7 +14,11 @@ import {
14
14
ListResourcesResultSchema ,
15
15
LoggingMessageNotificationSchema ,
16
16
ResourceListChangedNotificationSchema ,
17
+ ReadResourceRequest ,
18
+ ReadResourceResultSchema ,
19
+ ResourceLink ,
17
20
} from '../../types.js' ;
21
+ import { getDisplayName } from '../../shared/metadataUtils.js' ;
18
22
19
23
// Create readline interface for user input
20
24
const readline = createInterface ( {
@@ -59,6 +63,7 @@ function printHelp(): void {
59
63
console . log ( ' list-prompts - List available prompts' ) ;
60
64
console . log ( ' get-prompt [name] [args] - Get a prompt with optional JSON arguments' ) ;
61
65
console . log ( ' list-resources - List available resources' ) ;
66
+ console . log ( ' read-resource <uri> - Read a specific resource by URI' ) ;
62
67
console . log ( ' help - Show this help' ) ;
63
68
console . log ( ' quit - Exit the program' ) ;
64
69
}
@@ -154,6 +159,14 @@ function commandLoop(): void {
154
159
await listResources ( ) ;
155
160
break ;
156
161
162
+ case 'read-resource' :
163
+ if ( args . length < 2 ) {
164
+ console . log ( 'Usage: read-resource <uri>' ) ;
165
+ } else {
166
+ await readResource ( args [ 1 ] ) ;
167
+ }
168
+ break ;
169
+
157
170
case 'help' :
158
171
printHelp ( ) ;
159
172
break ;
@@ -317,7 +330,7 @@ async function listTools(): Promise<void> {
317
330
console . log ( ' No tools available' ) ;
318
331
} else {
319
332
for ( const tool of toolsResult . tools ) {
320
- console . log ( ` - ${ tool . name } : ${ tool . description } ` ) ;
333
+ console . log ( ` - id: ${ tool . name } , name: ${ getDisplayName ( tool ) } , description : ${ tool . description } ` ) ;
321
334
}
322
335
}
323
336
} catch ( error ) {
@@ -344,13 +357,37 @@ async function callTool(name: string, args: Record<string, unknown>): Promise<vo
344
357
const result = await client . request ( request , CallToolResultSchema ) ;
345
358
346
359
console . log ( 'Tool result:' ) ;
360
+ const resourceLinks : ResourceLink [ ] = [ ] ;
361
+
347
362
result . content . forEach ( item => {
348
363
if ( item . type === 'text' ) {
349
364
console . log ( ` ${ item . text } ` ) ;
365
+ } else if ( item . type === 'resource_link' ) {
366
+ const resourceLink = item as ResourceLink ;
367
+ resourceLinks . push ( resourceLink ) ;
368
+ console . log ( ` 📁 Resource Link: ${ resourceLink . name } ` ) ;
369
+ console . log ( ` URI: ${ resourceLink . uri } ` ) ;
370
+ if ( resourceLink . mimeType ) {
371
+ console . log ( ` Type: ${ resourceLink . mimeType } ` ) ;
372
+ }
373
+ if ( resourceLink . description ) {
374
+ console . log ( ` Description: ${ resourceLink . description } ` ) ;
375
+ }
376
+ } else if ( item . type === 'resource' ) {
377
+ console . log ( ` [Embedded Resource: ${ item . resource . uri } ]` ) ;
378
+ } else if ( item . type === 'image' ) {
379
+ console . log ( ` [Image: ${ item . mimeType } ]` ) ;
380
+ } else if ( item . type === 'audio' ) {
381
+ console . log ( ` [Audio: ${ item . mimeType } ]` ) ;
350
382
} else {
351
- console . log ( ` ${ item . type } content:` , item ) ;
383
+ console . log ( ` [Unknown content type] :` , item ) ;
352
384
}
353
385
} ) ;
386
+
387
+ // Offer to read resource links
388
+ if ( resourceLinks . length > 0 ) {
389
+ console . log ( `\nFound ${ resourceLinks . length } resource link(s). Use 'read-resource <uri>' to read their content.` ) ;
390
+ }
354
391
} catch ( error ) {
355
392
console . log ( `Error calling tool ${ name } : ${ error } ` ) ;
356
393
}
@@ -380,7 +417,7 @@ async function runNotificationsToolWithResumability(interval: number, count: num
380
417
try {
381
418
console . log ( `Starting notification stream with resumability: interval=${ interval } ms, count=${ count || 'unlimited' } ` ) ;
382
419
console . log ( `Using resumption token: ${ notificationsToolLastEventId || 'none' } ` ) ;
383
-
420
+
384
421
const request : CallToolRequest = {
385
422
method : 'tools/call' ,
386
423
params : {
@@ -393,7 +430,7 @@ async function runNotificationsToolWithResumability(interval: number, count: num
393
430
notificationsToolLastEventId = event ;
394
431
console . log ( `Updated resumption token: ${ event } ` ) ;
395
432
} ;
396
-
433
+
397
434
const result = await client . request ( request , CallToolResultSchema , {
398
435
resumptionToken : notificationsToolLastEventId ,
399
436
onresumptiontoken : onLastEventIdUpdate
@@ -429,7 +466,7 @@ async function listPrompts(): Promise<void> {
429
466
console . log ( ' No prompts available' ) ;
430
467
} else {
431
468
for ( const prompt of promptsResult . prompts ) {
432
- console . log ( ` - ${ prompt . name } : ${ prompt . description } ` ) ;
469
+ console . log ( ` - id: ${ prompt . name } , name: ${ getDisplayName ( prompt ) } , description : ${ prompt . description } ` ) ;
433
470
}
434
471
}
435
472
} catch ( error ) {
@@ -480,14 +517,50 @@ async function listResources(): Promise<void> {
480
517
console . log ( ' No resources available' ) ;
481
518
} else {
482
519
for ( const resource of resourcesResult . resources ) {
483
- console . log ( ` - ${ resource . name } : ${ resource . uri } ` ) ;
520
+ console . log ( ` - id: ${ resource . name } , name: ${ getDisplayName ( resource ) } , description : ${ resource . uri } ` ) ;
484
521
}
485
522
}
486
523
} catch ( error ) {
487
524
console . log ( `Resources not supported by this server (${ error } )` ) ;
488
525
}
489
526
}
490
527
528
+ async function readResource ( uri : string ) : Promise < void > {
529
+ if ( ! client ) {
530
+ console . log ( 'Not connected to server.' ) ;
531
+ return ;
532
+ }
533
+
534
+ try {
535
+ const request : ReadResourceRequest = {
536
+ method : 'resources/read' ,
537
+ params : { uri }
538
+ } ;
539
+
540
+ console . log ( `Reading resource: ${ uri } ` ) ;
541
+ const result = await client . request ( request , ReadResourceResultSchema ) ;
542
+
543
+ console . log ( 'Resource contents:' ) ;
544
+ for ( const content of result . contents ) {
545
+ console . log ( ` URI: ${ content . uri } ` ) ;
546
+ if ( content . mimeType ) {
547
+ console . log ( ` Type: ${ content . mimeType } ` ) ;
548
+ }
549
+
550
+ if ( 'text' in content && typeof content . text === 'string' ) {
551
+ console . log ( ' Content:' ) ;
552
+ console . log ( ' ---' ) ;
553
+ console . log ( content . text . split ( '\n' ) . map ( ( line : string ) => ' ' + line ) . join ( '\n' ) ) ;
554
+ console . log ( ' ---' ) ;
555
+ } else if ( 'blob' in content && typeof content . blob === 'string' ) {
556
+ console . log ( ` [Binary data: ${ content . blob . length } bytes]` ) ;
557
+ }
558
+ }
559
+ } catch ( error ) {
560
+ console . log ( `Error reading resource ${ uri } : ${ error } ` ) ;
561
+ }
562
+ }
563
+
491
564
async function cleanup ( ) : Promise < void > {
492
565
if ( client && transport ) {
493
566
try {
0 commit comments