77 * @module
88 */
99
10+ //#region imports
1011import { randomUUID } from 'node:crypto' ;
1112
1213import { createMcpExpressApp } from '@modelcontextprotocol/express' ;
1314import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node' ;
1415import type { CallToolResult , ResourceLink } from '@modelcontextprotocol/server' ;
1516import { completable , McpServer , ResourceTemplate , StdioServerTransport } from '@modelcontextprotocol/server' ;
1617import * as z from 'zod/v4' ;
18+ //#endregion imports
1719
1820// ---------------------------------------------------------------------------
19- // Instructions
21+ // Server instructions
2022// ---------------------------------------------------------------------------
2123
22- /** Example: Providing server instructions to guide LLM usage . */
24+ /** Example: McpServer with instructions for LLM guidance . */
2325function instructions_basic ( ) {
2426 //#region instructions_basic
2527 const server = new McpServer (
28+ { name : 'db-server' , version : '1.0.0' } ,
2629 {
27- name : 'multi-tool-server' ,
28- version : '1.0.0'
29- } ,
30- {
31- instructions : `This server provides data-pipeline tools. Always call "validate-schema"
32- before calling "transform-data" to avoid runtime errors.`
30+ instructions :
31+ 'Always call list_tables before running queries. Use validate_schema before migrate_schema for safe migrations. Results are limited to 1000 rows.'
3332 }
3433 ) ;
3534 //#endregion instructions_basic
@@ -95,6 +94,59 @@ function registerTool_resourceLink(server: McpServer) {
9594 //#endregion registerTool_resourceLink
9695}
9796
97+ /** Example: Tool with explicit error handling using isError. */
98+ function registerTool_errorHandling ( server : McpServer ) {
99+ //#region registerTool_errorHandling
100+ server . registerTool (
101+ 'fetch-data' ,
102+ {
103+ description : 'Fetch data from a URL' ,
104+ inputSchema : z . object ( { url : z . string ( ) } )
105+ } ,
106+ async ( { url } ) : Promise < CallToolResult > => {
107+ try {
108+ const res = await fetch ( url ) ;
109+ if ( ! res . ok ) {
110+ return {
111+ content : [ { type : 'text' , text : `HTTP ${ res . status } : ${ res . statusText } ` } ] ,
112+ isError : true
113+ } ;
114+ }
115+ const text = await res . text ( ) ;
116+ return { content : [ { type : 'text' , text } ] } ;
117+ } catch ( error ) {
118+ return {
119+ content : [ { type : 'text' , text : `Failed: ${ error instanceof Error ? error . message : String ( error ) } ` } ] ,
120+ isError : true
121+ } ;
122+ }
123+ }
124+ ) ;
125+ //#endregion registerTool_errorHandling
126+ }
127+
128+ /** Example: Tool with annotations hinting at behavior. */
129+ function registerTool_annotations ( server : McpServer ) {
130+ //#region registerTool_annotations
131+ server . registerTool (
132+ 'delete-file' ,
133+ {
134+ description : 'Delete a file from the project' ,
135+ inputSchema : z . object ( { path : z . string ( ) } ) ,
136+ annotations : {
137+ title : 'Delete File' ,
138+ destructiveHint : true ,
139+ idempotentHint : true
140+ }
141+ } ,
142+ async ( { path } ) : Promise < CallToolResult > => {
143+ // ... perform deletion ...
144+ return { content : [ { type : 'text' , text : `Deleted ${ path } ` } ] } ;
145+ }
146+ ) ;
147+ //#endregion registerTool_annotations
148+ }
149+
98150/** Example: Registering a static resource at a fixed URI. */
99151function registerResource_static ( server : McpServer ) {
100152 //#region registerResource_static
@@ -228,6 +280,44 @@ function registerTool_logging() {
228280 return server ;
229281}
230282
283+ // ---------------------------------------------------------------------------
284+ // Progress
285+ // ---------------------------------------------------------------------------
286+
287+ /** Example: Tool that sends progress notifications during a long-running operation. */
288+ function registerTool_progress ( server : McpServer ) {
289+ //#region registerTool_progress
290+ server . registerTool (
291+ 'process-files' ,
292+ {
293+ description : 'Process files with progress updates' ,
294+ inputSchema : z . object ( { files : z . array ( z . string ( ) ) } )
295+ } ,
296+ async ( { files } , ctx ) : Promise < CallToolResult > => {
297+ const progressToken = ctx . mcpReq . _meta ?. progressToken ;
298+
299+ for ( let i = 0 ; i < files . length ; i ++ ) {
300+ // ... process files[i] ...
301+
302+ if ( progressToken !== undefined ) {
303+ await ctx . mcpReq . notify ( {
304+ method : 'notifications/progress' ,
305+ params : {
306+ progressToken,
307+ progress : i + 1 ,
308+ total : files . length ,
309+ message : `Processed ${ files [ i ] } `
310+ }
311+ } ) ;
312+ }
313+ }
314+
315+ return { content : [ { type : 'text' , text : `Processed ${ files . length } files` } ] } ;
316+ }
317+ ) ;
318+ //#endregion registerTool_progress
319+ }
320+
231321// ---------------------------------------------------------------------------
232322// Server-initiated requests
233323// ---------------------------------------------------------------------------
@@ -310,6 +400,24 @@ function registerTool_elicitation(server: McpServer) {
310400 //#endregion registerTool_elicitation
311401}
312402
403+ /** Example: Tool that requests the client's filesystem roots. */
404+ function registerTool_roots ( server : McpServer ) {
405+ //#region registerTool_roots
406+ server . registerTool (
407+ 'list-workspace-files' ,
408+ {
409+ description : 'List files across all workspace roots' ,
410+ inputSchema : z . object ( { } )
411+ } ,
412+ async ( _args , _ctx ) : Promise < CallToolResult > => {
413+ const { roots } = await server . server . listRoots ( ) ;
414+ const summary = roots . map ( r => `${ r . name ?? r . uri } : ${ r . uri } ` ) . join ( '\n' ) ;
415+ return { content : [ { type : 'text' , text : summary } ] } ;
416+ }
417+ ) ;
418+ //#endregion registerTool_roots
419+ }
420+
313421// ---------------------------------------------------------------------------
314422// Transports
315423// ---------------------------------------------------------------------------
@@ -363,6 +471,39 @@ async function stdio_basic() {
363471 //#endregion stdio_basic
364472}
365473
474+ // ---------------------------------------------------------------------------
475+ // Shutdown
476+ // ---------------------------------------------------------------------------
477+
478+ /** Example: Graceful shutdown for a stateful multi-session HTTP server. */
479+ function shutdown_statefulHttp ( app : ReturnType < typeof createMcpExpressApp > , transports : Map < string , NodeStreamableHTTPServerTransport > ) {
480+ //#region shutdown_statefulHttp
481+ // Capture the http.Server so it can be closed on shutdown
482+ const httpServer = app . listen ( 3000 ) ;
483+
484+ process . on ( 'SIGINT' , async ( ) => {
485+ httpServer . close ( ) ;
486+
487+ for ( const [ sessionId , transport ] of transports ) {
488+ await transport . close ( ) ;
489+ transports . delete ( sessionId ) ;
490+ }
491+
492+ process . exit ( 0 ) ;
493+ } ) ;
494+ //#endregion shutdown_statefulHttp
495+ }
496+
497+ /** Example: Graceful shutdown for a stdio server. */
498+ function shutdown_stdio ( server : McpServer ) {
499+ //#region shutdown_stdio
500+ process . on ( 'SIGINT' , async ( ) => {
501+ await server . close ( ) ;
502+ process . exit ( 0 ) ;
503+ } ) ;
504+ //#endregion shutdown_stdio
505+ }
506+
366507// ---------------------------------------------------------------------------
367508// DNS rebinding protection
368509// ---------------------------------------------------------------------------
@@ -397,9 +538,13 @@ function dnsRebinding_allowedHosts() {
397538void instructions_basic ;
398539void registerTool_basic ;
399540void registerTool_resourceLink ;
541+ void registerTool_errorHandling ;
542+ void registerTool_annotations ;
400543void registerTool_logging ;
544+ void registerTool_progress ;
401545void registerTool_sampling ;
402546void registerTool_elicitation ;
547+ void registerTool_roots ;
403548void registerResource_static ;
404549void registerResource_template ;
405550void registerPrompt_basic ;
@@ -408,5 +553,7 @@ void streamableHttp_stateful;
408553void streamableHttp_stateless ;
409554void streamableHttp_jsonResponse ;
410555void stdio_basic ;
556+ void shutdown_statefulHttp ;
557+ void shutdown_stdio ;
411558void dnsRebinding_basic ;
412559void dnsRebinding_allowedHosts ;
0 commit comments