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 +57 -22
- package/dist/index.js +35 -59
- package/dist/mcp-server/resources/echoResource/echoResourceLogic.d.ts +1 -42
- package/dist/mcp-server/resources/echoResource/echoResourceLogic.js +6 -41
- package/dist/mcp-server/resources/echoResource/registration.d.ts +3 -19
- package/dist/mcp-server/resources/echoResource/registration.js +26 -115
- package/dist/mcp-server/server.d.ts +0 -8
- package/dist/mcp-server/server.js +20 -67
- package/dist/mcp-server/tools/catFactFetcher/logic.d.ts +3 -3
- package/dist/mcp-server/tools/catFactFetcher/logic.js +25 -70
- package/dist/mcp-server/tools/catFactFetcher/registration.d.ts +1 -2
- package/dist/mcp-server/tools/catFactFetcher/registration.js +34 -48
- package/dist/mcp-server/tools/echoTool/logic.d.ts +4 -35
- package/dist/mcp-server/tools/echoTool/logic.js +7 -38
- package/dist/mcp-server/tools/echoTool/registration.d.ts +1 -15
- package/dist/mcp-server/tools/echoTool/registration.js +33 -81
- package/dist/mcp-server/tools/imageTest/logic.d.ts +5 -6
- package/dist/mcp-server/tools/imageTest/logic.js +19 -54
- package/dist/mcp-server/tools/imageTest/registration.js +53 -27
- package/dist/mcp-server/transports/httpTransport.d.ts +0 -8
- package/dist/mcp-server/transports/httpTransport.js +56 -344
- package/package.json +8 -14
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# MCP TypeScript Template 🚀
|
|
2
2
|
|
|
3
3
|
[](https://www.typescriptlang.org/)
|
|
4
|
-
[](https://github.com/modelcontextprotocol/typescript-sdk)
|
|
5
5
|
[](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/changelog.mdx)
|
|
6
|
-
[](./CHANGELOG.md)
|
|
7
7
|
[](https://opensource.org/licenses/Apache-2.0)
|
|
8
8
|
[](https://github.com/cyanheads/mcp-ts-template/issues)
|
|
9
9
|
[](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
|
-
##
|
|
62
|
+
## 📦 Installation
|
|
63
63
|
|
|
64
|
-
|
|
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
|
|
82
|
+
# Or use 'npm run rebuild' for a clean install
|
|
84
83
|
```
|
|
85
84
|
|
|
86
|
-
|
|
85
|
+
## 🚀 Usage
|
|
87
86
|
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
100
|
+
# Run with HTTP transport
|
|
101
|
+
MCP_TRANSPORT_TYPE=http npx mcp-ts-template
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### From Source (for Development)
|
|
93
105
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
103
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
|
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
|
|
56
|
-
// The
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
4
|
-
*
|
|
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.
|
|
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
|
|
4
|
-
*
|
|
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
|
|
8
|
+
import { BaseErrorCode } from "../../../types-global/errors.js";
|
|
11
9
|
import { ErrorHandler, logger, requestContextService, } from "../../../utils/index.js";
|
|
12
|
-
import {
|
|
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.
|
|
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";
|
|
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(`
|
|
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
|
|
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
|
|
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
|
-
|
|
45
|
+
parentRequestId: registrationContext.requestId,
|
|
113
46
|
operation: "HandleResourceRead",
|
|
114
|
-
resourceName: resourceName,
|
|
115
47
|
resourceUri: uri.href,
|
|
116
|
-
|
|
117
|
-
? { messageLength: params.message.length }
|
|
118
|
-
: { noMessageParam: true },
|
|
48
|
+
inputParams: params,
|
|
119
49
|
});
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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}'
|
|
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>;
|