mcp-ts-template 1.1.6

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 (65) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +233 -0
  3. package/dist/config/index.d.ts +73 -0
  4. package/dist/config/index.js +125 -0
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.js +162 -0
  7. package/dist/mcp-client/client.d.ts +36 -0
  8. package/dist/mcp-client/client.js +276 -0
  9. package/dist/mcp-client/configLoader.d.ts +75 -0
  10. package/dist/mcp-client/configLoader.js +203 -0
  11. package/dist/mcp-client/index.d.ts +10 -0
  12. package/dist/mcp-client/index.js +14 -0
  13. package/dist/mcp-client/transport.d.ts +34 -0
  14. package/dist/mcp-client/transport.js +183 -0
  15. package/dist/mcp-server/resources/echoResource/echoResourceLogic.d.ts +38 -0
  16. package/dist/mcp-server/resources/echoResource/echoResourceLogic.js +40 -0
  17. package/dist/mcp-server/resources/echoResource/index.d.ts +5 -0
  18. package/dist/mcp-server/resources/echoResource/index.js +5 -0
  19. package/dist/mcp-server/resources/echoResource/registration.d.ts +12 -0
  20. package/dist/mcp-server/resources/echoResource/registration.js +122 -0
  21. package/dist/mcp-server/server.d.ts +27 -0
  22. package/dist/mcp-server/server.js +176 -0
  23. package/dist/mcp-server/tools/echoTool/echoToolLogic.d.ts +68 -0
  24. package/dist/mcp-server/tools/echoTool/echoToolLogic.js +73 -0
  25. package/dist/mcp-server/tools/echoTool/index.d.ts +5 -0
  26. package/dist/mcp-server/tools/echoTool/index.js +5 -0
  27. package/dist/mcp-server/tools/echoTool/registration.d.ts +12 -0
  28. package/dist/mcp-server/tools/echoTool/registration.js +86 -0
  29. package/dist/mcp-server/transports/authentication/authMiddleware.d.ts +57 -0
  30. package/dist/mcp-server/transports/authentication/authMiddleware.js +145 -0
  31. package/dist/mcp-server/transports/httpTransport.d.ts +23 -0
  32. package/dist/mcp-server/transports/httpTransport.js +411 -0
  33. package/dist/mcp-server/transports/stdioTransport.d.ts +40 -0
  34. package/dist/mcp-server/transports/stdioTransport.js +70 -0
  35. package/dist/types-global/errors.d.ts +73 -0
  36. package/dist/types-global/errors.js +66 -0
  37. package/dist/utils/index.d.ts +4 -0
  38. package/dist/utils/index.js +12 -0
  39. package/dist/utils/internal/errorHandler.d.ts +90 -0
  40. package/dist/utils/internal/errorHandler.js +247 -0
  41. package/dist/utils/internal/index.d.ts +3 -0
  42. package/dist/utils/internal/index.js +3 -0
  43. package/dist/utils/internal/logger.d.ts +50 -0
  44. package/dist/utils/internal/logger.js +267 -0
  45. package/dist/utils/internal/requestContext.d.ts +47 -0
  46. package/dist/utils/internal/requestContext.js +48 -0
  47. package/dist/utils/metrics/index.d.ts +1 -0
  48. package/dist/utils/metrics/index.js +1 -0
  49. package/dist/utils/metrics/tokenCounter.d.ts +27 -0
  50. package/dist/utils/metrics/tokenCounter.js +124 -0
  51. package/dist/utils/parsing/dateParser.d.ts +27 -0
  52. package/dist/utils/parsing/dateParser.js +62 -0
  53. package/dist/utils/parsing/index.d.ts +2 -0
  54. package/dist/utils/parsing/index.js +2 -0
  55. package/dist/utils/parsing/jsonParser.d.ts +46 -0
  56. package/dist/utils/parsing/jsonParser.js +79 -0
  57. package/dist/utils/security/idGenerator.d.ts +93 -0
  58. package/dist/utils/security/idGenerator.js +147 -0
  59. package/dist/utils/security/index.d.ts +3 -0
  60. package/dist/utils/security/index.js +3 -0
  61. package/dist/utils/security/rateLimiter.d.ts +92 -0
  62. package/dist/utils/security/rateLimiter.js +171 -0
  63. package/dist/utils/security/sanitization.d.ts +180 -0
  64. package/dist/utils/security/sanitization.js +372 -0
  65. package/package.json +79 -0
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Handles the setup and connection for the Stdio MCP transport.
3
+ * Implements the MCP Specification 2025-03-26 for stdio transport.
4
+ * This transport communicates directly over standard input (stdin) and
5
+ * standard output (stdout), typically used when the MCP server is launched
6
+ * as a child process by a host application.
7
+ *
8
+ * Specification Reference:
9
+ * https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx#stdio
10
+ *
11
+ * --- Authentication Note ---
12
+ * As per the MCP Authorization Specification (2025-03-26, Section 1.2),
13
+ * STDIO transports SHOULD NOT implement HTTP-based authentication flows.
14
+ * Authorization is typically handled implicitly by the host application
15
+ * controlling the server process. This implementation follows that guideline.
16
+ *
17
+ * @see {@link https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/authorization.mdx | MCP Authorization Specification}
18
+ */
19
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
20
+ // Import core utilities: ErrorHandler for centralized error management and logger for logging.
21
+ import { ErrorHandler, logger } from '../../utils/index.js';
22
+ /**
23
+ * Connects a given McpServer instance to the Stdio transport. (Asynchronous)
24
+ * Initializes the SDK's StdioServerTransport, which handles reading newline-delimited
25
+ * JSON-RPC messages from process.stdin and writing corresponding messages to process.stdout,
26
+ * adhering to the MCP stdio transport specification.
27
+ *
28
+ * MCP Spec Points Covered by SDK's StdioServerTransport:
29
+ * - Reads JSON-RPC messages (requests, notifications, responses, batches) from stdin.
30
+ * - Writes JSON-RPC messages to stdout.
31
+ * - Handles newline delimiters and ensures no embedded newlines in output messages.
32
+ * - Ensures only valid MCP messages are written to stdout.
33
+ *
34
+ * Note: Logging via the `logger` utility MAY result in output to stderr, which is
35
+ * permitted by the spec for logging purposes.
36
+ *
37
+ * @param {McpServer} server - The McpServer instance containing the core logic (tools, resources).
38
+ * @param {Record<string, any>} context - Logging context for correlation.
39
+ * @returns {Promise<void>} A promise that resolves when the connection is successfully established.
40
+ * @throws {Error} Throws an error if the connection fails during setup (e.g., issues connecting server to transport).
41
+ */
42
+ export async function connectStdioTransport(server, context) {
43
+ // Add a specific operation name to the context for better log filtering.
44
+ const operationContext = { ...context, operation: 'connectStdioTransport', transportType: 'Stdio' };
45
+ logger.debug('Attempting to connect stdio transport...', operationContext);
46
+ try {
47
+ logger.debug('Creating StdioServerTransport instance...', operationContext);
48
+ // Instantiate the transport provided by the SDK for standard I/O communication.
49
+ // This class encapsulates the logic for reading from stdin and writing to stdout
50
+ // according to the MCP stdio spec.
51
+ const transport = new StdioServerTransport();
52
+ logger.debug('Connecting McpServer instance to StdioServerTransport...', operationContext);
53
+ // Establish the link between the server's core logic and the transport layer.
54
+ // This internally starts the necessary listeners on process.stdin.
55
+ await server.connect(transport);
56
+ // Log successful connection. The server is now ready to process messages via stdio.
57
+ logger.info('MCP Server connected and listening via stdio transport.', operationContext);
58
+ // Use console.log for prominent startup message visibility when run directly, only if TTY.
59
+ if (process.stdout.isTTY) {
60
+ console.log(`\n🚀 MCP Server running in STDIO mode.\n (MCP Spec: 2025-03-26 Stdio Transport)\n`);
61
+ }
62
+ }
63
+ catch (err) {
64
+ // Catch and handle any critical errors during the transport connection setup.
65
+ // Mark as critical because the server cannot function without a connected transport.
66
+ ErrorHandler.handleError(err, { ...operationContext, critical: true });
67
+ // Rethrow the error to signal the failure to the calling code (e.g., the main server startup).
68
+ throw err;
69
+ }
70
+ }
@@ -0,0 +1,73 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Defines a set of standardized error codes for common issues within MCP servers or tools.
4
+ * These codes help clients understand the nature of an error programmatically.
5
+ */
6
+ export declare enum BaseErrorCode {
7
+ /** Access denied due to invalid credentials or lack of authentication. */
8
+ UNAUTHORIZED = "UNAUTHORIZED",
9
+ /** Access denied despite valid authentication, due to insufficient permissions. */
10
+ FORBIDDEN = "FORBIDDEN",
11
+ /** The requested resource or entity could not be found. */
12
+ NOT_FOUND = "NOT_FOUND",
13
+ /** The request could not be completed due to a conflict with the current state of the resource. */
14
+ CONFLICT = "CONFLICT",
15
+ /** The request failed due to invalid input parameters or data. */
16
+ VALIDATION_ERROR = "VALIDATION_ERROR",
17
+ /** An error occurred while parsing input data (e.g., date string, JSON). */
18
+ PARSING_ERROR = "PARSING_ERROR",
19
+ /** The request was rejected because the client has exceeded rate limits. */
20
+ RATE_LIMITED = "RATE_LIMITED",
21
+ /** The request timed out before a response could be generated. */
22
+ TIMEOUT = "TIMEOUT",
23
+ /** The service is temporarily unavailable, possibly due to maintenance or overload. */
24
+ SERVICE_UNAVAILABLE = "SERVICE_UNAVAILABLE",
25
+ /** An unexpected error occurred on the server side. */
26
+ INTERNAL_ERROR = "INTERNAL_ERROR",
27
+ /** An error occurred, but the specific cause is unknown or cannot be categorized. */
28
+ UNKNOWN_ERROR = "UNKNOWN_ERROR",
29
+ /** An error occurred during the loading or validation of configuration data. */
30
+ CONFIGURATION_ERROR = "CONFIGURATION_ERROR"
31
+ }
32
+ /**
33
+ * Custom error class for MCP-specific errors.
34
+ * Encapsulates a `BaseErrorCode`, a descriptive message, and optional details.
35
+ * Provides a method to format the error into a standard MCP tool response.
36
+ */
37
+ export declare class McpError extends Error {
38
+ code: BaseErrorCode;
39
+ details?: Record<string, unknown> | undefined;
40
+ /**
41
+ * Creates an instance of McpError.
42
+ * @param {BaseErrorCode} code - The standardized error code.
43
+ * @param {string} message - A human-readable description of the error.
44
+ * @param {Record<string, unknown>} [details] - Optional additional details about the error.
45
+ */
46
+ constructor(code: BaseErrorCode, message: string, details?: Record<string, unknown> | undefined);
47
+ }
48
+ /**
49
+ * Zod schema for validating error objects, potentially used for parsing
50
+ * error responses or validating error structures internally.
51
+ */
52
+ export declare const ErrorSchema: z.ZodObject<{
53
+ /** The error code, corresponding to BaseErrorCode enum values. */
54
+ code: z.ZodNativeEnum<typeof BaseErrorCode>;
55
+ /** A human-readable description of the error. */
56
+ message: z.ZodString;
57
+ /** Optional additional details or context about the error. */
58
+ details: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
59
+ }, "strip", z.ZodTypeAny, {
60
+ code: BaseErrorCode;
61
+ message: string;
62
+ details?: Record<string, unknown> | undefined;
63
+ }, {
64
+ code: BaseErrorCode;
65
+ message: string;
66
+ details?: Record<string, unknown> | undefined;
67
+ }>;
68
+ /**
69
+ * TypeScript type inferred from `ErrorSchema`.
70
+ * Represents a validated error object structure.
71
+ * @typedef {z.infer<typeof ErrorSchema>} ErrorResponse
72
+ */
73
+ export type ErrorResponse = z.infer<typeof ErrorSchema>;
@@ -0,0 +1,66 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Defines a set of standardized error codes for common issues within MCP servers or tools.
4
+ * These codes help clients understand the nature of an error programmatically.
5
+ */
6
+ export var BaseErrorCode;
7
+ (function (BaseErrorCode) {
8
+ /** Access denied due to invalid credentials or lack of authentication. */
9
+ BaseErrorCode["UNAUTHORIZED"] = "UNAUTHORIZED";
10
+ /** Access denied despite valid authentication, due to insufficient permissions. */
11
+ BaseErrorCode["FORBIDDEN"] = "FORBIDDEN";
12
+ /** The requested resource or entity could not be found. */
13
+ BaseErrorCode["NOT_FOUND"] = "NOT_FOUND";
14
+ /** The request could not be completed due to a conflict with the current state of the resource. */
15
+ BaseErrorCode["CONFLICT"] = "CONFLICT";
16
+ /** The request failed due to invalid input parameters or data. */
17
+ BaseErrorCode["VALIDATION_ERROR"] = "VALIDATION_ERROR";
18
+ /** An error occurred while parsing input data (e.g., date string, JSON). */
19
+ BaseErrorCode["PARSING_ERROR"] = "PARSING_ERROR";
20
+ /** The request was rejected because the client has exceeded rate limits. */
21
+ BaseErrorCode["RATE_LIMITED"] = "RATE_LIMITED";
22
+ /** The request timed out before a response could be generated. */
23
+ BaseErrorCode["TIMEOUT"] = "TIMEOUT";
24
+ /** The service is temporarily unavailable, possibly due to maintenance or overload. */
25
+ BaseErrorCode["SERVICE_UNAVAILABLE"] = "SERVICE_UNAVAILABLE";
26
+ /** An unexpected error occurred on the server side. */
27
+ BaseErrorCode["INTERNAL_ERROR"] = "INTERNAL_ERROR";
28
+ /** An error occurred, but the specific cause is unknown or cannot be categorized. */
29
+ BaseErrorCode["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
30
+ /** An error occurred during the loading or validation of configuration data. */
31
+ BaseErrorCode["CONFIGURATION_ERROR"] = "CONFIGURATION_ERROR";
32
+ })(BaseErrorCode || (BaseErrorCode = {}));
33
+ /**
34
+ * Custom error class for MCP-specific errors.
35
+ * Encapsulates a `BaseErrorCode`, a descriptive message, and optional details.
36
+ * Provides a method to format the error into a standard MCP tool response.
37
+ */
38
+ export class McpError extends Error {
39
+ /**
40
+ * Creates an instance of McpError.
41
+ * @param {BaseErrorCode} code - The standardized error code.
42
+ * @param {string} message - A human-readable description of the error.
43
+ * @param {Record<string, unknown>} [details] - Optional additional details about the error.
44
+ */
45
+ constructor(code, message, details) {
46
+ super(message);
47
+ this.code = code;
48
+ this.details = details;
49
+ // Set the error name for identification
50
+ this.name = 'McpError';
51
+ // Ensure the prototype chain is correct
52
+ Object.setPrototypeOf(this, McpError.prototype);
53
+ }
54
+ }
55
+ /**
56
+ * Zod schema for validating error objects, potentially used for parsing
57
+ * error responses or validating error structures internally.
58
+ */
59
+ export const ErrorSchema = z.object({
60
+ /** The error code, corresponding to BaseErrorCode enum values. */
61
+ code: z.nativeEnum(BaseErrorCode).describe("Standardized error code"),
62
+ /** A human-readable description of the error. */
63
+ message: z.string().describe("Detailed error message"),
64
+ /** Optional additional details or context about the error. */
65
+ details: z.record(z.unknown()).optional().describe("Optional structured error details")
66
+ }).describe("Schema for validating structured error objects.");
@@ -0,0 +1,4 @@
1
+ export * from './internal/index.js';
2
+ export * from './parsing/index.js';
3
+ export * from './security/index.js';
4
+ export * from './metrics/index.js';
@@ -0,0 +1,12 @@
1
+ // Re-export all utilities from their categorized subdirectories
2
+ export * from './internal/index.js';
3
+ export * from './parsing/index.js';
4
+ export * from './security/index.js';
5
+ export * from './metrics/index.js';
6
+ // It's good practice to have index.ts files in each subdirectory
7
+ // that export the contents of that directory.
8
+ // Assuming those will be created or already exist.
9
+ // If not, this might need adjustment to export specific files, e.g.:
10
+ // export * from './internal/errorHandler.js';
11
+ // export * from './internal/logger.js';
12
+ // ... etc.
@@ -0,0 +1,90 @@
1
+ import { BaseErrorCode } from '../../types-global/errors.js';
2
+ /**
3
+ * Generic error context interface
4
+ */
5
+ export interface ErrorContext {
6
+ /** Unique request or operation identifier */
7
+ requestId?: string;
8
+ /** Any additional context information */
9
+ [key: string]: unknown;
10
+ }
11
+ /**
12
+ * Error handler options
13
+ */
14
+ export interface ErrorHandlerOptions {
15
+ /** The context of the operation that caused the error */
16
+ context?: ErrorContext;
17
+ /** The name of the operation being performed */
18
+ operation: string;
19
+ /** The input that caused the error */
20
+ input?: unknown;
21
+ /** Whether to rethrow the error after handling */
22
+ rethrow?: boolean;
23
+ /** Custom error code to use when creating an McpError */
24
+ errorCode?: BaseErrorCode;
25
+ /** Custom error mapper function */
26
+ errorMapper?: (error: unknown) => Error;
27
+ /** Whether to include stack traces in logs */
28
+ includeStack?: boolean;
29
+ /** Whether this is a critical error that should abort operations */
30
+ critical?: boolean;
31
+ }
32
+ /**
33
+ * Base error mapping rule
34
+ */
35
+ export interface BaseErrorMapping {
36
+ /** Pattern to match in the error message */
37
+ pattern: string | RegExp;
38
+ /** Error code for mapped errors */
39
+ errorCode: BaseErrorCode;
40
+ /** Custom error message template */
41
+ messageTemplate?: string;
42
+ }
43
+ /**
44
+ * Error mapping configuration
45
+ */
46
+ export interface ErrorMapping<T extends Error = Error> extends BaseErrorMapping {
47
+ /** Factory function to create the mapped error */
48
+ factory: (error: unknown, context?: Record<string, unknown>) => T;
49
+ /** Additional context to merge with error context */
50
+ additionalContext?: Record<string, unknown>;
51
+ }
52
+ /**
53
+ * Error handler utility class with various error handling methods
54
+ */
55
+ export declare class ErrorHandler {
56
+ /**
57
+ * Determine the appropriate error code for an error based on patterns and type
58
+ * @param error The error to classify
59
+ * @returns The appropriate error code
60
+ */
61
+ static determineErrorCode(error: unknown): BaseErrorCode;
62
+ /**
63
+ * Handle operation errors with consistent logging and transformation
64
+ * @param error The error that occurred
65
+ * @param options Error handling options
66
+ * @returns The transformed error
67
+ */
68
+ static handleError(error: unknown, options: ErrorHandlerOptions): Error;
69
+ /**
70
+ * Map an error to a specific error type based on error message patterns
71
+ * @param error The error to map
72
+ * @param mappings Array of pattern and factory mappings
73
+ * @param defaultFactory Default factory function if no pattern matches
74
+ * @returns The mapped error
75
+ */
76
+ static mapError<T extends Error>(error: unknown, mappings: ErrorMapping<T>[], defaultFactory?: (error: unknown, context?: Record<string, unknown>) => T): T | Error;
77
+ /**
78
+ * Format an error for consistent response structure
79
+ * @param error The error to format
80
+ * @returns Formatted error object
81
+ */
82
+ static formatError(error: unknown): Record<string, unknown>;
83
+ /**
84
+ * Safely execute a function and handle any errors
85
+ * @param fn Function to execute
86
+ * @param options Error handling options
87
+ * @returns The result of the function or error
88
+ */
89
+ static tryCatch<T>(fn: () => Promise<T> | T, options: ErrorHandlerOptions): Promise<T>;
90
+ }
@@ -0,0 +1,247 @@
1
+ import { BaseErrorCode, McpError } from '../../types-global/errors.js'; // Corrected path
2
+ import { logger } from './logger.js';
3
+ import { sanitizeInputForLogging } from '../index.js'; // Import from main barrel file
4
+ /**
5
+ * Simple mapper that maps error types to error codes
6
+ */
7
+ const ERROR_TYPE_MAPPINGS = {
8
+ 'SyntaxError': BaseErrorCode.VALIDATION_ERROR,
9
+ 'TypeError': BaseErrorCode.VALIDATION_ERROR,
10
+ 'ReferenceError': BaseErrorCode.INTERNAL_ERROR,
11
+ 'RangeError': BaseErrorCode.VALIDATION_ERROR,
12
+ 'URIError': BaseErrorCode.VALIDATION_ERROR,
13
+ 'EvalError': BaseErrorCode.INTERNAL_ERROR
14
+ };
15
+ /**
16
+ * Common error patterns for automatic classification
17
+ */
18
+ const COMMON_ERROR_PATTERNS = [
19
+ // Authentication related errors
20
+ { pattern: /auth|unauthorized|unauthenticated|not.*logged.*in|invalid.*token|expired.*token/i, errorCode: BaseErrorCode.UNAUTHORIZED },
21
+ // Permission related errors
22
+ { pattern: /permission|forbidden|access.*denied|not.*allowed/i, errorCode: BaseErrorCode.FORBIDDEN },
23
+ // Not found errors
24
+ { pattern: /not.*found|missing|no.*such|doesn't.*exist|couldn't.*find/i, errorCode: BaseErrorCode.NOT_FOUND },
25
+ // Validation errors
26
+ { pattern: /invalid|validation|malformed|bad request|wrong format/i, errorCode: BaseErrorCode.VALIDATION_ERROR },
27
+ // Conflict errors
28
+ { pattern: /conflict|already.*exists|duplicate|unique.*constraint/i, errorCode: BaseErrorCode.CONFLICT },
29
+ // Rate limiting
30
+ { pattern: /rate.*limit|too.*many.*requests|throttled/i, errorCode: BaseErrorCode.RATE_LIMITED },
31
+ // Timeout errors
32
+ { pattern: /timeout|timed.*out|deadline.*exceeded/i, errorCode: BaseErrorCode.TIMEOUT },
33
+ // External service errors
34
+ { pattern: /service.*unavailable|bad.*gateway|gateway.*timeout/i, errorCode: BaseErrorCode.SERVICE_UNAVAILABLE }
35
+ ];
36
+ /**
37
+ * Get a readable name for an error
38
+ * @param error Error to get name for
39
+ * @returns User-friendly error name
40
+ */
41
+ function getErrorName(error) {
42
+ if (error instanceof Error) {
43
+ return error.name || 'Error';
44
+ }
45
+ if (error === null) {
46
+ return 'NullError';
47
+ }
48
+ if (error === undefined) {
49
+ return 'UndefinedError';
50
+ }
51
+ return typeof error === 'object'
52
+ ? 'ObjectError'
53
+ : 'UnknownError';
54
+ }
55
+ /**
56
+ * Get a message from an error
57
+ * @param error Error to get message from
58
+ * @returns Error message
59
+ */
60
+ function getErrorMessage(error) {
61
+ if (error instanceof Error) {
62
+ return error.message;
63
+ }
64
+ if (error === null) {
65
+ return 'Null error occurred';
66
+ }
67
+ if (error === undefined) {
68
+ return 'Undefined error occurred';
69
+ }
70
+ return typeof error === 'string'
71
+ ? error
72
+ : String(error);
73
+ }
74
+ /**
75
+ * Error handler utility class with various error handling methods
76
+ */
77
+ export class ErrorHandler {
78
+ /**
79
+ * Determine the appropriate error code for an error based on patterns and type
80
+ * @param error The error to classify
81
+ * @returns The appropriate error code
82
+ */
83
+ static determineErrorCode(error) {
84
+ // If it's already an McpError, use its code
85
+ if (error instanceof McpError) {
86
+ return error.code;
87
+ }
88
+ const errorName = getErrorName(error);
89
+ const errorMessage = getErrorMessage(error);
90
+ // Check if the error type has a direct mapping
91
+ if (errorName in ERROR_TYPE_MAPPINGS) {
92
+ return ERROR_TYPE_MAPPINGS[errorName];
93
+ }
94
+ // Check for common error patterns
95
+ for (const pattern of COMMON_ERROR_PATTERNS) {
96
+ const regex = pattern.pattern instanceof RegExp
97
+ ? pattern.pattern
98
+ : new RegExp(pattern.pattern, 'i');
99
+ if (regex.test(errorMessage) || regex.test(errorName)) {
100
+ return pattern.errorCode;
101
+ }
102
+ }
103
+ // Default to internal error if no pattern matches
104
+ return BaseErrorCode.INTERNAL_ERROR;
105
+ }
106
+ /**
107
+ * Handle operation errors with consistent logging and transformation
108
+ * @param error The error that occurred
109
+ * @param options Error handling options
110
+ * @returns The transformed error
111
+ */
112
+ static handleError(error, options) {
113
+ const { context, operation, input, rethrow = false, errorCode: explicitErrorCode, includeStack = true, critical = false } = options;
114
+ // If it's already an McpError, use it directly but apply additional context
115
+ if (error instanceof McpError) {
116
+ // Add any additional context
117
+ if (context && Object.keys(context).length > 0) {
118
+ // Ensure details is an object before spreading
119
+ const existingDetails = typeof error.details === 'object' && error.details !== null ? error.details : {};
120
+ error.details = { ...existingDetails, ...context };
121
+ }
122
+ // Log the error with sanitized input
123
+ logger.error(`Error ${operation}: ${error.message}`, {
124
+ errorCode: error.code,
125
+ requestId: context?.requestId,
126
+ input: input ? sanitizeInputForLogging(input) : undefined,
127
+ stack: includeStack ? error.stack : undefined,
128
+ critical,
129
+ ...context
130
+ });
131
+ if (rethrow) {
132
+ throw error;
133
+ }
134
+ // Ensure the function returns an Error type
135
+ return error;
136
+ }
137
+ // Sanitize input for logging
138
+ const sanitizedInput = input ? sanitizeInputForLogging(input) : undefined;
139
+ // Log the error with consistent format
140
+ logger.error(`Error ${operation}`, {
141
+ error: getErrorMessage(error), // Use helper function
142
+ errorType: getErrorName(error),
143
+ input: sanitizedInput,
144
+ requestId: context?.requestId,
145
+ stack: includeStack && error instanceof Error ? error.stack : undefined,
146
+ critical,
147
+ ...context
148
+ });
149
+ // Choose the error code (explicit > determined > default)
150
+ const errorCode = explicitErrorCode ||
151
+ ErrorHandler.determineErrorCode(error) ||
152
+ BaseErrorCode.INTERNAL_ERROR;
153
+ // Transform to appropriate error type
154
+ let transformedError;
155
+ if (options.errorMapper) {
156
+ transformedError = options.errorMapper(error);
157
+ }
158
+ else {
159
+ transformedError = new McpError(errorCode, `Error ${operation}: ${getErrorMessage(error)}`, // Use helper function
160
+ {
161
+ originalError: getErrorName(error),
162
+ ...context
163
+ });
164
+ }
165
+ // Rethrow if requested
166
+ if (rethrow) {
167
+ throw transformedError;
168
+ }
169
+ // Ensure the function returns an Error type
170
+ return transformedError;
171
+ }
172
+ /**
173
+ * Map an error to a specific error type based on error message patterns
174
+ * @param error The error to map
175
+ * @param mappings Array of pattern and factory mappings
176
+ * @param defaultFactory Default factory function if no pattern matches
177
+ * @returns The mapped error
178
+ */
179
+ static mapError(error, mappings, defaultFactory) {
180
+ // If it's already the target type and we have a default factory to check against, return it
181
+ if (defaultFactory && error instanceof Error) {
182
+ const defaultInstance = defaultFactory(error);
183
+ if (error.constructor === defaultInstance.constructor) {
184
+ return error;
185
+ }
186
+ }
187
+ const errorMessage = getErrorMessage(error);
188
+ // Check each pattern and return the first match
189
+ for (const mapping of mappings) {
190
+ const matches = mapping.pattern instanceof RegExp
191
+ ? mapping.pattern.test(errorMessage)
192
+ : errorMessage.includes(mapping.pattern);
193
+ if (matches) {
194
+ return mapping.factory(error, mapping.additionalContext);
195
+ }
196
+ }
197
+ // Return default or original error
198
+ if (defaultFactory) {
199
+ return defaultFactory(error);
200
+ }
201
+ return error instanceof Error
202
+ ? error
203
+ : new Error(String(error));
204
+ }
205
+ // Removed createErrorMapper method for simplification
206
+ /**
207
+ * Format an error for consistent response structure
208
+ * @param error The error to format
209
+ * @returns Formatted error object
210
+ */
211
+ static formatError(error) {
212
+ if (error instanceof McpError) {
213
+ return {
214
+ code: error.code,
215
+ message: error.message,
216
+ // Ensure details is an object
217
+ details: typeof error.details === 'object' && error.details !== null ? error.details : {}
218
+ };
219
+ }
220
+ if (error instanceof Error) {
221
+ return {
222
+ code: ErrorHandler.determineErrorCode(error),
223
+ message: error.message,
224
+ details: { errorType: error.name }
225
+ };
226
+ }
227
+ return {
228
+ code: BaseErrorCode.UNKNOWN_ERROR,
229
+ message: String(error),
230
+ details: { errorType: typeof error }
231
+ };
232
+ }
233
+ /**
234
+ * Safely execute a function and handle any errors
235
+ * @param fn Function to execute
236
+ * @param options Error handling options
237
+ * @returns The result of the function or error
238
+ */
239
+ static async tryCatch(fn, options) {
240
+ try {
241
+ return await fn();
242
+ }
243
+ catch (error) {
244
+ throw ErrorHandler.handleError(error, { ...options, rethrow: true });
245
+ }
246
+ }
247
+ }
@@ -0,0 +1,3 @@
1
+ export * from './errorHandler.js';
2
+ export * from './logger.js';
3
+ export * from './requestContext.js';
@@ -0,0 +1,3 @@
1
+ export * from './errorHandler.js';
2
+ export * from './logger.js';
3
+ export * from './requestContext.js';
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Supported logging levels based on RFC 5424 Syslog severity levels used by MCP.
3
+ * emerg: 0, alert: 1, crit: 2, error: 3, warning: 4, notice: 5, info: 6, debug: 7
4
+ */
5
+ export type McpLogLevel = 'debug' | 'info' | 'notice' | 'warning' | 'error' | 'crit' | 'alert' | 'emerg';
6
+ export type McpNotificationSender = (level: McpLogLevel, data: any, loggerName?: string) => void;
7
+ /**
8
+ * Singleton Logger wrapping Winston, adapted for MCP.
9
+ * Logs to files and optionally sends MCP notifications/message.
10
+ */
11
+ declare class Logger {
12
+ private static instance;
13
+ private winstonLogger?;
14
+ private initialized;
15
+ private mcpNotificationSender?;
16
+ private currentMcpLevel;
17
+ private currentWinstonLevel;
18
+ private constructor();
19
+ /**
20
+ * Initialize Winston logger for file transport. Must be called once at app start.
21
+ * Console transport is added conditionally.
22
+ * @param level Initial minimum level to log ('info' default).
23
+ */
24
+ initialize(level?: McpLogLevel): Promise<void>;
25
+ /**
26
+ * Sets the function used to send MCP 'notifications/message'.
27
+ */
28
+ setMcpNotificationSender(sender: McpNotificationSender | undefined): void;
29
+ /**
30
+ * Dynamically sets the minimum logging level.
31
+ */
32
+ setLevel(newLevel: McpLogLevel): void;
33
+ /** Get singleton instance. */
34
+ static getInstance(): Logger;
35
+ /** Ensures the logger has been initialized. */
36
+ private ensureInitialized;
37
+ /** Centralized log processing */
38
+ private log;
39
+ debug(msg: string, context?: Record<string, any>): void;
40
+ info(msg: string, context?: Record<string, any>): void;
41
+ notice(msg: string, context?: Record<string, any>): void;
42
+ warning(msg: string, context?: Record<string, any>): void;
43
+ error(msg: string, err?: Error | Record<string, any>, context?: Record<string, any>): void;
44
+ crit(msg: string, err?: Error | Record<string, any>, context?: Record<string, any>): void;
45
+ alert(msg: string, err?: Error | Record<string, any>, context?: Record<string, any>): void;
46
+ emerg(msg: string, err?: Error | Record<string, any>, context?: Record<string, any>): void;
47
+ fatal(msg: string, context?: Record<string, any>, error?: Error): void;
48
+ }
49
+ export declare const logger: Logger;
50
+ export {};