mcp-ts-template 1.5.0 → 1.5.1

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.
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # MCP TypeScript Template 🚀
2
2
 
3
3
  [![TypeScript](https://img.shields.io/badge/TypeScript-^5.8.3-blue.svg)](https://www.typescriptlang.org/)
4
- [![Model Context Protocol SDK](https://img.shields.io/badge/MCP%20SDK-1.12.1-green.svg)](https://github.com/modelcontextprotocol/typescript-sdk)
4
+ [![Model Context Protocol SDK](https://img.shields.io/badge/MCP%20SDK-^1.12.3-green.svg)](https://github.com/modelcontextprotocol/typescript-sdk)
5
5
  [![MCP Spec Version](https://img.shields.io/badge/MCP%20Spec-2025--03--26-lightgrey.svg)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/changelog.mdx)
6
- [![Version](https://img.shields.io/badge/Version-1.5.0-blue.svg)](./CHANGELOG.md)
6
+ [![Version](https://img.shields.io/badge/Version-1.5.1-blue.svg)](./CHANGELOG.md)
7
7
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
8
8
  [![Status](https://img.shields.io/badge/Status-Stable-green.svg)](https://github.com/cyanheads/mcp-ts-template/issues)
9
9
  [![GitHub](https://img.shields.io/github/stars/cyanheads/mcp-ts-template?style=social)](https://github.com/cyanheads/mcp-ts-template)
@@ -59,9 +59,9 @@ _Note: [**toolkit-mcp-server**](https://github.com/cyanheads/toolkit-mcp-server)
59
59
 
60
60
  You can also **see my [GitHub profile](https://github.com/cyanheads/)** for additional MCP servers I've created, many of which are planned to be migrated to or built upon this template in the future.
61
61
 
62
- ## 🏁 Quick Start
62
+ ## 📦 Installation
63
63
 
64
- Get the example server running in minutes:
64
+ This project is a template, but can also directly be run as an MCP server. To get started, follow these steps:
65
65
 
66
66
  1. **Clone the repository:**
67
67
 
@@ -77,31 +77,44 @@ Get the example server running in minutes:
77
77
  ```
78
78
 
79
79
  3. **Build the project:**
80
-
81
80
  ```bash
82
81
  npm run build
83
- # Or use 'npm run rebuild' for a clean install (deletes node_modules, logs, dist)
82
+ # Or use 'npm run rebuild' for a clean install
84
83
  ```
85
84
 
86
- 4. **Format the code (Optional but Recommended):**
85
+ ## 🚀 Usage
87
86
 
88
- ```bash
89
- npm run format
90
- ```
87
+ Once built, you can run the server. If you intend to publish your project as a package, you can test the `npx` command by linking it locally.
88
+
89
+ ### Using NPX
90
+ To run the MCP server directly using `npx`, you can use the following command:
91
+
92
+ ```bash
93
+
94
+ Now you can run it via `npx`:
95
+
96
+ ```bash
97
+ # Run with default stdio transport
98
+ npx mcp-ts-template
91
99
 
92
- 5. **Run the Example Server:**
100
+ # Run with HTTP transport
101
+ MCP_TRANSPORT_TYPE=http npx mcp-ts-template
102
+ ```
103
+
104
+ ### From Source (for Development)
93
105
 
94
- - **Via Stdio (Default):** Many MCP host applications will run this automatically using `stdio`.
95
- To run manually for testing:
96
- ```bash
97
- npm start
98
- # or 'npm run start:stdio'
99
- ```
100
- - **Via Streamable HTTP:**
101
- ```bash
102
- npm run start:http
103
- ```
104
- This starts a **Streamable HTTP** server (default: `http://127.0.0.1:3010`) which uses Server-Sent Events for the server-to-client streaming component. The port, host, and allowed origins are configurable via environment variables (see [Configuration](#configuration)).
106
+ You can also use the npm scripts to run the server directly from your cloned repository:
107
+
108
+ - **Via Stdio (Default):**
109
+ ```bash
110
+ npm start
111
+ # or 'npm run start:stdio'
112
+ ```
113
+ - **Via Streamable HTTP:**
114
+ ```bash
115
+ npm run start:http
116
+ ```
117
+ This starts a **Streamable HTTP** server (default: `http://127.0.0.1:3010`) which uses Server-Sent Events for the server-to-client streaming component. The port, host, and allowed origins are configurable via environment variables (see [Configuration](#configuration)).
105
118
 
106
119
  ## ⚙️ Configuration
107
120
 
@@ -142,6 +155,28 @@ You **MUST** configure one of these modes for the security mechanism to function
142
155
 
143
156
  For detailed information on configuring the built-in **MCP client**, including how to set up connections to external MCP servers using `mcp-config.json`, please see the [Client Configuration Guide](src/mcp-client/client-config/README.md).
144
157
 
158
+ #### Example: Adding to an MCP Client
159
+
160
+ To add this server to an MCP client application (like [Claude Desktop](https://github.com/cyanheads/claude-desktop)), you would update the client's configuration file. This example assumes you have published your package or have used `npm link` to make it available locally.
161
+
162
+ ```json
163
+ {
164
+ "mcpServers": {
165
+ "mcp-ts-template": {
166
+ "command": "npx",
167
+ "args": ["mcp-ts-template"],
168
+ "env": {
169
+ "MCP_LOG_LEVEL": "debug",
170
+ "MCP_TRANSPORT_TYPE": "http",
171
+ "MCP_HTTP_PORT": "3010"
172
+ },
173
+ "disabled": false,
174
+ "autoApprove": []
175
+ }
176
+ }
177
+ }
178
+ ```
179
+
145
180
  ## 🏗️ Project Structure
146
181
 
147
182
  This project follows a standard TypeScript project layout. Here's an overview of the key directories and files:
package/dist/index.js CHANGED
@@ -51,71 +51,47 @@ const shutdown = async (signal) => {
51
51
  triggerEvent: signal,
52
52
  });
53
53
  logger.info(`Received ${signal}. Initiating graceful shutdown...`, shutdownContext);
54
- let mcpClosed = false;
55
- let httpClosed = false;
56
- let closeError = null;
57
- const checkAndExit = () => {
58
- if (closeError) {
59
- logger.error("Critical error encountered during shutdown process.", {
60
- ...shutdownContext,
61
- errorMessage: closeError.message,
62
- errorStack: closeError.stack,
63
- });
64
- process.exit(1);
65
- }
66
- else if (mcpClosed && httpClosed) {
67
- logger.info("Graceful shutdown completed successfully. Exiting.", shutdownContext);
68
- process.exit(0);
69
- }
70
- };
54
+ const shutdownPromises = [];
71
55
  if (mcpStdioServer) {
72
- logger.info("Attempting to close main MCP server (STDIO)...", shutdownContext);
73
- mcpStdioServer
74
- .close()
75
- .then(() => {
76
- logger.info("Main MCP server (STDIO) closed successfully.", shutdownContext);
77
- mcpClosed = true;
78
- checkAndExit();
79
- })
80
- .catch((err) => {
81
- logger.error("Error closing MCP server (STDIO).", {
82
- ...shutdownContext,
83
- error: err,
84
- });
85
- mcpClosed = true; // Consider it closed even on error to allow exit
86
- if (!closeError)
87
- closeError = err;
88
- checkAndExit();
89
- });
90
- }
91
- else {
92
- mcpClosed = true; // No STDIO McpServer to close
93
- }
94
- if (actualHttpServer) {
95
- logger.info("Attempting to close HTTP server...", shutdownContext);
96
- actualHttpServer.close((err) => {
97
- if (err) {
98
- logger.error("Error closing HTTP server.", {
56
+ const serverToClose = mcpStdioServer;
57
+ shutdownPromises.push(new Promise((resolve) => {
58
+ logger.info("Closing main MCP server (STDIO)...", shutdownContext);
59
+ serverToClose
60
+ .close()
61
+ .then(() => {
62
+ logger.info("Main MCP server (STDIO) closed successfully.", shutdownContext);
63
+ resolve();
64
+ })
65
+ .catch((err) => {
66
+ logger.error("Error closing MCP server (STDIO).", {
99
67
  ...shutdownContext,
100
68
  error: err,
101
69
  });
102
- if (!closeError)
103
- closeError = err;
104
- }
105
- else {
106
- logger.info("HTTP server closed successfully.", shutdownContext);
107
- }
108
- httpClosed = true;
109
- checkAndExit();
110
- });
111
- }
112
- else {
113
- httpClosed = true; // No HTTP server to close
70
+ resolve(); // Resolve even on error to not block shutdown
71
+ });
72
+ }));
114
73
  }
115
- // Initial check in case no servers needed closing
116
- if (mcpClosed && httpClosed) {
117
- checkAndExit();
74
+ if (actualHttpServer) {
75
+ const serverToClose = actualHttpServer;
76
+ shutdownPromises.push(new Promise((resolve) => {
77
+ logger.info("Closing HTTP server...", shutdownContext);
78
+ serverToClose.close((err) => {
79
+ if (err) {
80
+ logger.error("Error closing HTTP server.", {
81
+ ...shutdownContext,
82
+ error: err,
83
+ });
84
+ }
85
+ else {
86
+ logger.info("HTTP server closed successfully.", shutdownContext);
87
+ }
88
+ resolve(); // Resolve regardless of error
89
+ });
90
+ }));
118
91
  }
92
+ await Promise.allSettled(shutdownPromises);
93
+ logger.info("Graceful shutdown completed successfully. Exiting.", shutdownContext);
94
+ process.exit(0);
119
95
  };
120
96
  /**
121
97
  * Initializes and starts the main MCP server application.
@@ -2,32 +2,14 @@
2
2
  * @fileoverview Defines the core logic, schemas, and types for the `echo` resource.
3
3
  * This module includes a Zod schema for query parameter validation, type definitions,
4
4
  * and the main processing function that constructs the resource response.
5
- * The echo resource is designed to return a message, typically extracted from the
6
- * request URI's path or query parameters, along with a timestamp.
7
5
  * @module src/mcp-server/resources/echoResource/echoResourceLogic
8
6
  */
9
7
  import { z } from "zod";
10
8
  import { type RequestContext } from "../../../utils/index.js";
11
9
  /**
12
10
  * Zod schema defining expected query parameters for the echo resource.
13
- *
14
- * This schema is intended for validating parameters passed via the URI's query string
15
- * (e.g., `echo://some_message?message=override_from_query&anotherParam=value`).
16
- * Path parameters, such as `{message}` in a template like `echo://{message}`,
17
- * are typically defined in the `ResourceTemplate` (see `registration.ts`) and
18
- * extracted by the MCP SDK from the URI path. The SDK merges these path
19
- * parameters into the `params` object passed to the handler.
20
- *
21
- * If a path parameter and a query parameter share the same name (e.g., 'message'),
22
- * the query parameter will take precedence over the path parameter. This schema
23
- * defines `message` as an optional query parameter.
24
11
  */
25
12
  export declare const EchoResourceQuerySchema: z.ZodObject<{
26
- /**
27
- * Optional message to be echoed back in the response.
28
- * If the resource template also defines a 'message' path parameter,
29
- * this query parameter will override the path parameter's value if both are present.
30
- */
31
13
  message: z.ZodOptional<z.ZodString>;
32
14
  }, "strip", z.ZodTypeAny, {
33
15
  message?: string | undefined;
@@ -36,44 +18,21 @@ export declare const EchoResourceQuerySchema: z.ZodObject<{
36
18
  }>;
37
19
  /**
38
20
  * TypeScript type inferred from the {@link EchoResourceQuerySchema}.
39
- * Represents the validated query parameters that might be passed to the echo resource.
40
21
  */
41
22
  export type EchoResourceParams = z.infer<typeof EchoResourceQuerySchema>;
42
23
  /**
43
24
  * Defines the structure of the JSON payload returned by the `processEchoResource` function.
44
- * This object is typically JSON-stringified by the resource handler before being sent
45
- * as the resource content.
46
- *
47
- * @property message - The message that is being echoed. This could be from a path parameter,
48
- * a query parameter (which takes precedence), or a default value.
49
- * @property timestamp - An ISO 8601 timestamp indicating when the response was generated.
50
- * @property requestUri - The full URI of the original resource request.
51
25
  */
52
26
  export interface EchoResourceResponsePayload {
53
- /** The message that is being echoed. */
54
27
  message: string;
55
- /** An ISO 8601 timestamp indicating when the response was generated. */
56
28
  timestamp: string;
57
- /** The full URI of the original resource request. */
58
29
  requestUri: string;
59
30
  }
60
31
  /**
61
32
  * Processes the core logic for an echo resource request.
62
- * It constructs a response payload containing a message (derived from path or query parameters),
63
- * the current timestamp, and the original request URI.
64
- *
65
- * The `params` argument is expected to contain validated query parameters. If the resource
66
- * template (e.g., `echo://{message}`) includes path parameters, the MCP SDK extracts
67
- * them and merges them into the `params` object. If a query parameter shares the same
68
- * name as a path parameter, the query parameter's value takes precedence. This function
69
- * assumes `params.message` will hold the definitive message.
70
- *
71
33
  * @param uri - The full URL object of the incoming resource request.
72
34
  * @param params - The validated query parameters for the request.
73
- * This object also includes path parameters merged by the SDK, with query parameters
74
- * taking precedence in case of name conflicts.
75
35
  * @param context - The request context, used for logging and tracing the operation.
76
36
  * @returns The data payload for the response.
77
- * This payload is typically JSON-stringified by the calling handler.
78
37
  */
79
- export declare const processEchoResource: (uri: URL, params: EchoResourceParams, context: RequestContext) => EchoResourceResponsePayload;
38
+ export declare function echoResourceLogic(uri: URL, params: EchoResourceParams, context: RequestContext): Promise<EchoResourceResponsePayload>;
@@ -2,32 +2,14 @@
2
2
  * @fileoverview Defines the core logic, schemas, and types for the `echo` resource.
3
3
  * This module includes a Zod schema for query parameter validation, type definitions,
4
4
  * and the main processing function that constructs the resource response.
5
- * The echo resource is designed to return a message, typically extracted from the
6
- * request URI's path or query parameters, along with a timestamp.
7
5
  * @module src/mcp-server/resources/echoResource/echoResourceLogic
8
6
  */
9
7
  import { z } from "zod";
10
8
  import { logger } from "../../../utils/index.js";
11
9
  /**
12
10
  * Zod schema defining expected query parameters for the echo resource.
13
- *
14
- * This schema is intended for validating parameters passed via the URI's query string
15
- * (e.g., `echo://some_message?message=override_from_query&anotherParam=value`).
16
- * Path parameters, such as `{message}` in a template like `echo://{message}`,
17
- * are typically defined in the `ResourceTemplate` (see `registration.ts`) and
18
- * extracted by the MCP SDK from the URI path. The SDK merges these path
19
- * parameters into the `params` object passed to the handler.
20
- *
21
- * If a path parameter and a query parameter share the same name (e.g., 'message'),
22
- * the query parameter will take precedence over the path parameter. This schema
23
- * defines `message` as an optional query parameter.
24
11
  */
25
12
  export const EchoResourceQuerySchema = z.object({
26
- /**
27
- * Optional message to be echoed back in the response.
28
- * If the resource template also defines a 'message' path parameter,
29
- * this query parameter will override the path parameter's value if both are present.
30
- */
31
13
  message: z
32
14
  .string()
33
15
  .optional()
@@ -35,34 +17,20 @@ export const EchoResourceQuerySchema = z.object({
35
17
  });
36
18
  /**
37
19
  * Processes the core logic for an echo resource request.
38
- * It constructs a response payload containing a message (derived from path or query parameters),
39
- * the current timestamp, and the original request URI.
40
- *
41
- * The `params` argument is expected to contain validated query parameters. If the resource
42
- * template (e.g., `echo://{message}`) includes path parameters, the MCP SDK extracts
43
- * them and merges them into the `params` object. If a query parameter shares the same
44
- * name as a path parameter, the query parameter's value takes precedence. This function
45
- * assumes `params.message` will hold the definitive message.
46
- *
47
20
  * @param uri - The full URL object of the incoming resource request.
48
21
  * @param params - The validated query parameters for the request.
49
- * This object also includes path parameters merged by the SDK, with query parameters
50
- * taking precedence in case of name conflicts.
51
22
  * @param context - The request context, used for logging and tracing the operation.
52
23
  * @returns The data payload for the response.
53
- * This payload is typically JSON-stringified by the calling handler.
54
24
  */
55
- export const processEchoResource = (uri, params, context) => {
56
- // The `params.message` can originate from a query parameter (validated by `EchoResourceQuerySchema`)
57
- // or a path parameter (e.g., from a template like `echo://{message_from_path}`).
58
- // The MCP SDK merges these, with query parameters taking precedence over path parameters if names conflict.
59
- // The fallback "Default message..." is a safeguard if no message is provided via path or query.
60
- const messageToEcho = params.message || `Default echo from ${uri.pathname}`;
25
+ export async function echoResourceLogic(uri, params, context) {
26
+ // The message can come from a query parameter or the path itself.
27
+ // For a URI like `echo://my-message?param=1`, `hostname` is `my-message`.
28
+ const messageFromPath = uri.hostname || uri.pathname.replace(/^\/+/g, "");
29
+ const messageToEcho = params.message || messageFromPath || "Default echo message";
61
30
  logger.debug("Processing echo resource logic.", {
62
31
  ...context,
63
32
  resourceUri: uri.href,
64
33
  extractedMessage: messageToEcho,
65
- queryParamMessage: params.message,
66
34
  });
67
35
  const responsePayload = {
68
36
  message: messageToEcho,
@@ -73,10 +41,7 @@ export const processEchoResource = (uri, params, context) => {
73
41
  ...context,
74
42
  responsePayloadSummary: {
75
43
  messageLength: responsePayload.message.length,
76
- uriEchoed: responsePayload.requestUri.length > 50
77
- ? `${responsePayload.requestUri.substring(0, 47)}...`
78
- : responsePayload.requestUri,
79
44
  },
80
45
  });
81
46
  return responsePayload;
82
- };
47
+ }
@@ -1,30 +1,14 @@
1
1
  /**
2
2
  * @fileoverview Handles the registration of the `echo` resource with an MCP server instance.
3
- * This module defines the resource's template (URI structure), metadata (name, description, examples),
4
- * and the asynchronous handler function that processes `resources/read` requests matching the template.
5
- * It utilizes the MCP SDK's `server.resource()` method for registration and integrates
6
- * robust error handling using the project's `ErrorHandler` utility.
3
+ * This module defines the resource's template, metadata, and the asynchronous handler
4
+ * that processes `resources/read` requests.
7
5
  * @module src/mcp-server/resources/echoResource/registration
8
6
  */
9
7
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
8
  /**
11
9
  * Registers the 'echo' resource and its handlers with the provided MCP server instance.
12
10
  *
13
- * This function defines:
14
- * 1. The resource template (e.g., `echo://{message}`), which determines the URI structure.
15
- * The `{message}` part is a path variable.
16
- * 2. A `list` operation for the template to provide example/discoverable URIs.
17
- * 3. Metadata for the resource, including its user-friendly name, description, MIME type,
18
- * and example URIs.
19
- * 4. The core asynchronous handler logic for `resources/read` requests that match the template.
20
- * This handler processes the request and returns the resource content.
21
- *
22
- * Error handling is integrated throughout using `ErrorHandler.tryCatch` for robustness.
23
- *
24
11
  * @param server - The MCP server instance to register the resource with.
25
- * @returns A promise that resolves when the resource registration is complete. It does not return a value upon successful completion.
26
- * @throws {McpError} If the registration process fails critically, which might halt server startup.
27
- * @see {@link EchoResourceParams} for the type of parameters passed to the handler.
28
- * @see {@link processEchoResource} for the core resource logic.
12
+ * @returns A promise that resolves when the resource registration is complete.
29
13
  */
30
14
  export declare const registerEchoResource: (server: McpServer) => Promise<void>;
@@ -1,128 +1,54 @@
1
1
  /**
2
2
  * @fileoverview Handles the registration of the `echo` resource with an MCP server instance.
3
- * This module defines the resource's template (URI structure), metadata (name, description, examples),
4
- * and the asynchronous handler function that processes `resources/read` requests matching the template.
5
- * It utilizes the MCP SDK's `server.resource()` method for registration and integrates
6
- * robust error handling using the project's `ErrorHandler` utility.
3
+ * This module defines the resource's template, metadata, and the asynchronous handler
4
+ * that processes `resources/read` requests.
7
5
  * @module src/mcp-server/resources/echoResource/registration
8
6
  */
9
7
  import { ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
10
- import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
8
+ import { BaseErrorCode } from "../../../types-global/errors.js";
11
9
  import { ErrorHandler, logger, requestContextService, } from "../../../utils/index.js";
12
- import { processEchoResource, } from "./echoResourceLogic.js";
10
+ import { echoResourceLogic, } from "./echoResourceLogic.js";
13
11
  /**
14
12
  * Registers the 'echo' resource and its handlers with the provided MCP server instance.
15
13
  *
16
- * This function defines:
17
- * 1. The resource template (e.g., `echo://{message}`), which determines the URI structure.
18
- * The `{message}` part is a path variable.
19
- * 2. A `list` operation for the template to provide example/discoverable URIs.
20
- * 3. Metadata for the resource, including its user-friendly name, description, MIME type,
21
- * and example URIs.
22
- * 4. The core asynchronous handler logic for `resources/read` requests that match the template.
23
- * This handler processes the request and returns the resource content.
24
- *
25
- * Error handling is integrated throughout using `ErrorHandler.tryCatch` for robustness.
26
- *
27
14
  * @param server - The MCP server instance to register the resource with.
28
- * @returns A promise that resolves when the resource registration is complete. It does not return a value upon successful completion.
29
- * @throws {McpError} If the registration process fails critically, which might halt server startup.
30
- * @see {@link EchoResourceParams} for the type of parameters passed to the handler.
31
- * @see {@link processEchoResource} for the core resource logic.
15
+ * @returns A promise that resolves when the resource registration is complete.
32
16
  */
33
17
  export const registerEchoResource = async (server) => {
34
- const resourceName = "echo-resource"; // Internal identifier for this resource registration.
18
+ const resourceName = "echo-resource";
35
19
  const registrationContext = requestContextService.createRequestContext({
36
20
  operation: "RegisterResource",
37
21
  resourceName: resourceName,
38
- moduleName: "EchoResourceRegistration",
39
22
  });
40
- logger.info(`Attempting to register resource: '${resourceName}'`, registrationContext);
23
+ logger.info(`Registering resource: '${resourceName}'`, registrationContext);
41
24
  await ErrorHandler.tryCatch(async () => {
42
- // Define the resource template. This specifies the URI structure and supported operations.
43
- // The URI `echo://{message}` uses RFC 6570 syntax, where `{message}` is a path variable.
44
25
  const template = new ResourceTemplate("echo://{message}", {
45
- /**
46
- * Asynchronous handler for the `resources/list` operation associated with this template.
47
- * It provides a list of example or discoverable resource URIs that match this template.
48
- * This allows clients to discover how to interact with the echo resource.
49
- *
50
- * @returns A promise resolving to an object containing an array of resource descriptors.
51
- */
52
26
  list: async () => {
53
- const listContext = requestContextService.createRequestContext({
54
- parentContext: registrationContext,
55
- operation: "ListEchoResourceExamples",
56
- });
57
- logger.debug("Executing list operation for echo resource template.", listContext);
58
- // Return a static list of example URIs.
59
27
  return {
60
28
  resources: [
61
29
  {
62
30
  uri: "echo://hello",
63
31
  name: "Default Echo Message",
64
- description: "A simple echo resource example using a default message.",
32
+ description: "A simple echo resource example.",
65
33
  },
66
- // Add more examples as needed
67
34
  ],
68
- // nextCursor could be used here if the list were paginated.
69
35
  };
70
36
  },
71
- // The `complete` operation (for URI completion suggestions) is optional and not implemented here.
72
37
  });
73
- logger.debug(`Resource template created for '${resourceName}': ${template.uriTemplate}`, registrationContext);
74
- // Register the resource with the server.
75
- // This involves providing the registration name, the template, metadata, and the handler for read operations.
76
38
  server.resource(resourceName, template, {
77
39
  name: "Echo Message Resource",
78
- description: "A simple echo resource that returns a message, optionally specified in the URI path.",
40
+ description: "A simple echo resource that returns a message.",
79
41
  mimeType: "application/json",
80
- examples: [
81
- {
82
- name: "Basic echo",
83
- uri: "echo://hello",
84
- description: "Accesses the echo resource to echo the message 'hello'.",
85
- },
86
- {
87
- name: "Custom echo",
88
- uri: "echo://custom-message-here",
89
- description: "Accesses the echo resource to echo 'custom-message-here'.",
90
- },
91
- ],
92
- },
93
- /**
94
- * Asynchronous handler for `resources/read` requests matching the `echo://{message}` template.
95
- * This function is invoked by the MCP SDK when a client requests to read a resource
96
- * whose URI matches the registered template.
97
- *
98
- * The SDK extracts path variables (like `{message}` from `echo://{message}`) from the URI.
99
- * These path variables, along with any validated query parameters, are passed in the `params` object.
100
- *
101
- * @param uri - The full URL object of the resource being requested.
102
- * @param params - An object containing parameters derived from the request.
103
- * For this resource, it's expected to include `message` extracted from the URI
104
- * path by the SDK. It conforms to {@link EchoResourceParams}.
105
- * @returns A promise that resolves with the resource content, formatted as a `ReadResourceResult`.
106
- * This includes the URI, Base64 encoded content blob, and MIME type.
107
- * If an error is thrown from this handler, the SDK is responsible for catching it and
108
- * formatting an error response.
109
- */
110
- async (uri, params) => {
42
+ examples: [{ name: "Basic echo", uri: "echo://hello" }],
43
+ }, async (uri, params) => {
111
44
  const handlerContext = requestContextService.createRequestContext({
112
- parentContext: registrationContext,
45
+ parentRequestId: registrationContext.requestId,
113
46
  operation: "HandleResourceRead",
114
- resourceName: resourceName,
115
47
  resourceUri: uri.href,
116
- inputParamsSummary: params.message
117
- ? { messageLength: params.message.length }
118
- : { noMessageParam: true },
48
+ inputParams: params,
119
49
  });
120
- logger.debug(`Handling read request for resource '${resourceName}', URI: ${uri.href}`, handlerContext);
121
- return await ErrorHandler.tryCatch(async () => {
122
- const responseData = processEchoResource(uri, params, handlerContext);
123
- logger.debug(`'${resourceName}' (URI: ${uri.href}) processed successfully. Preparing content.`, handlerContext);
124
- // Construct the `ReadResourceResult` as expected by the MCP SDK.
125
- // The content (blob) must be Base64 encoded.
50
+ try {
51
+ const responseData = await echoResourceLogic(uri, params, handlerContext);
126
52
  return {
127
53
  contents: [
128
54
  {
@@ -132,37 +58,22 @@ export const registerEchoResource = async (server) => {
132
58
  },
133
59
  ],
134
60
  };
135
- }, {
136
- operation: `ExecutingCoreLogicFor_${resourceName}_Read`,
137
- context: handlerContext,
138
- input: { uri: uri.href, params },
139
- errorMapper: (error) => {
140
- const baseErrorCode = error instanceof McpError
141
- ? error.code
142
- : BaseErrorCode.INTERNAL_ERROR;
143
- const errorMessage = `Error processing read request for resource '${uri.href}': ${error instanceof Error ? error.message : "An unknown error occurred"}`;
144
- return new McpError(baseErrorCode, errorMessage, {
145
- ...handlerContext,
146
- originalErrorName: error instanceof Error ? error.name : typeof error,
147
- });
148
- },
149
- });
61
+ }
62
+ catch (error) {
63
+ const handledError = ErrorHandler.handleError(error, {
64
+ operation: "echoResourceReadHandler",
65
+ context: handlerContext,
66
+ input: { uri: uri.href, params },
67
+ });
68
+ // Re-throw to be caught by the SDK's top-level error handler
69
+ throw handledError;
70
+ }
150
71
  });
151
- logger.info(`Resource '${resourceName}' (template: '${template.uriTemplate}') registered successfully.`, registrationContext);
72
+ logger.info(`Resource '${resourceName}' registered successfully.`, registrationContext);
152
73
  }, {
153
74
  operation: `RegisteringResource_${resourceName}`,
154
75
  context: registrationContext,
155
76
  errorCode: BaseErrorCode.INITIALIZATION_FAILED,
156
- errorMapper: (error) => {
157
- const errorMessage = `Failed to register resource '${resourceName}': ${error instanceof Error ? error.message : "An unknown error occurred during registration."}`;
158
- const code = error instanceof McpError
159
- ? error.code
160
- : BaseErrorCode.INITIALIZATION_FAILED;
161
- return new McpError(code, errorMessage, {
162
- ...registrationContext,
163
- originalErrorName: error instanceof Error ? error.name : typeof error,
164
- });
165
- },
166
77
  critical: true,
167
78
  });
168
79
  };
@@ -17,13 +17,5 @@ import { ServerType } from "@hono/node-server";
17
17
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
18
18
  /**
19
19
  * Main application entry point. Initializes and starts the MCP server.
20
- * Orchestrates server startup, transport selection, and top-level error handling.
21
- *
22
- * MCP Spec Relevance:
23
- * - Manages server startup, leading to a server ready for MCP messages.
24
- * - Handles critical startup failures, ensuring appropriate process exit.
25
- *
26
- * @returns For 'stdio', resolves with `McpServer`. For 'http', resolves with `http.Server`.
27
- * Rejects on critical failure, leading to process exit.
28
20
  */
29
21
  export declare function initializeAndStartServer(): Promise<void | McpServer | ServerType>;