@@ -15,7 +15,11 @@ import {
15
15
LoggingMessageNotificationSchema ,
16
16
ResourceListChangedNotificationSchema ,
17
17
ElicitRequestSchema ,
18
+ ResourceLink ,
19
+ ReadResourceRequest ,
20
+ ReadResourceResultSchema ,
18
21
} from '../../types.js' ;
22
+ import { getDisplayName } from '../../shared/metadataUtils.js' ;
19
23
import Ajv from "ajv" ;
20
24
21
25
// Create readline interface for user input
@@ -62,6 +66,7 @@ function printHelp(): void {
62
66
console . log ( ' list-prompts - List available prompts' ) ;
63
67
console . log ( ' get-prompt [name] [args] - Get a prompt with optional JSON arguments' ) ;
64
68
console . log ( ' list-resources - List available resources' ) ;
69
+ console . log ( ' read-resource <uri> - Read a specific resource by URI' ) ;
65
70
console . log ( ' help - Show this help' ) ;
66
71
console . log ( ' quit - Exit the program' ) ;
67
72
}
@@ -161,6 +166,14 @@ function commandLoop(): void {
161
166
await listResources ( ) ;
162
167
break ;
163
168
169
+ case 'read-resource' :
170
+ if ( args . length < 2 ) {
171
+ console . log ( 'Usage: read-resource <uri>' ) ;
172
+ } else {
173
+ await readResource ( args [ 1 ] ) ;
174
+ }
175
+ break ;
176
+
164
177
case 'help' :
165
178
printHelp ( ) ;
166
179
break ;
@@ -521,7 +534,7 @@ async function listTools(): Promise<void> {
521
534
console . log ( ' No tools available' ) ;
522
535
} else {
523
536
for ( const tool of toolsResult . tools ) {
524
- console . log ( ` - ${ tool . name } : ${ tool . description } ` ) ;
537
+ console . log ( ` - id: ${ tool . name } , name: ${ getDisplayName ( tool ) } , description : ${ tool . description } ` ) ;
525
538
}
526
539
}
527
540
} catch ( error ) {
@@ -548,13 +561,37 @@ async function callTool(name: string, args: Record<string, unknown>): Promise<vo
548
561
const result = await client . request ( request , CallToolResultSchema ) ;
549
562
550
563
console . log ( 'Tool result:' ) ;
564
+ const resourceLinks : ResourceLink [ ] = [ ] ;
565
+
551
566
result . content . forEach ( item => {
552
567
if ( item . type === 'text' ) {
553
568
console . log ( ` ${ item . text } ` ) ;
569
+ } else if ( item . type === 'resource_link' ) {
570
+ const resourceLink = item as ResourceLink ;
571
+ resourceLinks . push ( resourceLink ) ;
572
+ console . log ( ` 📁 Resource Link: ${ resourceLink . name } ` ) ;
573
+ console . log ( ` URI: ${ resourceLink . uri } ` ) ;
574
+ if ( resourceLink . mimeType ) {
575
+ console . log ( ` Type: ${ resourceLink . mimeType } ` ) ;
576
+ }
577
+ if ( resourceLink . description ) {
578
+ console . log ( ` Description: ${ resourceLink . description } ` ) ;
579
+ }
580
+ } else if ( item . type === 'resource' ) {
581
+ console . log ( ` [Embedded Resource: ${ item . resource . uri } ]` ) ;
582
+ } else if ( item . type === 'image' ) {
583
+ console . log ( ` [Image: ${ item . mimeType } ]` ) ;
584
+ } else if ( item . type === 'audio' ) {
585
+ console . log ( ` [Audio: ${ item . mimeType } ]` ) ;
554
586
} else {
555
- console . log ( ` ${ item . type } content:` , item ) ;
587
+ console . log ( ` [Unknown content type] :` , item ) ;
556
588
}
557
589
} ) ;
590
+
591
+ // Offer to read resource links
592
+ if ( resourceLinks . length > 0 ) {
593
+ console . log ( `\nFound ${ resourceLinks . length } resource link(s). Use 'read-resource <uri>' to read their content.` ) ;
594
+ }
558
595
} catch ( error ) {
559
596
console . log ( `Error calling tool ${ name } : ${ error } ` ) ;
560
597
}
@@ -589,7 +626,7 @@ async function runNotificationsToolWithResumability(interval: number, count: num
589
626
try {
590
627
console . log ( `Starting notification stream with resumability: interval=${ interval } ms, count=${ count || 'unlimited' } ` ) ;
591
628
console . log ( `Using resumption token: ${ notificationsToolLastEventId || 'none' } ` ) ;
592
-
629
+
593
630
const request : CallToolRequest = {
594
631
method : 'tools/call' ,
595
632
params : {
@@ -602,7 +639,7 @@ async function runNotificationsToolWithResumability(interval: number, count: num
602
639
notificationsToolLastEventId = event ;
603
640
console . log ( `Updated resumption token: ${ event } ` ) ;
604
641
} ;
605
-
642
+
606
643
const result = await client . request ( request , CallToolResultSchema , {
607
644
resumptionToken : notificationsToolLastEventId ,
608
645
onresumptiontoken : onLastEventIdUpdate
@@ -638,7 +675,7 @@ async function listPrompts(): Promise<void> {
638
675
console . log ( ' No prompts available' ) ;
639
676
} else {
640
677
for ( const prompt of promptsResult . prompts ) {
641
- console . log ( ` - ${ prompt . name } : ${ prompt . description } ` ) ;
678
+ console . log ( ` - id: ${ prompt . name } , name: ${ getDisplayName ( prompt ) } , description : ${ prompt . description } ` ) ;
642
679
}
643
680
}
644
681
} catch ( error ) {
@@ -689,14 +726,50 @@ async function listResources(): Promise<void> {
689
726
console . log ( ' No resources available' ) ;
690
727
} else {
691
728
for ( const resource of resourcesResult . resources ) {
692
- console . log ( ` - ${ resource . name } : ${ resource . uri } ` ) ;
729
+ console . log ( ` - id: ${ resource . name } , name: ${ getDisplayName ( resource ) } , description : ${ resource . uri } ` ) ;
693
730
}
694
731
}
695
732
} catch ( error ) {
696
733
console . log ( `Resources not supported by this server (${ error } )` ) ;
697
734
}
698
735
}
699
736
737
+ async function readResource ( uri : string ) : Promise < void > {
738
+ if ( ! client ) {
739
+ console . log ( 'Not connected to server.' ) ;
740
+ return ;
741
+ }
742
+
743
+ try {
744
+ const request : ReadResourceRequest = {
745
+ method : 'resources/read' ,
746
+ params : { uri }
747
+ } ;
748
+
749
+ console . log ( `Reading resource: ${ uri } ` ) ;
750
+ const result = await client . request ( request , ReadResourceResultSchema ) ;
751
+
752
+ console . log ( 'Resource contents:' ) ;
753
+ for ( const content of result . contents ) {
754
+ console . log ( ` URI: ${ content . uri } ` ) ;
755
+ if ( content . mimeType ) {
756
+ console . log ( ` Type: ${ content . mimeType } ` ) ;
757
+ }
758
+
759
+ if ( 'text' in content && typeof content . text === 'string' ) {
760
+ console . log ( ' Content:' ) ;
761
+ console . log ( ' ---' ) ;
762
+ console . log ( content . text . split ( '\n' ) . map ( ( line : string ) => ' ' + line ) . join ( '\n' ) ) ;
763
+ console . log ( ' ---' ) ;
764
+ } else if ( 'blob' in content && typeof content . blob === 'string' ) {
765
+ console . log ( ` [Binary data: ${ content . blob . length } bytes]` ) ;
766
+ }
767
+ }
768
+ } catch ( error ) {
769
+ console . log ( `Error reading resource ${ uri } : ${ error } ` ) ;
770
+ }
771
+ }
772
+
700
773
async function cleanup ( ) : Promise < void > {
701
774
if ( client && transport ) {
702
775
try {
0 commit comments