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