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,122 @@
1
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { BaseErrorCode, McpError } from '../../../types-global/errors.js';
3
+ // Import utils from the main barrel file (ErrorHandler, logger, requestContextService from ../../../utils/internal/*)
4
+ import { ErrorHandler, logger, requestContextService } from '../../../utils/index.js';
5
+ // Import logic, schema, and type from the dedicated logic file
6
+ import { processEchoResource } from './echoResourceLogic.js'; // Removed querySchema import
7
+ // Type inference for UnsubscribeRequest removed as it's not handled
8
+ /**
9
+ * Registers the 'echo' resource and its handlers with the provided MCP server instance.
10
+ * This includes defining the resource template, metadata, query schema, examples,
11
+ * and the core request handling logic. Error handling is integrated using ErrorHandler.
12
+ *
13
+ * @function registerEchoResource
14
+ * @param {McpServer} server - The MCP server instance to register the resource with.
15
+ * @returns {Promise<void>} A promise that resolves when the resource registration is complete.
16
+ * @throws {McpError} Throws an McpError if the registration process fails critically.
17
+ */
18
+ export const registerEchoResource = async (server) => {
19
+ const resourceName = "echo-resource"; // Internal identifier for the resource
20
+ // Create registration context using the service
21
+ const registrationContext = requestContextService.createRequestContext({
22
+ operation: 'RegisterEchoResource',
23
+ resourceName: resourceName,
24
+ module: 'EchoResourceRegistration'
25
+ });
26
+ logger.info(`Registering resource: ${resourceName}`, registrationContext);
27
+ // Use ErrorHandler to wrap the entire registration process for robustness
28
+ await ErrorHandler.tryCatch(async () => {
29
+ // Define the resource template structure (URI pattern and basic operations)
30
+ const template = new ResourceTemplate("echo://{message}", // URI template using RFC 6570 syntax
31
+ {
32
+ // --- List Operation ---
33
+ // Provides a list of example or discoverable resource URIs.
34
+ list: async () => ({
35
+ resources: [{
36
+ uri: "echo://hello", // Example static URI
37
+ name: "Default Echo Message",
38
+ description: "A simple echo resource example using a default message."
39
+ }]
40
+ }),
41
+ // --- Complete Operation ---
42
+ // (Optional) Provides suggestions or completions based on partial input.
43
+ // Not implemented for this simple resource.
44
+ });
45
+ logger.debug(`Resource template created for ${resourceName}`, registrationContext);
46
+ // Register the resource, its template, metadata, and handler with the server
47
+ // This implicitly handles 'resources/read' based on the template match.
48
+ server.resource(resourceName, // The unique name for this resource registration
49
+ template, // The ResourceTemplate defined above
50
+ // --- Resource Metadata ---
51
+ {
52
+ name: "Echo Message", // User-friendly name
53
+ description: "A simple echo resource that returns a message, optionally specified in the URI.",
54
+ mimeType: "application/json", // Default MIME type for responses
55
+ // --- Query Schema ---
56
+ // Removed querySchema as path variable is used via template
57
+ // --- Examples ---
58
+ // Provides illustrative examples for clients
59
+ examples: [
60
+ {
61
+ name: "Basic echo",
62
+ uri: "echo://hello",
63
+ description: "Get a default welcome message."
64
+ },
65
+ {
66
+ name: "Custom echo",
67
+ uri: "echo://custom-message-here",
68
+ description: "Get a response echoing 'custom-message-here'."
69
+ }
70
+ ],
71
+ },
72
+ // --- Resource Handler (for resources/read implicitly) ---
73
+ // The core logic executed when a request matches the resource template.
74
+ async (uri, params) => {
75
+ // Create handler context using the service
76
+ const handlerContext = requestContextService.createRequestContext({
77
+ parentContext: registrationContext, // Link to the registration context if needed
78
+ operation: 'HandleEchoResourceRequest',
79
+ resourceName: resourceName,
80
+ uri: uri.href,
81
+ params: params // Include relevant request details
82
+ });
83
+ logger.debug("Handling echo resource request", handlerContext);
84
+ // Wrap the handler logic in tryCatch for robust error handling
85
+ return await ErrorHandler.tryCatch(async () => {
86
+ // Delegate the core processing logic, passing the context
87
+ const responseData = processEchoResource(uri, params, handlerContext);
88
+ logger.debug("Echo resource processed successfully", handlerContext);
89
+ // Return the response in the standardized format expected by the MCP SDK
90
+ // Correctly omits `type: "text"` as per 2025-03-26 spec
91
+ return {
92
+ contents: [{
93
+ uri: uri.href, // Echo back the requested URI
94
+ blob: Buffer.from(JSON.stringify(responseData)).toString('base64'), // Return Base64 encoded JSON object
95
+ mimeType: "application/json" // Specify the content type
96
+ }]
97
+ };
98
+ }, {
99
+ // Configuration for the error handler specific to this request
100
+ operation: 'processing echo resource handler',
101
+ context: handlerContext, // Pass handler-specific context
102
+ input: { uri: uri.href, params }, // Log input on error
103
+ // Provide a custom error mapping for more specific error reporting
104
+ errorMapper: (error) => new McpError(// Add type 'unknown' to error parameter
105
+ BaseErrorCode.INTERNAL_ERROR, // Map internal errors
106
+ `Error processing echo resource request for URI '${uri.href}': ${error instanceof Error ? error.message : 'Unknown error'}`, { ...handlerContext } // Include context in the McpError
107
+ )
108
+ });
109
+ }); // End of server.resource call
110
+ logger.info(`Resource registered successfully: ${resourceName}`, registrationContext);
111
+ }, {
112
+ // Configuration for the error handler wrapping the entire registration
113
+ operation: `registering resource ${resourceName}`,
114
+ context: registrationContext, // Context for registration-level errors
115
+ errorCode: BaseErrorCode.INTERNAL_ERROR, // Default error code for registration failure
116
+ // Custom error mapping for registration failures
117
+ errorMapper: (error) => new McpError(// Add type 'unknown' to error parameter
118
+ error instanceof McpError ? error.code : BaseErrorCode.INTERNAL_ERROR, `Failed to register resource '${resourceName}': ${error instanceof Error ? error.message : 'Unknown error'}`, { ...registrationContext } // Include context in the McpError
119
+ ),
120
+ critical: true // Mark registration failure as critical to halt startup
121
+ }); // End of ErrorHandler.tryCatch for registration
122
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Main entry point for the MCP (Model Context Protocol) server.
3
+ * This file orchestrates the server's lifecycle:
4
+ * 1. Initializes the core McpServer instance with its identity and capabilities.
5
+ * 2. Registers available resources and tools, making them discoverable and usable by clients.
6
+ * 3. Selects and starts the appropriate communication transport (stdio or Streamable HTTP)
7
+ * based on configuration.
8
+ * 4. Handles top-level error management during startup.
9
+ *
10
+ * MCP Specification References:
11
+ * - Lifecycle: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/lifecycle.mdx
12
+ * - Overview (Capabilities): https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/index.mdx
13
+ * - Transports: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx
14
+ */
15
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
16
+ /**
17
+ * Main application entry point. Initializes and starts the MCP server.
18
+ *
19
+ * MCP Spec Relevance:
20
+ * - Orchestrates the server startup sequence, culminating in a server ready to accept
21
+ * connections and process MCP messages according to the chosen transport's rules.
22
+ * - Implements top-level error handling for critical startup failures, ensuring the
23
+ * process exits appropriately if it cannot initialize correctly.
24
+ *
25
+ * @returns {Promise<void | McpServer>} Resolves upon successful startup (void for http, McpServer for stdio). Rejects on critical failure.
26
+ */
27
+ export declare function initializeAndStartServer(): Promise<void | McpServer>;
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Main entry point for the MCP (Model Context Protocol) server.
3
+ * This file orchestrates the server's lifecycle:
4
+ * 1. Initializes the core McpServer instance with its identity and capabilities.
5
+ * 2. Registers available resources and tools, making them discoverable and usable by clients.
6
+ * 3. Selects and starts the appropriate communication transport (stdio or Streamable HTTP)
7
+ * based on configuration.
8
+ * 4. Handles top-level error management during startup.
9
+ *
10
+ * MCP Specification References:
11
+ * - Lifecycle: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/lifecycle.mdx
12
+ * - Overview (Capabilities): https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/index.mdx
13
+ * - Transports: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx
14
+ */
15
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
16
+ // Import validated configuration and environment details.
17
+ import { config, environment } from '../config/index.js';
18
+ // Import core utilities: ErrorHandler, logger, requestContextService.
19
+ import { ErrorHandler, logger, requestContextService } from '../utils/index.js';
20
+ // Import registration functions for specific resources and tools.
21
+ import { registerEchoResource } from './resources/echoResource/index.js';
22
+ import { registerEchoTool } from './tools/echoTool/index.js';
23
+ // Import transport setup functions.
24
+ import { startHttpTransport } from './transports/httpTransport.js';
25
+ import { connectStdioTransport } from './transports/stdioTransport.js';
26
+ /**
27
+ * Creates and configures a new instance of the McpServer.
28
+ *
29
+ * This function is central to defining the server's identity and functionality
30
+ * as presented to connecting clients during the MCP initialization phase.
31
+ *
32
+ * MCP Spec Relevance:
33
+ * - Server Identity (`serverInfo`): The `name` and `version` provided here are part
34
+ * of the `ServerInformation` object returned in the `InitializeResult` message,
35
+ * allowing clients to identify the server they are connected to.
36
+ * - Capabilities Declaration: The `capabilities` object declares the features this
37
+ * server supports, enabling clients to tailor their interactions.
38
+ * - `logging: {}`: Indicates the server can receive `logging/setLevel` requests
39
+ * and may send `notifications/message` log messages (handled by the logger utility).
40
+ * - `resources: { listChanged: true }`: Signals that the server supports dynamic
41
+ * resource lists and will send `notifications/resources/list_changed` if the
42
+ * available resources change after initialization.
43
+ * - `tools: { listChanged: true }`: Signals support for dynamic tool lists and
44
+ * `notifications/tools/list_changed`.
45
+ * - Resource/Tool Registration: This function calls specific registration functions
46
+ * (e.g., `registerEchoResource`) which use SDK methods (`server.resource`, `server.tool`)
47
+ * to make capabilities available for discovery (`resources/list`, `tools/list`) and
48
+ * invocation (`resources/read`, `tools/call`).
49
+ *
50
+ * Design Note: This factory function is used to create server instances. For the 'stdio'
51
+ * transport, it's called once. For the 'http' transport, it's passed to `startHttpTransport`
52
+ * and called *per session* to ensure session isolation.
53
+ *
54
+ * @returns {Promise<McpServer>} A promise resolving with the configured McpServer instance.
55
+ * @throws {Error} If any resource or tool registration fails.
56
+ */
57
+ async function createMcpServerInstance() {
58
+ const context = { operation: 'createMcpServerInstance' };
59
+ logger.info('Initializing MCP server instance', context);
60
+ // Configure the request context service (used for correlating logs/errors).
61
+ requestContextService.configure({
62
+ appName: config.mcpServerName,
63
+ appVersion: config.mcpServerVersion,
64
+ environment,
65
+ });
66
+ // Instantiate the core McpServer using the SDK.
67
+ // Provide server identity (name, version) and declare supported capabilities.
68
+ logger.debug('Instantiating McpServer with capabilities', { ...context, serverInfo: { name: config.mcpServerName, version: config.mcpServerVersion }, capabilities: { logging: {}, resources: { listChanged: true }, tools: { listChanged: true } } });
69
+ const server = new McpServer({ name: config.mcpServerName, version: config.mcpServerVersion }, // ServerInformation part of InitializeResult
70
+ { capabilities: { logging: {}, resources: { listChanged: true }, tools: { listChanged: true } } } // Declared capabilities
71
+ );
72
+ try {
73
+ // Register all defined resources and tools. These calls populate the server's
74
+ // internal registry, making them available via MCP methods like 'tools/list'.
75
+ logger.debug('Registering resources and tools...', context);
76
+ await registerEchoResource(server); // Example resource registration
77
+ await registerEchoTool(server); // Example tool registration
78
+ // Add calls to register other resources/tools here.
79
+ logger.info('Resources and tools registered successfully', context);
80
+ }
81
+ catch (err) {
82
+ // Registration is critical; log and re-throw errors.
83
+ logger.error('Failed to register resources/tools', {
84
+ ...context,
85
+ error: err instanceof Error ? err.message : String(err),
86
+ stack: err instanceof Error ? err.stack : undefined, // Include stack for debugging
87
+ });
88
+ throw err; // Propagate error to prevent server starting with incomplete capabilities.
89
+ }
90
+ return server;
91
+ }
92
+ /**
93
+ * Selects, sets up, and starts the appropriate MCP transport layer based on configuration.
94
+ * This function acts as the bridge between the core server logic and the communication channel.
95
+ *
96
+ * MCP Spec Relevance:
97
+ * - Transport Selection: Reads `config.mcpTransportType` ('stdio' or 'http') to determine
98
+ * which transport mechanism defined in the MCP specification to use.
99
+ * - Transport Connection: Calls dedicated functions (`connectStdioTransport` or `startHttpTransport`)
100
+ * which handle the specifics of establishing communication according to the chosen
101
+ * transport's rules (e.g., stdin/stdout handling for 'stdio', HTTP server setup and
102
+ * endpoint handling for 'http').
103
+ * - Server Instance Lifecycle:
104
+ * - For 'stdio', creates a single `McpServer` instance for the lifetime of the process.
105
+ * - For 'http', passes the `createMcpServerInstance` factory function to `startHttpTransport`,
106
+ * allowing the HTTP transport to create a new, isolated server instance for each client session,
107
+ * aligning with the stateful session management described in the Streamable HTTP spec.
108
+ *
109
+ * @returns {Promise<McpServer | void>} Resolves with the McpServer instance for 'stdio', or void for 'http'.
110
+ * @throws {Error} If the configured transport type is unsupported or if transport setup fails.
111
+ */
112
+ async function startTransport() {
113
+ // Determine the transport type from the validated configuration.
114
+ const transportType = config.mcpTransportType;
115
+ const context = { operation: 'startTransport', transport: transportType };
116
+ logger.info(`Starting transport: ${transportType}`, context);
117
+ // --- HTTP Transport Setup ---
118
+ if (transportType === 'http') {
119
+ logger.debug('Delegating to startHttpTransport...', context);
120
+ // For HTTP, the transport layer manages its own lifecycle and potentially multiple sessions.
121
+ // We pass the factory function to allow the HTTP transport to create server instances as needed (per session).
122
+ await startHttpTransport(createMcpServerInstance, context);
123
+ // The HTTP server runs indefinitely, listening for connections, so this function returns void.
124
+ return;
125
+ }
126
+ // --- Stdio Transport Setup ---
127
+ if (transportType === 'stdio') {
128
+ logger.debug('Creating single McpServer instance for stdio transport...', context);
129
+ // For stdio, there's typically one persistent connection managed by a parent process.
130
+ // Create a single McpServer instance for the entire process lifetime.
131
+ const server = await createMcpServerInstance();
132
+ logger.debug('Delegating to connectStdioTransport...', context);
133
+ // Connect the server instance to the stdio transport handler.
134
+ await connectStdioTransport(server, context);
135
+ // Return the server instance; the caller (main entry point) might hold onto it.
136
+ return server;
137
+ }
138
+ // --- Unsupported Transport ---
139
+ // This case should theoretically not be reached due to config validation, but acts as a safeguard.
140
+ logger.fatal(`Unsupported transport type configured: ${transportType}`, context);
141
+ throw new Error(`Unsupported transport type: ${transportType}. Must be 'stdio' or 'http'.`);
142
+ }
143
+ /**
144
+ * Main application entry point. Initializes and starts the MCP server.
145
+ *
146
+ * MCP Spec Relevance:
147
+ * - Orchestrates the server startup sequence, culminating in a server ready to accept
148
+ * connections and process MCP messages according to the chosen transport's rules.
149
+ * - Implements top-level error handling for critical startup failures, ensuring the
150
+ * process exits appropriately if it cannot initialize correctly.
151
+ *
152
+ * @returns {Promise<void | McpServer>} Resolves upon successful startup (void for http, McpServer for stdio). Rejects on critical failure.
153
+ */
154
+ export async function initializeAndStartServer() {
155
+ const context = { operation: 'initializeAndStartServer' };
156
+ logger.info('MCP Server initialization sequence started.', context);
157
+ try {
158
+ // Initiate the transport setup based on configuration.
159
+ const result = await startTransport();
160
+ logger.info('MCP Server initialization sequence completed successfully.', context);
161
+ return result;
162
+ }
163
+ catch (err) {
164
+ // Catch any errors that occurred during server instance creation or transport setup.
165
+ logger.fatal('Critical error during MCP server initialization.', {
166
+ ...context,
167
+ error: err instanceof Error ? err.message : String(err),
168
+ stack: err instanceof Error ? err.stack : undefined,
169
+ });
170
+ // Use the centralized error handler for consistent critical error reporting.
171
+ ErrorHandler.handleError(err, { ...context, critical: true });
172
+ // Exit the process with a non-zero code to indicate failure.
173
+ logger.info('Exiting process due to critical initialization error.', context);
174
+ process.exit(1);
175
+ }
176
+ }
@@ -0,0 +1,68 @@
1
+ import { z } from 'zod';
2
+ import { type RequestContext } from "../../../utils/index.js";
3
+ /**
4
+ * Defines the valid formatting modes for the echo tool operation.
5
+ * - `standard`: Echo the message as is.
6
+ * - `uppercase`: Convert the message to uppercase.
7
+ * - `lowercase`: Convert the message to lowercase.
8
+ */
9
+ export declare const ECHO_MODES: readonly ["standard", "uppercase", "lowercase"];
10
+ /**
11
+ * Zod schema defining the input parameters for the `echo_message` tool.
12
+ * Includes validation rules and descriptions for each parameter.
13
+ */
14
+ export declare const EchoToolInputSchema: z.ZodObject<{
15
+ /** The message to be echoed back. Must be between 1 and 1000 characters. */
16
+ message: z.ZodString;
17
+ /** Specifies how the message should be formatted. Defaults to 'standard'. */
18
+ mode: z.ZodDefault<z.ZodOptional<z.ZodEnum<["standard", "uppercase", "lowercase"]>>>;
19
+ /** The number of times the formatted message should be repeated. Defaults to 1, max 10. */
20
+ repeat: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
21
+ /** Whether to include an ISO 8601 timestamp in the response. Defaults to true. */
22
+ timestamp: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
23
+ }, "strip", z.ZodTypeAny, {
24
+ repeat: number;
25
+ message: string;
26
+ timestamp: boolean;
27
+ mode: "standard" | "uppercase" | "lowercase";
28
+ }, {
29
+ message: string;
30
+ repeat?: number | undefined;
31
+ timestamp?: boolean | undefined;
32
+ mode?: "standard" | "uppercase" | "lowercase" | undefined;
33
+ }>;
34
+ /**
35
+ * TypeScript type inferred from `EchoToolInputSchema`.
36
+ * Represents the validated input parameters for the echo tool.
37
+ * @typedef {z.infer<typeof EchoToolInputSchema>} EchoToolInput
38
+ */
39
+ export type EchoToolInput = z.infer<typeof EchoToolInputSchema>;
40
+ /**
41
+ * Defines the structure of the JSON payload returned by the `echo_message` tool handler.
42
+ * This object is JSON-stringified and placed within the `text` field of the
43
+ * `CallToolResult`'s `content` array.
44
+ */
45
+ export interface EchoToolResponse {
46
+ /** The original message provided in the input. */
47
+ originalMessage: string;
48
+ /** The message after applying the specified formatting mode. */
49
+ formattedMessage: string;
50
+ /** The formatted message repeated the specified number of times, joined by spaces. */
51
+ repeatedMessage: string;
52
+ /** The formatting mode that was applied ('standard', 'uppercase', or 'lowercase'). */
53
+ mode: typeof ECHO_MODES[number];
54
+ /** The number of times the message was repeated. */
55
+ repeatCount: number;
56
+ /** Optional ISO 8601 timestamp indicating when the response was generated. Included if `timestamp` input was true. */
57
+ timestamp?: string;
58
+ }
59
+ /**
60
+ * Processes the core logic for the echo tool.
61
+ * Formats and repeats the message based on the provided parameters.
62
+ *
63
+ * @function processEchoMessage
64
+ * @param {EchoToolInput} params - The validated input parameters for the echo tool.
65
+ * @param {RequestContext} context - The request context for logging and tracing.
66
+ * @returns {EchoToolResponse} The processed response data, including original message, formatted/repeated message, and optional timestamp.
67
+ */
68
+ export declare const processEchoMessage: (params: EchoToolInput, context: RequestContext) => EchoToolResponse;
@@ -0,0 +1,73 @@
1
+ import { z } from 'zod'; // Import z here
2
+ // Import utils from the main barrel file (logger from ../../../utils/internal/logger.js, RequestContext from ../../../utils/internal/requestContext.js)
3
+ import { logger } from "../../../utils/index.js";
4
+ // --- Schema and Type Definitions (Moved from types.ts) ---
5
+ /**
6
+ * Defines the valid formatting modes for the echo tool operation.
7
+ * - `standard`: Echo the message as is.
8
+ * - `uppercase`: Convert the message to uppercase.
9
+ * - `lowercase`: Convert the message to lowercase.
10
+ */
11
+ export const ECHO_MODES = ['standard', 'uppercase', 'lowercase'];
12
+ /**
13
+ * Zod schema defining the input parameters for the `echo_message` tool.
14
+ * Includes validation rules and descriptions for each parameter.
15
+ */
16
+ export const EchoToolInputSchema = z.object({
17
+ /** The message to be echoed back. Must be between 1 and 1000 characters. */
18
+ message: z.string().min(1, "Message cannot be empty").max(1000, "Message cannot exceed 1000 characters").describe('The message to echo back (1-1000 characters)'),
19
+ /** Specifies how the message should be formatted. Defaults to 'standard'. */
20
+ mode: z.enum(ECHO_MODES).optional().default('standard').describe('How to format the echoed message: standard (as-is), uppercase, or lowercase'),
21
+ /** The number of times the formatted message should be repeated. Defaults to 1, max 10. */
22
+ repeat: z.number().int().min(1).max(10).optional().default(1).describe('Number of times to repeat the message (1-10)'),
23
+ /** Whether to include an ISO 8601 timestamp in the response. Defaults to true. */
24
+ timestamp: z.boolean().optional().default(true).describe('Whether to include a timestamp in the response')
25
+ }).describe('Defines the input arguments for the echo_message tool.');
26
+ // --- Core Logic Function ---
27
+ /**
28
+ * Processes the core logic for the echo tool.
29
+ * Formats and repeats the message based on the provided parameters.
30
+ *
31
+ * @function processEchoMessage
32
+ * @param {EchoToolInput} params - The validated input parameters for the echo tool.
33
+ * @param {RequestContext} context - The request context for logging and tracing.
34
+ * @returns {EchoToolResponse} The processed response data, including original message, formatted/repeated message, and optional timestamp.
35
+ */
36
+ export const processEchoMessage = (params, context // Add context parameter
37
+ ) => {
38
+ // Use the passed context for logging
39
+ logger.debug("Processing echo message logic", { ...context, inputMessage: params.message, mode: params.mode });
40
+ // Process the message according to the requested mode
41
+ let formattedMessage = params.message;
42
+ switch (params.mode) {
43
+ case 'uppercase':
44
+ formattedMessage = params.message.toUpperCase();
45
+ break;
46
+ case 'lowercase':
47
+ formattedMessage = params.message.toLowerCase();
48
+ break;
49
+ // 'standard' mode keeps the message as-is
50
+ }
51
+ // Repeat the message the specified number of times, ensuring it's within bounds
52
+ // Default repeat value is handled by the Zod schema
53
+ const safeRepeatCount = Math.min(params.repeat, 10);
54
+ const repeatedMessage = Array(safeRepeatCount)
55
+ .fill(formattedMessage)
56
+ .join(' ');
57
+ // Prepare the response data using the imported EchoToolResponse type
58
+ const response = {
59
+ originalMessage: params.message,
60
+ formattedMessage,
61
+ repeatedMessage,
62
+ // Default mode value is handled by the Zod schema
63
+ mode: params.mode,
64
+ repeatCount: safeRepeatCount
65
+ };
66
+ // Add timestamp if requested (default is true based on schema)
67
+ if (params.timestamp !== false) {
68
+ response.timestamp = new Date().toISOString();
69
+ }
70
+ // Use the passed context for logging the result
71
+ logger.debug("Echo message processed successfully", { ...context, response });
72
+ return response;
73
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Barrel file for the echo tool.
3
+ * Exports the registration function.
4
+ */
5
+ export { registerEchoTool } from './registration.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Barrel file for the echo tool.
3
+ * Exports the registration function.
4
+ */
5
+ export { registerEchoTool } from './registration.js';
@@ -0,0 +1,12 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ /**
3
+ * Registers the 'echo_message' tool and its handler with the provided MCP server instance.
4
+ * Defines the tool's input schema, description, and the core request handling logic.
5
+ * Error handling is integrated using ErrorHandler. (Asynchronous)
6
+ *
7
+ * @function registerEchoTool
8
+ * @param {McpServer} server - The MCP server instance to register the tool with.
9
+ * @returns {Promise<void>} A promise that resolves when the tool registration is complete.
10
+ * @throws {McpError} Throws an McpError if the registration process fails critically.
11
+ */
12
+ export declare const registerEchoTool: (server: McpServer) => Promise<void>;
@@ -0,0 +1,86 @@
1
+ // Import schema and types from the logic file
2
+ import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
3
+ // Import utils from the main barrel file (ErrorHandler, logger, requestContextService from ../../../utils/internal/*)
4
+ import { ErrorHandler, logger, requestContextService } from "../../../utils/index.js";
5
+ import { EchoToolInputSchema } from './echoToolLogic.js'; // Schema needed for shape extraction
6
+ // Import the core logic function
7
+ import { processEchoMessage } from './echoToolLogic.js';
8
+ /**
9
+ * Registers the 'echo_message' tool and its handler with the provided MCP server instance.
10
+ * Defines the tool's input schema, description, and the core request handling logic.
11
+ * Error handling is integrated using ErrorHandler. (Asynchronous)
12
+ *
13
+ * @function registerEchoTool
14
+ * @param {McpServer} server - The MCP server instance to register the tool with.
15
+ * @returns {Promise<void>} A promise that resolves when the tool registration is complete.
16
+ * @throws {McpError} Throws an McpError if the registration process fails critically.
17
+ */
18
+ export const registerEchoTool = async (server) => {
19
+ const toolName = "echo_message"; // The unique identifier for the tool
20
+ const toolDescription = "Echoes a message back with optional formatting and repetition."; // Tool description
21
+ // Create registration context using the service
22
+ const registrationContext = requestContextService.createRequestContext({
23
+ operation: 'RegisterEchoTool',
24
+ toolName: toolName,
25
+ module: 'EchoToolRegistration'
26
+ });
27
+ logger.info(`Registering tool: ${toolName}`, registrationContext);
28
+ // Use ErrorHandler to wrap the entire registration process
29
+ await ErrorHandler.tryCatch(async () => {
30
+ // Register the tool using the 4-argument server.tool() overload (SDK v1.10.2+)
31
+ server.tool(toolName, toolDescription, // Argument 2: Tool Description
32
+ // --- Tool Input Schema (Raw Shape) ---
33
+ // Pass the raw shape of the Zod schema. The SDK uses this for validation.
34
+ EchoToolInputSchema.shape, // Argument 3: Schema Shape
35
+ // --- Tool Handler ---
36
+ // The core logic executed when the tool is called.
37
+ // Params are automatically validated against the provided schema shape by the SDK.
38
+ async (params) => {
39
+ // Create handler context using the service
40
+ const handlerContext = requestContextService.createRequestContext({
41
+ parentContext: registrationContext, // Link to registration context
42
+ operation: 'HandleEchoToolRequest',
43
+ toolName: toolName,
44
+ params: params // Include relevant request details
45
+ });
46
+ logger.debug("Handling echo tool request", handlerContext);
47
+ // Wrap the handler logic in tryCatch for robust error handling
48
+ return await ErrorHandler.tryCatch(async () => {
49
+ // Delegate the core processing logic, passing the context
50
+ const response = processEchoMessage(params, handlerContext);
51
+ logger.debug("Echo tool processed successfully", handlerContext);
52
+ // Return the response in the standard MCP tool result format
53
+ // as required by the SDK's server.tool method signature.
54
+ return {
55
+ content: [{
56
+ type: "text", // Content type is text
57
+ // The actual content is a JSON string representing the EchoToolResponse
58
+ text: JSON.stringify(response, null, 2)
59
+ }],
60
+ isError: false // Explicitly set isError to false for successful execution
61
+ };
62
+ }, {
63
+ // Configuration for the error handler specific to this tool call
64
+ operation: 'processing echo message handler',
65
+ context: handlerContext, // Pass handler-specific context
66
+ input: params, // Log input parameters on error
67
+ // Provide a custom error mapping for more specific error reporting
68
+ errorMapper: (error) => new McpError(// Add type 'unknown' to error parameter
69
+ // Use VALIDATION_ERROR if the error likely stems from processing invalid (though schema-valid) input
70
+ error instanceof McpError ? error.code : BaseErrorCode.INTERNAL_ERROR, `Error processing echo message tool: ${error instanceof Error ? error.message : 'Unknown error'}`, { ...handlerContext } // Include context in the McpError
71
+ )
72
+ });
73
+ }); // End of server.tool call
74
+ logger.info(`Tool registered successfully: ${toolName}`, registrationContext);
75
+ }, {
76
+ // Configuration for the error handler wrapping the entire registration
77
+ operation: `registering tool ${toolName}`,
78
+ context: registrationContext, // Context for registration-level errors
79
+ errorCode: BaseErrorCode.INTERNAL_ERROR, // Default error code for registration failure
80
+ // Custom error mapping for registration failures
81
+ errorMapper: (error) => new McpError(// Add type 'unknown' to error parameter
82
+ error instanceof McpError ? error.code : BaseErrorCode.INTERNAL_ERROR, `Failed to register tool '${toolName}': ${error instanceof Error ? error.message : 'Unknown error'}`, { ...registrationContext } // Include context in the McpError
83
+ ),
84
+ critical: true // Mark registration failure as critical to halt startup
85
+ }); // End of ErrorHandler.tryCatch for registration
86
+ };
@@ -0,0 +1,57 @@
1
+ /**
2
+ * MCP Authentication Middleware: Bearer Token Validation (JWT).
3
+ *
4
+ * This middleware validates JSON Web Tokens (JWT) passed via the 'Authorization' header
5
+ * using the 'Bearer' scheme (e.g., "Authorization: Bearer <your_token>").
6
+ * It verifies the token's signature and expiration using the secret key defined
7
+ * in the configuration (MCP_AUTH_SECRET_KEY).
8
+ *
9
+ * If the token is valid, the decoded payload is attached to `req.auth` for potential
10
+ * use in downstream authorization logic (e.g., checking scopes or permissions).
11
+ * If the token is missing, invalid, or expired, it sends an HTTP 401 Unauthorized response.
12
+ *
13
+ * --- Scope and Relation to MCP Authorization Spec (2025-03-26) ---
14
+ * - This middleware handles the *validation* of an already obtained Bearer token,
15
+ * as required by Section 2.6 of the MCP Auth Spec.
16
+ * - It does *NOT* implement the full OAuth 2.1 authorization flows (e.g., Authorization
17
+ * Code Grant with PKCE), token endpoints (/token), authorization endpoints (/authorize),
18
+ * metadata discovery (/.well-known/oauth-authorization-server), or dynamic client
19
+ * registration (/register) described in the specification. It assumes the client
20
+ * obtained the JWT through an external process compliant with the spec or another
21
+ * agreed-upon mechanism.
22
+ * - It correctly returns HTTP 401 errors for invalid/missing tokens as per Section 2.8.
23
+ *
24
+ * --- Implementation Details & Requirements ---
25
+ * - Requires the 'jsonwebtoken' package (`npm install jsonwebtoken @types/jsonwebtoken`).
26
+ * - The `MCP_AUTH_SECRET_KEY` environment variable MUST be set to a strong, secret value
27
+ * in production. The middleware includes a startup check for this.
28
+ * - In non-production environments, if the secret key is missing, authentication checks
29
+ * are bypassed for development convenience (a warning is logged). THIS IS INSECURE FOR PRODUCTION.
30
+ * - The structure of the JWT payload (e.g., containing user ID, scopes) depends on the
31
+ * token issuer and is not dictated by this middleware itself, but the payload is made
32
+ * available on `req.auth`.
33
+ *
34
+ * @see {@link https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/authorization.mdx | MCP Authorization Specification}
35
+ */
36
+ import { Request, Response, NextFunction } from 'express';
37
+ import jwt from 'jsonwebtoken';
38
+ declare global {
39
+ namespace Express {
40
+ interface Request {
41
+ /** Decoded JWT payload if authentication is successful, or a development mode indicator. */
42
+ auth?: jwt.JwtPayload | string | {
43
+ devMode: boolean;
44
+ warning: string;
45
+ };
46
+ }
47
+ }
48
+ }
49
+ /**
50
+ * Express middleware function for verifying JWT Bearer token authentication.
51
+ * Checks the `Authorization` header, verifies the token, and attaches the payload to `req.auth`.
52
+ *
53
+ * @param {Request} req - Express request object.
54
+ * @param {Response} res - Express response object.
55
+ * @param {NextFunction} next - Express next middleware function.
56
+ */
57
+ export declare function mcpAuthMiddleware(req: Request, res: Response, next: NextFunction): void;