fa-mcp-sdk 0.2.249 → 0.2.258

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/cli-template/FA-MCP-SDK-DOC/00-FA-MCP-SDK-index.md +45 -161
  2. package/cli-template/FA-MCP-SDK-DOC/01-getting-started.md +71 -226
  3. package/cli-template/FA-MCP-SDK-DOC/02-1-tools-and-api.md +80 -360
  4. package/cli-template/FA-MCP-SDK-DOC/02-2-prompts-and-resources.md +191 -342
  5. package/cli-template/FA-MCP-SDK-DOC/03-configuration.md +141 -279
  6. package/cli-template/FA-MCP-SDK-DOC/04-authentication.md +73 -522
  7. package/cli-template/FA-MCP-SDK-DOC/05-ad-authorization.md +68 -419
  8. package/cli-template/FA-MCP-SDK-DOC/06-utilities.md +64 -447
  9. package/cli-template/FA-MCP-SDK-DOC/07-testing-and-operations.md +39 -196
  10. package/cli-template/package.json +2 -1
  11. package/config/local.yaml +1 -1
  12. package/dist/core/_types_/types.d.ts +36 -10
  13. package/dist/core/_types_/types.d.ts.map +1 -1
  14. package/dist/core/auth/admin-auth.js +1 -1
  15. package/dist/core/auth/admin-auth.js.map +1 -1
  16. package/dist/core/auth/middleware.js +8 -8
  17. package/dist/core/auth/middleware.js.map +1 -1
  18. package/dist/core/auth/multi-auth.d.ts.map +1 -1
  19. package/dist/core/auth/multi-auth.js +15 -14
  20. package/dist/core/auth/multi-auth.js.map +1 -1
  21. package/dist/core/index.d.ts +1 -1
  22. package/dist/core/index.d.ts.map +1 -1
  23. package/dist/core/index.js.map +1 -1
  24. package/dist/core/mcp/create-mcp-server.js +8 -9
  25. package/dist/core/mcp/create-mcp-server.js.map +1 -1
  26. package/dist/core/mcp/prompts.d.ts +10 -5
  27. package/dist/core/mcp/prompts.d.ts.map +1 -1
  28. package/dist/core/mcp/prompts.js +17 -15
  29. package/dist/core/mcp/prompts.js.map +1 -1
  30. package/dist/core/mcp/resources.d.ts +4 -4
  31. package/dist/core/mcp/resources.d.ts.map +1 -1
  32. package/dist/core/mcp/resources.js +21 -20
  33. package/dist/core/mcp/resources.js.map +1 -1
  34. package/dist/core/utils/utils.d.ts +2 -1
  35. package/dist/core/utils/utils.d.ts.map +1 -1
  36. package/dist/core/utils/utils.js +2 -2
  37. package/dist/core/utils/utils.js.map +1 -1
  38. package/dist/core/web/home-api.d.ts.map +1 -1
  39. package/dist/core/web/home-api.js +4 -3
  40. package/dist/core/web/home-api.js.map +1 -1
  41. package/dist/core/web/server-http.d.ts.map +1 -1
  42. package/dist/core/web/server-http.js +36 -21
  43. package/dist/core/web/server-http.js.map +1 -1
  44. package/package.json +1 -1
  45. package/scripts/update-doc.js +21 -0
  46. package/src/template/start.ts +1 -1
@@ -1,529 +1,146 @@
1
1
  # Utilities, Errors, and Logging
2
2
 
3
- ## Error Handling
4
-
5
- ### Custom Error Classes
3
+ ## Error Classes
6
4
 
7
5
  ```typescript
8
6
  import { BaseMcpError, ToolExecutionError, ValidationError, ServerError } from 'fa-mcp-sdk';
9
7
 
10
- // Create custom error types
11
- class MyCustomError extends BaseMcpError {
12
- constructor(message: string) {
13
- super(message, 'CUSTOM_ERROR');
14
- }
15
- }
16
-
17
- // Use built-in error types
18
- if (!validInput) {
19
- throw new ValidationError('Input validation failed');
20
- }
8
+ throw new ValidationError('Input validation failed');
9
+ throw new ToolExecutionError('my_tool', 'Execution failed');
10
+ throw new ServerError('Database connection failed', { key: 'value' });
21
11
 
22
- if (toolFailed) {
23
- throw new ToolExecutionError('my_tool', 'Tool execution failed');
12
+ // Custom error
13
+ class MyError extends BaseMcpError {
14
+ constructor(msg: string) { super(msg, 'MY_ERROR'); }
24
15
  }
25
16
  ```
26
17
 
27
- ### `ServerError`
18
+ **ServerError**: `code: 'SERVER_ERROR'`, `httpStatus: 500`
28
19
 
29
- Server-related error class for internal MCP server failures. Use for unexpected server-side errors that aren't tool-specific.
20
+ ## Error Utilities
30
21
 
31
22
  ```typescript
32
- import { ServerError } from 'fa-mcp-sdk';
33
-
34
- // Class Definition:
35
- class ServerError extends BaseMcpError {
36
- constructor(
37
- message: string,
38
- details?: Record<string, unknown>,
39
- printed?: boolean
40
- );
41
- }
42
-
43
- // Examples:
44
- throw new ServerError('Database connection failed');
45
-
46
- throw new ServerError('Configuration error', {
47
- configKey: 'webServer.port',
48
- expected: 'number',
49
- received: 'string'
50
- });
51
-
52
- // With printed flag (prevents duplicate logging)
53
- throw new ServerError('Internal error', undefined, true);
54
- ```
55
-
56
- **Properties:**
57
- - `code`: Always `'SERVER_ERROR'`
58
- - `httpStatus`: Always `500`
59
- - `details`: Optional additional error context
60
-
61
- ### Error Utilities
62
-
63
- ```typescript
64
- import {
65
- createJsonRpcErrorResponse,
66
- toError,
67
- toStr,
68
- addErrorMessage
69
- } from 'fa-mcp-sdk';
70
-
71
- // createJsonRpcErrorResponse - create JSON-RPC 2.0 error response
72
- // Function Signature:
73
- function createJsonRpcErrorResponse (
74
- error: Error | BaseMcpError,
75
- requestId?: string | number | null,
76
- ): any {...}
77
-
78
- // Example:
79
- try {
80
- // some operation
81
- } catch (error) {
82
- const jsonRpcError = createJsonRpcErrorResponse(error, 'request-123');
83
- res.json(jsonRpcError);
84
- }
23
+ import { createJsonRpcErrorResponse, toError, toStr, addErrorMessage } from 'fa-mcp-sdk';
85
24
 
86
- // toError - safely convert any value to Error object
87
- // Function Signature:
88
- const toError = (err: any): Error {...}
25
+ // Create JSON-RPC error response
26
+ const response = createJsonRpcErrorResponse(error, 'request-123');
89
27
 
90
- // Examples:
91
- const err1 = toError(new Error('Original error')); // Returns original Error
92
- const err2 = toError('String error message'); // Returns new Error('String error message')
93
- const err3 = toError({ message: 'Object error' }); // Returns new Error('[object Object]')
28
+ // Safe error conversion
29
+ const err = toError(anything); // Error object
30
+ const msg = toStr(anything); // string message
94
31
 
95
- // toStr - safely convert error to string message
96
- // Function Signature:
97
- const toStr = (err: any): string {...}
98
-
99
- // Examples:
100
- const msg1 = toStr(new Error('Test error')); // Returns 'Test error'
101
- const msg2 = toStr('String message'); // Returns 'String message'
102
- const msg3 = toStr(null); // Returns 'Unknown error'
103
-
104
- // addErrorMessage - add context to existing error message
105
- // Function Signature:
106
- const addErrorMessage = (err: any, msg: string): void {...}
107
-
108
- // Example:
109
- const originalError = new Error('Connection failed');
110
- addErrorMessage(originalError, 'Database operation failed');
111
- // originalError.message is now: 'Database operation failed. Connection failed'
32
+ // Add context to error
33
+ addErrorMessage(error, 'Operation failed');
34
+ // error.message = 'Operation failed. Original message'
112
35
  ```
113
36
 
114
- ---
115
-
116
37
  ## Constants
117
38
 
118
- ### `ROOT_PROJECT_DIR`
119
-
120
- Absolute path to the project root directory. Calculated at runtime based on `process.cwd()`.
121
-
122
39
  ```typescript
123
40
  import { ROOT_PROJECT_DIR } from 'fa-mcp-sdk';
124
41
 
125
- // Constant Definition:
126
- const ROOT_PROJECT_DIR: string = process.cwd();
127
-
128
- // Example usage:
129
- import * as path from 'path';
130
-
131
42
  const configPath = path.join(ROOT_PROJECT_DIR, 'config', 'default.yaml');
132
- const assetsPath = path.join(ROOT_PROJECT_DIR, 'src', 'assets');
133
-
134
- console.log('Project root:', ROOT_PROJECT_DIR);
135
- // Output: /home/user/my-mcp-server
136
43
  ```
137
44
 
138
- **Use Cases:**
139
- - Building absolute paths to project files
140
- - Locating configuration files
141
- - Resolving asset paths
142
-
143
- ---
144
-
145
- ## Utility Functions
146
-
147
- ### General Utilities
45
+ ## General Utilities
148
46
 
149
47
  ```typescript
150
- import {
151
- trim,
152
- isMainModule,
153
- isNonEmptyObject,
154
- isObject,
155
- ppj,
156
- encodeSvgForDataUri,
157
- getAsset
158
- } from 'fa-mcp-sdk';
159
-
160
- // trim - safely trim string with null/undefined handling
161
- // Function Signature:
162
- const trim = (s: any): string {...}
163
-
164
- // Examples:
165
- const cleanText1 = trim(' hello '); // Returns 'hello'
166
- const cleanText2 = trim(null); // Returns ''
167
- const cleanText3 = trim(undefined); // Returns ''
168
- const cleanText4 = trim(123); // Returns '123'
169
-
170
- // isMainModule - check if current module is the main entry point
171
- // Function Signature:
172
- const isMainModule = (url: string): boolean {...}
173
-
174
- // Example:
175
- if (isMainModule(import.meta.url)) {
176
- console.log('Running as main module');
177
- startServer();
178
- }
179
-
180
- // isObject - check if value is an object (not null, not array)
181
- // Function Signature:
182
- const isObject = (o: any): boolean {...}
183
-
184
- // Examples:
185
- isObject({}); // Returns true
186
- isObject({ key: 'value' }); // Returns true
187
- isObject([]); // Returns false
188
- isObject(null); // Returns false
189
- isObject('string'); // Returns false
190
-
191
- // isNonEmptyObject - check if value is non-empty object with defined values
192
- // Function Signature:
193
- const isNonEmptyObject = (o: any): boolean {...}
194
-
195
- // Examples:
196
- isNonEmptyObject({ key: 'value' }); // Returns true
197
- isNonEmptyObject({}); // Returns false
198
- isNonEmptyObject({ key: undefined }); // Returns false
199
- isNonEmptyObject([]); // Returns false
200
-
201
- // ppj - pretty-print JSON with 2-space indentation
202
- // Function Signature:
203
- const ppj = (v: any): string {...}
204
-
205
- // Example:
206
- const formatted = ppj({ user: 'john', age: 30 });
207
- // Returns:
208
- // {
209
- // "user": "john",
210
- // "age": 30
211
- // }
212
-
213
- // encodeSvgForDataUri - encode SVG content for use in data URI
214
- // Function Signature:
215
- const encodeSvgForDataUri = (svg: string): string {...}
216
-
217
- // Example:
218
- const svgContent = '<svg xmlns="http://www.w3.org/2000/svg"><circle r="10"/></svg>';
219
- const encoded = encodeSvgForDataUri(svgContent);
220
- const dataUri = `data:image/svg+xml,${encoded}`;
48
+ import { trim, isMainModule, isObject, isNonEmptyObject, ppj, encodeSvgForDataUri, getAsset } from 'fa-mcp-sdk';
221
49
 
222
- // getAsset - get asset file content from src/asset folder
223
- // Function Signature:
224
- const getAsset = (relPathFromAssetRoot: string): string | undefined {...}
50
+ trim(' hello '); // 'hello'
51
+ trim(null); // ''
52
+ isMainModule(import.meta.url); // true if main entry
53
+ isObject({}); // true
54
+ isObject([]); // false
55
+ isNonEmptyObject({}); // false
56
+ isNonEmptyObject({ k: undefined }); // false
57
+ ppj({ user: 'john' }); // Pretty JSON string
225
58
 
226
- // Example:
227
- const logoContent = getAsset('logo.svg'); // Reads from src/asset/logo.svg
228
- const iconContent = getAsset('icons/star.svg'); // Reads from src/asset/icons/star.svg
59
+ const encoded = encodeSvgForDataUri(svgContent);
60
+ const logo = getAsset('logo.svg'); // From src/asset/
229
61
  ```
230
62
 
231
- ### HTTP Utilities
63
+ ## HTTP Utilities
232
64
 
233
65
  ```typescript
234
66
  import { normalizeHeaders } from 'fa-mcp-sdk';
235
67
 
236
- // normalizeHeaders - Normalize HTTP headers for consistent access
237
- // Function Signature:
238
- function normalizeHeaders(headers: Record<string, any>): Record<string, string>;
239
-
240
- // Features:
241
- // - Converts all header names to lowercase
242
- // - Joins array values with ', ' separator
243
- // - Filters out null/undefined values
244
- // - Converts non-string values to strings
245
-
246
- // Example:
247
- const rawHeaders = {
248
- 'Authorization': 'Bearer token123',
249
- 'X-Custom-Header': 'value',
250
- 'Accept-Language': ['en', 'ru'],
251
- 'X-Null-Header': null,
252
- };
253
-
254
- const normalized = normalizeHeaders(rawHeaders);
255
- // Result:
256
- // {
257
- // 'authorization': 'Bearer token123',
258
- // 'x-custom-header': 'value',
259
- // 'accept-language': 'en, ru'
260
- // }
261
-
262
- // Common use case - accessing headers in tool handler:
263
- import { IToolHandlerParams } from 'fa-mcp-sdk';
264
-
265
- export const handleToolCall = async (params: IToolHandlerParams): Promise<any> => {
266
- const { headers } = params;
267
-
268
- // Headers are already normalized by SDK, access with lowercase keys
269
- const authHeader = headers?.authorization;
270
- const userAgent = headers?.['user-agent'];
271
- const clientIP = headers?.['x-real-ip'] || headers?.['x-forwarded-for'];
272
-
273
- // ...
274
- };
68
+ // Normalizes to lowercase, joins arrays with ', '
69
+ const normalized = normalizeHeaders({
70
+ 'Authorization': 'Bearer token',
71
+ 'Accept-Language': ['en', 'ru']
72
+ });
73
+ // { 'authorization': 'Bearer token', 'accept-language': 'en, ru' }
275
74
  ```
276
75
 
277
- ### Tool Utilities
76
+ ## Tool Utilities
278
77
 
279
78
  ```typescript
280
- import { getTools } from 'fa-mcp-sdk';
281
- import { Tool } from '@modelcontextprotocol/sdk/types.js';
79
+ import { getTools, formatToolResult, getJsonFromResult } from 'fa-mcp-sdk';
282
80
 
283
- // getTools - Get the list of registered MCP tools
284
- // Function Signature:
285
- async function getTools(): Promise<Tool[]>;
81
+ const tools = await getTools(); // Get registered tools
286
82
 
287
- // Retrieves tools from the project data passed to initMcpServer()
288
- // Supports both static arrays and dynamic tool functions
289
-
290
- // Example:
291
- const tools = await getTools();
292
- console.log(`Registered tools: ${tools.length}`);
293
- tools.forEach(tool => {
294
- console.log(`- ${tool.name}: ${tool.description}`);
295
- });
83
+ // Format based on appConfig.mcp.toolAnswerAs
84
+ const result = formatToolResult({ message: 'Done', data: {} });
296
85
 
297
- // Useful for:
298
- // - Introspection and debugging
299
- // - Dynamic tool documentation
300
- // - Tool validation in tests
86
+ // Extract original JSON from formatted result
87
+ const original = getJsonFromResult<MyType>(result);
301
88
  ```
302
89
 
303
- ### Network Utilities
90
+ ## Network Utilities
304
91
 
305
92
  ```typescript
306
93
  import { isPortAvailable, checkPortAvailability } from 'fa-mcp-sdk';
307
94
 
308
- // isPortAvailable - check if port is available for binding
309
- // Function Signature:
310
- function isPortAvailable (port: number, host: string = '0.0.0.0'): Promise<boolean> {...}
95
+ const available = await isPortAvailable(3000, 'localhost');
311
96
 
312
- // Examples:
313
- const available1 = await isPortAvailable(1234); // Check on all interfaces
314
- const available2 = await isPortAvailable(1234, 'localhost'); // Check on localhost
315
- const available3 = await isPortAvailable(1234, '192.168.1.10'); // Check on specific IP
316
-
317
- if (available1) {
318
- console.log('Port 3000 is available');
319
- } else {
320
- console.log('Port 3000 is occupied');
321
- }
322
-
323
- // checkPortAvailability - check port with error handling
324
- // Function Signature:
325
- async function checkPortAvailability (
326
- port: number,
327
- host: string = '0.0.0.0',
328
- exitOnError: boolean = true
329
- ): Promise<void> {...}
330
-
331
- // Examples:
332
- try {
333
- // Throws error if port is busy
334
- await checkPortAvailability(3000, 'localhost', true);
335
- console.log('Port is available, can start server');
336
- } catch (error) {
337
- console.log('Port is busy:', error.message);
338
- }
339
-
340
- // Don't exit process on busy port
341
- try {
342
- await checkPortAvailability(3000, 'localhost', false);
343
- console.log('Port is available');
344
- } catch (error) {
345
- console.log('Port is occupied, will use different port');
346
- // Continue execution instead of exiting
347
- }
97
+ // Throws/exits if port busy
98
+ await checkPortAvailability(3000, 'localhost', true);
348
99
  ```
349
100
 
350
- ### Tool Result Formatting
351
-
352
- ```typescript
353
- import { formatToolResult, getJsonFromResult } from 'fa-mcp-sdk';
354
-
355
- // formatToolResult - format tool execution results based on configuration
356
- // Function Signature:
357
- function formatToolResult (json: any): any {...}
358
-
359
- // Behavior depends on appConfig.mcp.toolAnswerAs setting:
360
- // - 'structuredContent': Returns { structuredContent: json }
361
- // - 'text': Returns { content: [{ type: 'text', text: JSON.stringify(json, null, 2) }] }
362
-
363
- // Examples:
364
- const result = {
365
- message: 'Operation completed',
366
- data: { count: 42, items: ['a', 'b'] },
367
- timestamp: new Date().toISOString(),
368
- };
369
-
370
- const formattedResult = formatToolResult(result);
371
-
372
- // If toolAnswerAs = 'structuredContent':
373
- // {
374
- // structuredContent: {
375
- // message: 'Operation completed',
376
- // data: { count: 42, items: ['a', 'b'] },
377
- // timestamp: '2025-01-01T12:00:00.000Z'
378
- // }
379
- // }
380
-
381
- // If toolAnswerAs = 'text':
382
- // {
383
- // content: [{
384
- // type: 'text',
385
- // text: '{\n "message": "Operation completed",\n "data": {\n "count": 42,\n "items": ["a", "b"]\n },\n "timestamp": "2025-01-01T12:00:00.000Z"\n}'
386
- // }]
387
- // }
388
-
389
- // getJsonFromResult - extract original JSON from formatted result
390
- // Function Signature:
391
- const getJsonFromResult = <T = any> (result: any): T {...}
392
-
393
- // Examples:
394
- const originalData1 = getJsonFromResult<MyDataType>(formattedResult);
395
-
396
- // Works with both response formats:
397
- const structuredResponse = { structuredContent: { user: 'john', age: 30 } };
398
- const textResponse = {
399
- content: [{ type: 'text', text: '{"user":"john","age":30}' }]
400
- };
401
-
402
- const data1 = getJsonFromResult(structuredResponse); // { user: 'john', age: 30 }
403
- const data2 = getJsonFromResult(textResponse); // { user: 'john', age: 30 }
404
- ```
405
-
406
- ---
407
-
408
101
  ## Logging
409
102
 
410
103
  ```typescript
411
104
  import { logger, fileLogger } from 'fa-mcp-sdk';
412
105
 
413
- // Console logging
414
- logger.info('Server started successfully');
415
- logger.warn('Warning message');
416
- logger.error('Error occurred', error);
106
+ logger.info('Server started');
107
+ logger.warn('Warning');
108
+ logger.error('Error', error);
417
109
 
418
- // File logging (if configured)
419
- fileLogger.info('This goes to file');
420
-
421
- // Ensure file logs are written before shutdown
422
- await fileLogger.asyncFinish();
110
+ fileLogger.info('To file');
111
+ await fileLogger.asyncFinish(); // Flush before shutdown
423
112
  ```
424
113
 
425
- ---
426
-
427
114
  ## Event System
428
115
 
429
116
  ```typescript
430
117
  import { eventEmitter } from 'fa-mcp-sdk';
431
118
 
432
- // Listen for events
433
- eventEmitter.on('server:started', (data) => {
434
- console.log('Server started with config:', data);
435
- });
436
-
437
- // Emit custom events
119
+ eventEmitter.on('server:started', (data) => console.log(data));
438
120
  eventEmitter.emit('custom:event', { data: 'example' });
439
121
  ```
440
122
 
441
- ---
442
-
443
123
  ## Consul Integration
444
124
 
445
- If using Consul for service discovery:
446
-
447
125
  ```typescript
448
- import {
449
- getConsulAPI,
450
- accessPointUpdater,
451
- deregisterServiceFromConsul
452
- } from 'fa-mcp-sdk';
453
-
454
- // getConsulAPI - get configured Consul client instance
455
- // Function Signature:
456
- const getConsulAPI = async (): Promise<any> {...}
457
-
458
- // Returns Consul API client configured from appConfig.consul settings
459
- // Example:
460
- const consulApi = await getConsulAPI();
461
- const services = await consulApi.catalog.service.list();
462
- console.log('Available services:', services);
463
-
464
- // deregisterServiceFromConsul - remove service registration from Consul
465
- // Function Signature:
466
- const deregisterServiceFromConsul = async (): Promise<void> {...}
467
-
468
- // Note: This function reads serviceId from command line arguments (process.argv)
469
- // Usage in command line context:
470
- // node script.js <serviceId> [agentHost] [agentPort]
471
-
472
- // Example programmatic usage:
473
- await deregisterServiceFromConsul();
126
+ import { getConsulAPI, accessPointUpdater, deregisterServiceFromConsul } from 'fa-mcp-sdk';
474
127
 
475
- // accessPointUpdater - manage access point lifecycle
476
- // Object with start/stop methods:
477
- const accessPointUpdater = {
478
- start(): void; // Start automatic access point updates
479
- stop(): void; // Stop automatic access point updates
480
- }
128
+ const consul = await getConsulAPI();
129
+ const services = await consul.catalog.service.list();
481
130
 
482
- // Examples:
483
- accessPointUpdater.start(); // Automatically starts if appConfig.accessPoints configured
484
- accessPointUpdater.stop(); // Stop updates (called automatically on shutdown)
485
-
486
- // Access point configuration in config/default.yaml:
487
- // accessPoints:
488
- // myService:
489
- // title: 'My remote service'
490
- // host: <host>
491
- // port: 9999
492
- // token: '***'
493
- // noConsul: true
494
- // consulServiceName: <consulServiceName>
495
- ```
131
+ accessPointUpdater.start(); // Auto-update access points
132
+ accessPointUpdater.stop();
496
133
 
497
- ---
134
+ await deregisterServiceFromConsul();
135
+ ```
498
136
 
499
137
  ## Graceful Shutdown
500
138
 
501
139
  ```typescript
502
140
  import { gracefulShutdown } from 'fa-mcp-sdk';
503
141
 
504
- // gracefulShutdown - perform graceful application shutdown
505
- // Function Signature:
506
- async function gracefulShutdown (signal: string, exitCode: number = 0): Promise<void> {...}
507
-
508
- // Automatically handles:
509
- // - Stopping Consul service registration
510
- // - Closing database connections
511
- // - Flushing file logs
512
- // - Stopping access point updater
513
- // - Process exit with specified code
514
-
515
- // Examples:
516
- // Manual shutdown
517
- process.on('SIGUSR2', () => {
518
- gracefulShutdown('SIGUSR2', 0);
519
- });
520
-
521
- // Emergency shutdown
522
- process.on('uncaughtException', (error) => {
523
- console.error('Uncaught exception:', error);
524
- gracefulShutdown('UNCAUGHT_EXCEPTION', 1);
525
- });
142
+ // Handles: Consul deregistration, DB close, log flush, etc.
143
+ process.on('SIGUSR2', () => gracefulShutdown('SIGUSR2', 0));
526
144
 
527
- // Note: SDK automatically registers SIGINT and SIGTERM handlers
528
- // in initMcpServer(), so manual registration is only needed for custom signals
145
+ // SDK auto-registers SIGINT/SIGTERM handlers
529
146
  ```