@@ -62,10 +62,21 @@ const EXAMPLE_COMPLETIONS = {
62
62
const GetTinyImageSchema = z . object ( { } ) ;
63
63
64
64
const AnnotatedMessageSchema = z . object ( {
65
- messageType : z . enum ( [ "error" , "success" , "debug" ] )
65
+ messageType : z
66
+ . enum ( [ "error" , "success" , "debug" ] )
66
67
. describe ( "Type of message to demonstrate different annotation patterns" ) ,
67
- includeImage : z . boolean ( ) . default ( false )
68
- . describe ( "Whether to include an example image" )
68
+ includeImage : z
69
+ . boolean ( )
70
+ . default ( false )
71
+ . describe ( "Whether to include an example image" ) ,
72
+ } ) ;
73
+
74
+ const GetResourceReferenceSchema = z . object ( {
75
+ resourceId : z
76
+ . number ( )
77
+ . min ( 1 )
78
+ . max ( 100 )
79
+ . describe ( "ID of the resource to reference (1-100)" ) ,
69
80
} ) ;
70
81
71
82
enum ToolName {
@@ -76,11 +87,13 @@ enum ToolName {
76
87
SAMPLE_LLM = "sampleLLM" ,
77
88
GET_TINY_IMAGE = "getTinyImage" ,
78
89
ANNOTATED_MESSAGE = "annotatedMessage" ,
90
+ GET_RESOURCE_REFERENCE = "getResourceReference" ,
79
91
}
80
92
81
93
enum PromptName {
82
94
SIMPLE = "simple_prompt" ,
83
95
COMPLEX = "complex_prompt" ,
96
+ RESOURCE = "resource_prompt" ,
84
97
}
85
98
86
99
export const createServer = ( ) => {
@@ -97,7 +110,7 @@ export const createServer = () => {
97
110
logging : { } ,
98
111
completions : { } ,
99
112
} ,
100
- } ,
113
+ }
101
114
) ;
102
115
103
116
let subscriptions : Set < string > = new Set ( ) ;
@@ -116,36 +129,37 @@ export const createServer = () => {
116
129
let logLevel : LoggingLevel = "debug" ;
117
130
let logsUpdateInterval : NodeJS . Timeout | undefined ;
118
131
const messages = [
119
- { level : "debug" , data : "Debug-level message" } ,
120
- { level : "info" , data : "Info-level message" } ,
121
- { level : "notice" , data : "Notice-level message" } ,
122
- { level : "warning" , data : "Warning-level message" } ,
123
- { level : "error" , data : "Error-level message" } ,
124
- { level : "critical" , data : "Critical-level message" } ,
125
- { level : "alert" , data : "Alert level-message" } ,
126
- { level : "emergency" , data : "Emergency-level message" }
127
- ]
128
-
129
- const isMessageIgnored = ( level :LoggingLevel ) :boolean => {
132
+ { level : "debug" , data : "Debug-level message" } ,
133
+ { level : "info" , data : "Info-level message" } ,
134
+ { level : "notice" , data : "Notice-level message" } ,
135
+ { level : "warning" , data : "Warning-level message" } ,
136
+ { level : "error" , data : "Error-level message" } ,
137
+ { level : "critical" , data : "Critical-level message" } ,
138
+ { level : "alert" , data : "Alert level-message" } ,
139
+ { level : "emergency" , data : "Emergency-level message" } ,
140
+ ] ;
141
+
142
+ const isMessageIgnored = ( level : LoggingLevel ) : boolean => {
130
143
const currentLevel = messages . findIndex ( ( msg ) => logLevel === msg . level ) ;
131
- const messageLevel = messages . findIndex ( ( msg ) => level === msg . level ) ;
144
+ const messageLevel = messages . findIndex ( ( msg ) => level === msg . level ) ;
132
145
return messageLevel < currentLevel ;
133
- }
146
+ } ;
134
147
135
148
// Set up update interval for random log messages
136
149
logsUpdateInterval = setInterval ( ( ) => {
137
150
let message = {
138
151
method : "notifications/message" ,
139
152
params : messages [ Math . floor ( Math . random ( ) * messages . length ) ] ,
140
- }
141
- if ( ! isMessageIgnored ( message . params . level as LoggingLevel ) ) server . notification ( message ) ;
153
+ } ;
154
+ if ( ! isMessageIgnored ( message . params . level as LoggingLevel ) )
155
+ server . notification ( message ) ;
142
156
} , 15000 ) ;
143
157
144
158
// Helper method to request sampling from client
145
159
const requestSampling = async (
146
160
context : string ,
147
161
uri : string ,
148
- maxTokens : number = 100 ,
162
+ maxTokens : number = 100
149
163
) => {
150
164
const request : CreateMessageRequest = {
151
165
method : "sampling/createMessage" ,
@@ -281,6 +295,17 @@ export const createServer = () => {
281
295
} ,
282
296
] ,
283
297
} ,
298
+ {
299
+ name : PromptName . RESOURCE ,
300
+ description : "A prompt that includes an embedded resource reference" ,
301
+ arguments : [
302
+ {
303
+ name : "resourceId" ,
304
+ description : "Resource ID to include (1-100)" ,
305
+ required : true ,
306
+ } ,
307
+ ] ,
308
+ } ,
284
309
] ,
285
310
} ;
286
311
} ) ;
@@ -331,6 +356,37 @@ export const createServer = () => {
331
356
} ;
332
357
}
333
358
359
+ if ( name === PromptName . RESOURCE ) {
360
+ const resourceId = parseInt ( args ?. resourceId as string , 10 ) ;
361
+ if ( isNaN ( resourceId ) || resourceId < 1 || resourceId > 100 ) {
362
+ throw new Error (
363
+ `Invalid resourceId: ${ args ?. resourceId } . Must be a number between 1 and 100.`
364
+ ) ;
365
+ }
366
+
367
+ const resourceIndex = resourceId - 1 ;
368
+ const resource = ALL_RESOURCES [ resourceIndex ] ;
369
+
370
+ return {
371
+ messages : [
372
+ {
373
+ role : "user" ,
374
+ content : {
375
+ type : "text" ,
376
+ text : `This prompt includes Resource ${ resourceId } . Please analyze the following resource:` ,
377
+ } ,
378
+ } ,
379
+ {
380
+ role : "user" ,
381
+ content : {
382
+ type : "resource" ,
383
+ resource : resource ,
384
+ } ,
385
+ } ,
386
+ ] ,
387
+ } ;
388
+ }
389
+
334
390
throw new Error ( `Unknown prompt: ${ name } ` ) ;
335
391
} ) ;
336
392
@@ -348,7 +404,8 @@ export const createServer = () => {
348
404
} ,
349
405
{
350
406
name : ToolName . PRINT_ENV ,
351
- description : "Prints all environment variables, helpful for debugging MCP server configuration" ,
407
+ description :
408
+ "Prints all environment variables, helpful for debugging MCP server configuration" ,
352
409
inputSchema : zodToJsonSchema ( PrintEnvSchema ) as ToolInput ,
353
410
} ,
354
411
{
@@ -369,9 +426,16 @@ export const createServer = () => {
369
426
} ,
370
427
{
371
428
name : ToolName . ANNOTATED_MESSAGE ,
372
- description : "Demonstrates how annotations can be used to provide metadata about content" ,
429
+ description :
430
+ "Demonstrates how annotations can be used to provide metadata about content" ,
373
431
inputSchema : zodToJsonSchema ( AnnotatedMessageSchema ) as ToolInput ,
374
432
} ,
433
+ {
434
+ name : ToolName . GET_RESOURCE_REFERENCE ,
435
+ description :
436
+ "Returns a resource reference that can be used by MCP clients" ,
437
+ inputSchema : zodToJsonSchema ( GetResourceReferenceSchema ) as ToolInput ,
438
+ } ,
375
439
] ;
376
440
377
441
return { tools } ;
@@ -408,7 +472,7 @@ export const createServer = () => {
408
472
409
473
for ( let i = 1 ; i < steps + 1 ; i ++ ) {
410
474
await new Promise ( ( resolve ) =>
411
- setTimeout ( resolve , stepDuration * 1000 ) ,
475
+ setTimeout ( resolve , stepDuration * 1000 )
412
476
) ;
413
477
414
478
if ( progressToken !== undefined ) {
@@ -451,10 +515,12 @@ export const createServer = () => {
451
515
const result = await requestSampling (
452
516
prompt ,
453
517
ToolName . SAMPLE_LLM ,
454
- maxTokens ,
518
+ maxTokens
455
519
) ;
456
520
return {
457
- content : [ { type : "text" , text : `LLM sampling result: ${ result . content . text } ` } ] ,
521
+ content : [
522
+ { type : "text" , text : `LLM sampling result: ${ result . content . text } ` } ,
523
+ ] ,
458
524
} ;
459
525
}
460
526
@@ -479,6 +545,35 @@ export const createServer = () => {
479
545
} ;
480
546
}
481
547
548
+ if ( name === ToolName . GET_RESOURCE_REFERENCE ) {
549
+ const validatedArgs = GetResourceReferenceSchema . parse ( args ) ;
550
+ const resourceId = validatedArgs . resourceId ;
551
+
552
+ const resourceIndex = resourceId - 1 ;
553
+ if ( resourceIndex < 0 || resourceIndex >= ALL_RESOURCES . length ) {
554
+ throw new Error ( `Resource with ID ${ resourceId } does not exist` ) ;
555
+ }
556
+
557
+ const resource = ALL_RESOURCES [ resourceIndex ] ;
558
+
559
+ return {
560
+ content : [
561
+ {
562
+ type : "text" ,
563
+ text : `Returning resource reference for Resource ${ resourceId } :` ,
564
+ } ,
565
+ {
566
+ type : "resource" ,
567
+ resource : resource ,
568
+ } ,
569
+ {
570
+ type : "text" ,
571
+ text : `You can access this resource using the URI: ${ resource . uri } ` ,
572
+ } ,
573
+ ] ,
574
+ } ;
575
+ }
576
+
482
577
if ( name === ToolName . ANNOTATED_MESSAGE ) {
483
578
const { messageType, includeImage } = AnnotatedMessageSchema . parse ( args ) ;
484
579
@@ -491,26 +586,26 @@ export const createServer = () => {
491
586
text : "Error: Operation failed" ,
492
587
annotations : {
493
588
priority : 1.0 , // Errors are highest priority
494
- audience : [ "user" , "assistant" ] // Both need to know about errors
495
- }
589
+ audience : [ "user" , "assistant" ] , // Both need to know about errors
590
+ } ,
496
591
} ) ;
497
592
} else if ( messageType === "success" ) {
498
593
content . push ( {
499
594
type : "text" ,
500
595
text : "Operation completed successfully" ,
501
596
annotations : {
502
597
priority : 0.7 , // Success messages are important but not critical
503
- audience : [ "user" ] // Success mainly for user consumption
504
- }
598
+ audience : [ "user" ] , // Success mainly for user consumption
599
+ } ,
505
600
} ) ;
506
601
} else if ( messageType === "debug" ) {
507
602
content . push ( {
508
603
type : "text" ,
509
604
text : "Debug: Cache hit ratio 0.95, latency 150ms" ,
510
605
annotations : {
511
606
priority : 0.3 , // Debug info is low priority
512
- audience : [ "assistant" ] // Technical details for assistant
513
- }
607
+ audience : [ "assistant" ] , // Technical details for assistant
608
+ } ,
514
609
} ) ;
515
610
}
516
611
@@ -522,8 +617,8 @@ export const createServer = () => {
522
617
mimeType : "image/png" ,
523
618
annotations : {
524
619
priority : 0.5 ,
525
- audience : [ "user" ] // Images primarily for user visualization
526
- }
620
+ audience : [ "user" ] , // Images primarily for user visualization
621
+ } ,
527
622
} ) ;
528
623
}
529
624
@@ -541,18 +636,19 @@ export const createServer = () => {
541
636
if ( ! resourceId ) return { completion : { values : [ ] } } ;
542
637
543
638
// Filter resource IDs that start with the input value
544
- const values = EXAMPLE_COMPLETIONS . resourceId . filter ( id =>
639
+ const values = EXAMPLE_COMPLETIONS . resourceId . filter ( ( id ) =>
545
640
id . startsWith ( argument . value )
546
641
) ;
547
642
return { completion : { values, hasMore : false , total : values . length } } ;
548
643
}
549
644
550
645
if ( ref . type === "ref/prompt" ) {
551
646
// Handle completion for prompt arguments
552
- const completions = EXAMPLE_COMPLETIONS [ argument . name as keyof typeof EXAMPLE_COMPLETIONS ] ;
647
+ const completions =
648
+ EXAMPLE_COMPLETIONS [ argument . name as keyof typeof EXAMPLE_COMPLETIONS ] ;
553
649
if ( ! completions ) return { completion : { values : [ ] } } ;
554
650
555
- const values = completions . filter ( value =>
651
+ const values = completions . filter ( ( value ) =>
556
652
value . startsWith ( argument . value )
557
653
) ;
558
654
return { completion : { values, hasMore : false , total : values . length } } ;
0 commit comments