mcp-ts-template 1.2.2 → 1.2.3
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 +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.js +1 -1
- package/dist/mcp-client/client.js +2 -2
- package/dist/mcp-server/resources/echoResource/echoResourceLogic.d.ts +1 -1
- package/dist/mcp-server/resources/echoResource/echoResourceLogic.js +1 -1
- package/dist/mcp-server/resources/echoResource/index.d.ts +1 -1
- package/dist/mcp-server/resources/echoResource/index.js +1 -1
- package/dist/mcp-server/resources/echoResource/registration.d.ts +1 -1
- package/dist/mcp-server/resources/echoResource/registration.js +1 -1
- package/dist/mcp-server/server.d.ts +1 -1
- package/dist/mcp-server/server.js +1 -1
- package/dist/mcp-server/tools/echoTool/echoToolLogic.d.ts +1 -1
- package/dist/mcp-server/tools/echoTool/echoToolLogic.js +1 -1
- package/dist/mcp-server/tools/echoTool/index.d.ts +1 -1
- package/dist/mcp-server/tools/echoTool/index.js +1 -1
- package/dist/mcp-server/tools/echoTool/registration.d.ts +1 -1
- package/dist/mcp-server/tools/echoTool/registration.js +1 -1
- package/dist/mcp-server/transports/authentication/authMiddleware.d.ts +1 -1
- package/dist/mcp-server/transports/authentication/authMiddleware.js +38 -14
- package/dist/mcp-server/transports/httpTransport.d.ts +1 -1
- package/dist/mcp-server/transports/httpTransport.js +1 -1
- package/dist/mcp-server/transports/stdioTransport.d.ts +1 -1
- package/dist/mcp-server/transports/stdioTransport.js +1 -1
- package/dist/services/openRouterProvider.js +1 -1
- package/dist/types-global/errors.d.ts +1 -1
- package/dist/types-global/errors.js +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +2 -2
- package/dist/utils/internal/errorHandler.d.ts +1 -1
- package/dist/utils/internal/errorHandler.js +1 -1
- package/dist/utils/internal/index.d.ts +1 -1
- package/dist/utils/internal/index.js +1 -1
- package/dist/utils/internal/logger.js +3 -2
- package/dist/utils/internal/requestContext.d.ts +1 -1
- package/dist/utils/internal/requestContext.js +2 -2
- package/dist/utils/metrics/index.d.ts +1 -1
- package/dist/utils/metrics/index.js +1 -1
- package/dist/utils/metrics/tokenCounter.d.ts +1 -1
- package/dist/utils/parsing/dateParser.d.ts +1 -1
- package/dist/utils/parsing/dateParser.js +1 -1
- package/dist/utils/parsing/index.d.ts +2 -2
- package/dist/utils/parsing/index.js +2 -2
- package/dist/utils/parsing/jsonParser.js +13 -4
- package/dist/utils/security/idGenerator.js +5 -3
- package/dist/utils/security/index.d.ts +3 -3
- package/dist/utils/security/index.js +3 -3
- package/dist/utils/security/rateLimiter.js +1 -1
- package/dist/utils/security/sanitization.js +82 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.typescriptlang.org/)
|
|
4
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)
|
package/dist/config/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* - Construct and export a comprehensive `config` object.
|
|
13
13
|
* - Export individual configuration values like `logLevel` and `environment` for convenience.
|
|
14
14
|
*
|
|
15
|
-
* @module config/index
|
|
15
|
+
* @module src/config/index
|
|
16
16
|
*/
|
|
17
17
|
/**
|
|
18
18
|
* Main application configuration object.
|
package/dist/config/index.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* - Construct and export a comprehensive `config` object.
|
|
13
13
|
* - Export individual configuration values like `logLevel` and `environment` for convenience.
|
|
14
14
|
*
|
|
15
|
-
* @module config/index
|
|
15
|
+
* @module src/config/index
|
|
16
16
|
*/
|
|
17
17
|
import dotenv from "dotenv";
|
|
18
18
|
import { readFileSync } from "fs";
|
|
@@ -302,8 +302,8 @@ export async function disconnectAllMcpClients(parentContext) {
|
|
|
302
302
|
error: result.reason instanceof Error
|
|
303
303
|
? result.reason.message
|
|
304
304
|
: String(result.reason), // Get the error message
|
|
305
|
-
|
|
306
|
-
result.reason instanceof Error ? result.reason.stack : undefined,
|
|
305
|
+
// Include stack trace if available
|
|
306
|
+
stack: result.reason instanceof Error ? result.reason.stack : undefined,
|
|
307
307
|
});
|
|
308
308
|
}
|
|
309
309
|
else {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* and the main processing function that constructs the resource response.
|
|
5
5
|
* The echo resource is designed to return a message, typically extracted from the
|
|
6
6
|
* request URI's path or query parameters, along with a timestamp.
|
|
7
|
-
* @module mcp-server/resources/echoResource/echoResourceLogic
|
|
7
|
+
* @module src/mcp-server/resources/echoResource/echoResourceLogic
|
|
8
8
|
*/
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import { type RequestContext } from "../../../utils/index.js";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* and the main processing function that constructs the resource response.
|
|
5
5
|
* The echo resource is designed to return a message, typically extracted from the
|
|
6
6
|
* request URI's path or query parameters, along with a timestamp.
|
|
7
|
-
* @module mcp-server/resources/echoResource/echoResourceLogic
|
|
7
|
+
* @module src/mcp-server/resources/echoResource/echoResourceLogic
|
|
8
8
|
*/
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import { logger } from "../../../utils/index.js";
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Consuming modules should import from this barrel file to access
|
|
10
10
|
* the echo resource's registration capabilities.
|
|
11
|
-
* @module mcp-server/resources/echoResource/index
|
|
11
|
+
* @module src/mcp-server/resources/echoResource/index
|
|
12
12
|
*/
|
|
13
13
|
export { registerEchoResource } from "./registration.js";
|
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Consuming modules should import from this barrel file to access
|
|
10
10
|
* the echo resource's registration capabilities.
|
|
11
|
-
* @module mcp-server/resources/echoResource/index
|
|
11
|
+
* @module src/mcp-server/resources/echoResource/index
|
|
12
12
|
*/
|
|
13
13
|
export { registerEchoResource } from "./registration.js";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* and the asynchronous handler function that processes `resources/read` requests matching the template.
|
|
5
5
|
* It utilizes the MCP SDK's `server.resource()` method for registration and integrates
|
|
6
6
|
* robust error handling using the project's `ErrorHandler` utility.
|
|
7
|
-
* @module mcp-server/resources/echoResource/registration
|
|
7
|
+
* @module src/mcp-server/resources/echoResource/registration
|
|
8
8
|
*/
|
|
9
9
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
10
|
/**
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* and the asynchronous handler function that processes `resources/read` requests matching the template.
|
|
5
5
|
* It utilizes the MCP SDK's `server.resource()` method for registration and integrates
|
|
6
6
|
* robust error handling using the project's `ErrorHandler` utility.
|
|
7
|
-
* @module mcp-server/resources/echoResource/registration
|
|
7
|
+
* @module src/mcp-server/resources/echoResource/registration
|
|
8
8
|
*/
|
|
9
9
|
import { ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
10
|
import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* - Lifecycle: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/lifecycle.mdx
|
|
12
12
|
* - Overview (Capabilities): https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/index.mdx
|
|
13
13
|
* - Transports: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx
|
|
14
|
-
* @module mcp-server/server
|
|
14
|
+
* @module src/mcp-server/server
|
|
15
15
|
*/
|
|
16
16
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
17
17
|
/**
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* - Lifecycle: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/lifecycle.mdx
|
|
12
12
|
* - Overview (Capabilities): https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/index.mdx
|
|
13
13
|
* - Transports: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx
|
|
14
|
-
* @module mcp-server/server
|
|
14
|
+
* @module src/mcp-server/server
|
|
15
15
|
*/
|
|
16
16
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
17
17
|
import { config, environment } from "../config/index.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview Defines the core logic, schemas, and types for the `echo_message` tool.
|
|
3
3
|
* This module includes input validation using Zod, type definitions for input and output,
|
|
4
4
|
* and the main processing function that handles message formatting and repetition.
|
|
5
|
-
* @module mcp-server/tools/echoTool/echoToolLogic
|
|
5
|
+
* @module src/mcp-server/tools/echoTool/echoToolLogic
|
|
6
6
|
*/
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { type RequestContext } from "../../../utils/index.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview Defines the core logic, schemas, and types for the `echo_message` tool.
|
|
3
3
|
* This module includes input validation using Zod, type definitions for input and output,
|
|
4
4
|
* and the main processing function that handles message formatting and repetition.
|
|
5
|
-
* @module mcp-server/tools/echoTool/echoToolLogic
|
|
5
|
+
* @module src/mcp-server/tools/echoTool/echoToolLogic
|
|
6
6
|
*/
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { logger } from "../../../utils/index.js";
|
|
@@ -7,6 +7,6 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Consuming modules should import from this barrel file to access
|
|
9
9
|
* the echo tool's registration capabilities.
|
|
10
|
-
* @module mcp-server/tools/echoTool/index
|
|
10
|
+
* @module src/mcp-server/tools/echoTool/index
|
|
11
11
|
*/
|
|
12
12
|
export { registerEchoTool } from "./registration.js";
|
|
@@ -7,6 +7,6 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Consuming modules should import from this barrel file to access
|
|
9
9
|
* the echo tool's registration capabilities.
|
|
10
|
-
* @module mcp-server/tools/echoTool/index
|
|
10
|
+
* @module src/mcp-server/tools/echoTool/index
|
|
11
11
|
*/
|
|
12
12
|
export { registerEchoTool } from "./registration.js";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* and the asynchronous handler function that processes tool invocation requests.
|
|
5
5
|
* It leverages the MCP SDK's `server.tool()` method for registration and integrates
|
|
6
6
|
* robust error handling using the project's `ErrorHandler` utility.
|
|
7
|
-
* @module mcp-server/tools/echoTool/registration
|
|
7
|
+
* @module src/mcp-server/tools/echoTool/registration
|
|
8
8
|
*/
|
|
9
9
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
10
|
/**
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* and the asynchronous handler function that processes tool invocation requests.
|
|
5
5
|
* It leverages the MCP SDK's `server.tool()` method for registration and integrates
|
|
6
6
|
* robust error handling using the project's `ErrorHandler` utility.
|
|
7
|
-
* @module mcp-server/tools/echoTool/registration
|
|
7
|
+
* @module src/mcp-server/tools/echoTool/registration
|
|
8
8
|
*/
|
|
9
9
|
import { BaseErrorCode, McpError } from "../../../types-global/errors.js";
|
|
10
10
|
import { ErrorHandler, logger, requestContextService, } from "../../../utils/index.js";
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* If the token is missing, invalid, or expired, it sends an HTTP 401 Unauthorized response.
|
|
12
12
|
*
|
|
13
13
|
* @see {@link https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/authorization.mdx | MCP Authorization Specification}
|
|
14
|
-
* @module mcp-server/transports/authentication/authMiddleware
|
|
14
|
+
* @module src/mcp-server/transports/authentication/authMiddleware
|
|
15
15
|
*/
|
|
16
16
|
import { NextFunction, Request, Response } from "express";
|
|
17
17
|
import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types.js";
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* If the token is missing, invalid, or expired, it sends an HTTP 401 Unauthorized response.
|
|
12
12
|
*
|
|
13
13
|
* @see {@link https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/authorization.mdx | MCP Authorization Specification}
|
|
14
|
-
* @module mcp-server/transports/authentication/authMiddleware
|
|
14
|
+
* @module src/mcp-server/transports/authentication/authMiddleware
|
|
15
15
|
*/
|
|
16
16
|
import jwt from "jsonwebtoken";
|
|
17
17
|
import { config, environment } from "../../../config/index.js";
|
|
@@ -45,7 +45,10 @@ export function mcpAuthMiddleware(req, res, next) {
|
|
|
45
45
|
scopes: ["dev-scope"],
|
|
46
46
|
};
|
|
47
47
|
// Log dev mode details separately, not attaching to req.auth if not part of AuthInfo
|
|
48
|
-
logger.debug("Dev mode auth object created.", {
|
|
48
|
+
logger.debug("Dev mode auth object created.", {
|
|
49
|
+
...context,
|
|
50
|
+
authDetails: req.auth,
|
|
51
|
+
});
|
|
49
52
|
return next();
|
|
50
53
|
}
|
|
51
54
|
else {
|
|
@@ -67,7 +70,9 @@ export function mcpAuthMiddleware(req, res, next) {
|
|
|
67
70
|
const tokenParts = authHeader.split(" ");
|
|
68
71
|
if (tokenParts.length !== 2 || tokenParts[0] !== "Bearer" || !tokenParts[1]) {
|
|
69
72
|
logger.warning("Authentication failed: Malformed Bearer token.", context);
|
|
70
|
-
res
|
|
73
|
+
res
|
|
74
|
+
.status(401)
|
|
75
|
+
.json({ error: "Unauthorized: Malformed authentication token." });
|
|
71
76
|
return;
|
|
72
77
|
}
|
|
73
78
|
const rawToken = tokenParts[1];
|
|
@@ -75,26 +80,37 @@ export function mcpAuthMiddleware(req, res, next) {
|
|
|
75
80
|
const decoded = jwt.verify(rawToken, config.mcpAuthSecretKey);
|
|
76
81
|
if (typeof decoded === "string") {
|
|
77
82
|
logger.warning("Authentication failed: JWT decoded to a string, expected an object payload.", context);
|
|
78
|
-
res
|
|
83
|
+
res
|
|
84
|
+
.status(401)
|
|
85
|
+
.json({ error: "Unauthorized: Invalid token payload format." });
|
|
79
86
|
return;
|
|
80
87
|
}
|
|
81
88
|
// Extract and validate fields for SDK's AuthInfo
|
|
82
|
-
const clientIdFromToken = typeof decoded.cid ===
|
|
89
|
+
const clientIdFromToken = typeof decoded.cid === "string"
|
|
90
|
+
? decoded.cid
|
|
91
|
+
: typeof decoded.client_id === "string"
|
|
92
|
+
? decoded.client_id
|
|
93
|
+
: undefined;
|
|
83
94
|
if (!clientIdFromToken) {
|
|
84
95
|
logger.warning("Authentication failed: JWT 'cid' or 'client_id' claim is missing or not a string.", { ...context, jwtPayloadKeys: Object.keys(decoded) });
|
|
85
|
-
res.status(401).json({
|
|
96
|
+
res.status(401).json({
|
|
97
|
+
error: "Unauthorized: Invalid token, missing client identifier.",
|
|
98
|
+
});
|
|
86
99
|
return;
|
|
87
100
|
}
|
|
88
101
|
let scopesFromToken;
|
|
89
|
-
if (Array.isArray(decoded.scp) &&
|
|
102
|
+
if (Array.isArray(decoded.scp) &&
|
|
103
|
+
decoded.scp.every((s) => typeof s === "string")) {
|
|
90
104
|
scopesFromToken = decoded.scp;
|
|
91
105
|
}
|
|
92
|
-
else if (typeof decoded.scope ===
|
|
93
|
-
|
|
94
|
-
|
|
106
|
+
else if (typeof decoded.scope === "string" &&
|
|
107
|
+
decoded.scope.trim() !== "") {
|
|
108
|
+
scopesFromToken = decoded.scope.split(" ").filter((s) => s);
|
|
109
|
+
if (scopesFromToken.length === 0 && decoded.scope.trim() !== "") {
|
|
110
|
+
// handles case " " -> [""]
|
|
95
111
|
scopesFromToken = [decoded.scope.trim()];
|
|
96
112
|
}
|
|
97
|
-
else if (scopesFromToken.length === 0 && decoded.scope.trim() ===
|
|
113
|
+
else if (scopesFromToken.length === 0 && decoded.scope.trim() === "") {
|
|
98
114
|
// If scope is an empty string, treat as no scopes rather than erroring, or use a default.
|
|
99
115
|
// Depending on strictness, could also error here. For now, allow empty array if scope was empty string.
|
|
100
116
|
logger.debug("JWT 'scope' claim was an empty string, resulting in empty scopes array.", context);
|
|
@@ -116,15 +132,23 @@ export function mcpAuthMiddleware(req, res, next) {
|
|
|
116
132
|
scopes: scopesFromToken,
|
|
117
133
|
};
|
|
118
134
|
// Log separately if other JWT claims like 'sub' (sessionId) are needed for app logic
|
|
119
|
-
const subClaimForLogging = typeof decoded.sub ===
|
|
120
|
-
logger.debug("JWT verified successfully. AuthInfo attached to request.", {
|
|
135
|
+
const subClaimForLogging = typeof decoded.sub === "string" ? decoded.sub : undefined;
|
|
136
|
+
logger.debug("JWT verified successfully. AuthInfo attached to request.", {
|
|
137
|
+
...context,
|
|
138
|
+
mcpSessionIdContext: subClaimForLogging,
|
|
139
|
+
clientId: req.auth.clientId,
|
|
140
|
+
scopes: req.auth.scopes,
|
|
141
|
+
});
|
|
121
142
|
next();
|
|
122
143
|
}
|
|
123
144
|
catch (error) {
|
|
124
145
|
let errorMessage = "Invalid token";
|
|
125
146
|
if (error instanceof jwt.TokenExpiredError) {
|
|
126
147
|
errorMessage = "Token expired";
|
|
127
|
-
logger.warning("Authentication failed: Token expired.", {
|
|
148
|
+
logger.warning("Authentication failed: Token expired.", {
|
|
149
|
+
...context,
|
|
150
|
+
expiredAt: error.expiredAt,
|
|
151
|
+
});
|
|
128
152
|
}
|
|
129
153
|
else if (error instanceof jwt.JsonWebTokenError) {
|
|
130
154
|
errorMessage = `Invalid token: ${error.message}`;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Specification Reference:
|
|
10
10
|
* https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx#streamable-http
|
|
11
|
-
* @module mcp-server/transports/httpTransport
|
|
11
|
+
* @module src/mcp-server/transports/httpTransport
|
|
12
12
|
*/
|
|
13
13
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
14
14
|
import { RequestContext } from "../../utils/index.js";
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Specification Reference:
|
|
10
10
|
* https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx#streamable-http
|
|
11
|
-
* @module mcp-server/transports/httpTransport
|
|
11
|
+
* @module src/mcp-server/transports/httpTransport
|
|
12
12
|
*/
|
|
13
13
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
14
14
|
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* controlling the server process. This implementation follows that guideline.
|
|
16
16
|
*
|
|
17
17
|
* @see {@link https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/authorization.mdx | MCP Authorization Specification}
|
|
18
|
-
* @module mcp-server/transports/stdioTransport
|
|
18
|
+
* @module src/mcp-server/transports/stdioTransport
|
|
19
19
|
*/
|
|
20
20
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
21
21
|
import { RequestContext } from "../../utils/index.js";
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* controlling the server process. This implementation follows that guideline.
|
|
16
16
|
*
|
|
17
17
|
* @see {@link https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/authorization.mdx | MCP Authorization Specification}
|
|
18
|
-
* @module mcp-server/transports/stdioTransport
|
|
18
|
+
* @module src/mcp-server/transports/stdioTransport
|
|
19
19
|
*/
|
|
20
20
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
21
21
|
import { ErrorHandler, logger } from "../../utils/index.js";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* OpenRouter API, using the OpenAI SDK for chat completions. It handles API key
|
|
4
4
|
* configuration, default parameters, rate limiting, model-specific parameter adjustments,
|
|
5
5
|
* and error handling.
|
|
6
|
-
* @module services/openRouterProvider
|
|
6
|
+
* @module src/services/openRouterProvider
|
|
7
7
|
*/
|
|
8
8
|
import OpenAI from "openai";
|
|
9
9
|
import { config } from "../config/index.js";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* for handling errors within the Model Context Protocol (MCP) server and its components.
|
|
4
4
|
* This module provides a structured way to represent and communicate errors, ensuring
|
|
5
5
|
* consistency and clarity for both server-side operations and client-side error handling.
|
|
6
|
-
* @module types-global/errors
|
|
6
|
+
* @module src/types-global/errors
|
|
7
7
|
*/
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
/**
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* for handling errors within the Model Context Protocol (MCP) server and its components.
|
|
4
4
|
* This module provides a structured way to represent and communicate errors, ensuring
|
|
5
5
|
* consistency and clarity for both server-side operations and client-side error handling.
|
|
6
|
-
* @module types-global/errors
|
|
6
|
+
* @module src/types-global/errors
|
|
7
7
|
*/
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
/**
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* @fileoverview Barrel file for the utils module.
|
|
3
3
|
* This file re-exports all utilities from their categorized subdirectories,
|
|
4
4
|
* providing a single entry point for accessing utility functions.
|
|
5
|
-
* @module utils
|
|
5
|
+
* @module src/utils
|
|
6
6
|
*/
|
|
7
7
|
export * from "./internal/index.js";
|
|
8
|
+
export * from "./metrics/index.js";
|
|
8
9
|
export * from "./parsing/index.js";
|
|
9
10
|
export * from "./security/index.js";
|
|
10
|
-
export * from "./metrics/index.js";
|
package/dist/utils/index.js
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* @fileoverview Barrel file for the utils module.
|
|
3
3
|
* This file re-exports all utilities from their categorized subdirectories,
|
|
4
4
|
* providing a single entry point for accessing utility functions.
|
|
5
|
-
* @module utils
|
|
5
|
+
* @module src/utils
|
|
6
6
|
*/
|
|
7
7
|
// Re-export all utilities from their categorized subdirectories
|
|
8
8
|
export * from "./internal/index.js";
|
|
9
|
+
export * from "./metrics/index.js";
|
|
9
10
|
export * from "./parsing/index.js";
|
|
10
11
|
export * from "./security/index.js";
|
|
11
|
-
export * from "./metrics/index.js";
|
|
12
12
|
// It's good practice to have index.ts files in each subdirectory
|
|
13
13
|
// that export the contents of that directory.
|
|
14
14
|
// Assuming those will be created or already exist.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* It defines structures for error context, options for handling errors,
|
|
4
4
|
* and mappings for classifying errors. The main `ErrorHandler` class
|
|
5
5
|
* offers static methods for consistent error processing, logging, and transformation.
|
|
6
|
-
* @module utils/internal/errorHandler
|
|
6
|
+
* @module src/utils/internal/errorHandler
|
|
7
7
|
*/
|
|
8
8
|
import { BaseErrorCode } from "../../types-global/errors.js";
|
|
9
9
|
/**
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* It defines structures for error context, options for handling errors,
|
|
4
4
|
* and mappings for classifying errors. The main `ErrorHandler` class
|
|
5
5
|
* offers static methods for consistent error processing, logging, and transformation.
|
|
6
|
-
* @module utils/internal/errorHandler
|
|
6
|
+
* @module src/utils/internal/errorHandler
|
|
7
7
|
*/
|
|
8
8
|
import { BaseErrorCode, McpError } from "../../types-global/errors.js";
|
|
9
9
|
import { generateUUID, sanitizeInputForLogging } from "../index.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview Barrel file for internal utility modules.
|
|
3
3
|
* This file re-exports core internal utilities related to error handling,
|
|
4
4
|
* logging, and request context management.
|
|
5
|
-
* @module utils/internal
|
|
5
|
+
* @module src/utils/internal
|
|
6
6
|
*/
|
|
7
7
|
export * from "./errorHandler.js";
|
|
8
8
|
export * from "./logger.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview Barrel file for internal utility modules.
|
|
3
3
|
* This file re-exports core internal utilities related to error handling,
|
|
4
4
|
* logging, and request context management.
|
|
5
|
-
* @module utils/internal
|
|
5
|
+
* @module src/utils/internal
|
|
6
6
|
*/
|
|
7
7
|
export * from "./errorHandler.js";
|
|
8
8
|
export * from "./logger.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview Provides a singleton Logger class that wraps Winston for file logging
|
|
3
3
|
* and supports sending MCP (Model Context Protocol) `notifications/message`.
|
|
4
4
|
* It handles different log levels compliant with RFC 5424 and MCP specifications.
|
|
5
|
-
* @module utils/internal/logger
|
|
5
|
+
* @module src/utils/internal/logger
|
|
6
6
|
*/
|
|
7
7
|
import fs from "fs";
|
|
8
8
|
import path from "path";
|
|
@@ -40,7 +40,8 @@ const projectRoot = process.cwd(); // Use current working directory as project r
|
|
|
40
40
|
const logsDir = path.join(projectRoot, "logs");
|
|
41
41
|
// Security check for the logs directory path
|
|
42
42
|
const resolvedLogsDir = path.resolve(logsDir); // Should be projectRoot/logs
|
|
43
|
-
const isLogsDirSafe = resolvedLogsDir.startsWith(projectRoot + path.sep) &&
|
|
43
|
+
const isLogsDirSafe = resolvedLogsDir.startsWith(projectRoot + path.sep) &&
|
|
44
|
+
resolvedLogsDir !== projectRoot;
|
|
44
45
|
if (!isLogsDirSafe) {
|
|
45
46
|
// This case should ideally not be hit if logsDir is simply projectRoot + /logs
|
|
46
47
|
// But it's a safeguard if path.join or path.resolve behaves unexpectedly or logsDir is manipulated.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* A request context is an object carrying a unique ID, timestamp, and other
|
|
4
4
|
* relevant data for logging, tracing, and processing. It also defines
|
|
5
5
|
* configuration and operational context structures.
|
|
6
|
-
* @module utils/internal/requestContext
|
|
6
|
+
* @module src/utils/internal/requestContext
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
9
|
* Defines the core structure for context information associated with a request or operation.
|
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* A request context is an object carrying a unique ID, timestamp, and other
|
|
4
4
|
* relevant data for logging, tracing, and processing. It also defines
|
|
5
5
|
* configuration and operational context structures.
|
|
6
|
-
* @module utils/internal/requestContext
|
|
6
|
+
* @module src/utils/internal/requestContext
|
|
7
7
|
*/
|
|
8
|
-
import { logger } from "./logger.js";
|
|
9
8
|
import { generateUUID } from "../index.js";
|
|
9
|
+
import { logger } from "./logger.js";
|
|
10
10
|
/**
|
|
11
11
|
* Singleton-like service object for managing request context operations.
|
|
12
12
|
* @private
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* using the `tiktoken` library, specifically configured for 'gpt-4o' tokenization.
|
|
4
4
|
* These functions are essential for managing token limits and estimating costs
|
|
5
5
|
* when interacting with language models.
|
|
6
|
-
* @module utils/metrics/tokenCounter
|
|
6
|
+
* @module src/utils/metrics/tokenCounter
|
|
7
7
|
*/
|
|
8
8
|
import { ChatCompletionMessageParam } from "openai/resources/chat/completions";
|
|
9
9
|
import { RequestContext } from "../index.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Provides utility functions for parsing natural language date strings
|
|
3
3
|
* into Date objects or detailed parsing results using the `chrono-node` library.
|
|
4
|
-
* @module utils/parsing/dateParser
|
|
4
|
+
* @module src/utils/parsing/dateParser
|
|
5
5
|
*/
|
|
6
6
|
import * as chrono from "chrono-node";
|
|
7
7
|
import { RequestContext } from "../index.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Provides utility functions for parsing natural language date strings
|
|
3
3
|
* into Date objects or detailed parsing results using the `chrono-node` library.
|
|
4
|
-
* @module utils/parsing/dateParser
|
|
4
|
+
* @module src/utils/parsing/dateParser
|
|
5
5
|
*/
|
|
6
6
|
import * as chrono from "chrono-node";
|
|
7
7
|
import { BaseErrorCode } from "../../types-global/errors.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview Barrel file for parsing utility modules.
|
|
3
3
|
* This file re-exports utilities related to parsing various data formats,
|
|
4
4
|
* such as JSON and dates.
|
|
5
|
-
* @module utils/parsing
|
|
5
|
+
* @module src/utils/parsing
|
|
6
6
|
*/
|
|
7
|
-
export * from "./jsonParser.js";
|
|
8
7
|
export * from "./dateParser.js";
|
|
8
|
+
export * from "./jsonParser.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview Barrel file for parsing utility modules.
|
|
3
3
|
* This file re-exports utilities related to parsing various data formats,
|
|
4
4
|
* such as JSON and dates.
|
|
5
|
-
* @module utils/parsing
|
|
5
|
+
* @module src/utils/parsing
|
|
6
6
|
*/
|
|
7
|
-
export * from "./jsonParser.js";
|
|
8
7
|
export * from "./dateParser.js";
|
|
8
|
+
export * from "./jsonParser.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview Provides a utility class for parsing potentially partial JSON strings.
|
|
3
3
|
* It wraps the 'partial-json' npm library and includes functionality to handle
|
|
4
4
|
* optional <think>...</think> blocks often found at the beginning of LLM outputs.
|
|
5
|
-
* @module utils/parsing/jsonParser
|
|
5
|
+
* @module src/utils/parsing/jsonParser
|
|
6
6
|
*/
|
|
7
7
|
import { parse as parsePartialJson, Allow as PartialJsonAllow, } from "partial-json";
|
|
8
8
|
import { BaseErrorCode, McpError } from "../../types-global/errors.js";
|
|
@@ -61,9 +61,15 @@ export class JsonParser {
|
|
|
61
61
|
if (match) {
|
|
62
62
|
const thinkContent = match[1].trim();
|
|
63
63
|
const restOfString = match[2];
|
|
64
|
-
const logContext = context ||
|
|
64
|
+
const logContext = context ||
|
|
65
|
+
requestContextService.createRequestContext({
|
|
66
|
+
operation: "JsonParser.thinkBlock",
|
|
67
|
+
});
|
|
65
68
|
if (thinkContent) {
|
|
66
|
-
logger.debug("LLM <think> block detected and logged.", {
|
|
69
|
+
logger.debug("LLM <think> block detected and logged.", {
|
|
70
|
+
...logContext,
|
|
71
|
+
thinkContent,
|
|
72
|
+
});
|
|
67
73
|
}
|
|
68
74
|
else {
|
|
69
75
|
logger.debug("Empty LLM <think> block detected.", logContext);
|
|
@@ -78,7 +84,10 @@ export class JsonParser {
|
|
|
78
84
|
return parsePartialJson(stringToParse, allowPartial);
|
|
79
85
|
}
|
|
80
86
|
catch (error) {
|
|
81
|
-
const errorLogContext = context ||
|
|
87
|
+
const errorLogContext = context ||
|
|
88
|
+
requestContextService.createRequestContext({
|
|
89
|
+
operation: "JsonParser.parseError",
|
|
90
|
+
});
|
|
82
91
|
logger.error("Failed to parse JSON content.", {
|
|
83
92
|
...errorLogContext,
|
|
84
93
|
errorDetails: error.message,
|
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
* with the `requestContextService`, which itself uses `generateUUID` from this module.
|
|
8
8
|
* This was causing `ReferenceError: Cannot access 'generateUUID' before initialization`
|
|
9
9
|
* during application startup.
|
|
10
|
-
* @module utils/security/idGenerator
|
|
10
|
+
* @module src/utils/security/idGenerator
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
12
|
+
import { randomUUID as cryptoRandomUUID, randomBytes } from "crypto";
|
|
13
13
|
import { BaseErrorCode, McpError } from "../../types-global/errors.js";
|
|
14
14
|
/**
|
|
15
15
|
* A generic ID Generator class for creating and managing unique, prefixed identifiers.
|
|
@@ -77,7 +77,9 @@ export class IdGenerator {
|
|
|
77
77
|
// Logging removed.
|
|
78
78
|
const { length = IdGenerator.DEFAULT_LENGTH, separator = IdGenerator.DEFAULT_SEPARATOR, charset = IdGenerator.DEFAULT_CHARSET, } = options;
|
|
79
79
|
const randomPart = this.generateRandomString(length, charset);
|
|
80
|
-
const generatedId = prefix
|
|
80
|
+
const generatedId = prefix
|
|
81
|
+
? `${prefix}${separator}${randomPart}`
|
|
82
|
+
: randomPart;
|
|
81
83
|
return generatedId;
|
|
82
84
|
}
|
|
83
85
|
/**
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* @fileoverview Barrel file for security-related utility modules.
|
|
3
3
|
* This file re-exports utilities for input sanitization, rate limiting,
|
|
4
4
|
* and ID generation.
|
|
5
|
-
* @module utils/security
|
|
5
|
+
* @module src/utils/security
|
|
6
6
|
*/
|
|
7
|
-
export * from "./sanitization.js";
|
|
8
|
-
export * from "./rateLimiter.js";
|
|
9
7
|
export * from "./idGenerator.js";
|
|
8
|
+
export * from "./rateLimiter.js";
|
|
9
|
+
export * from "./sanitization.js";
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* @fileoverview Barrel file for security-related utility modules.
|
|
3
3
|
* This file re-exports utilities for input sanitization, rate limiting,
|
|
4
4
|
* and ID generation.
|
|
5
|
-
* @module utils/security
|
|
5
|
+
* @module src/utils/security
|
|
6
6
|
*/
|
|
7
|
-
export * from "./sanitization.js";
|
|
8
|
-
export * from "./rateLimiter.js";
|
|
9
7
|
export * from "./idGenerator.js";
|
|
8
|
+
export * from "./rateLimiter.js";
|
|
9
|
+
export * from "./sanitization.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Provides a generic `RateLimiter` class for implementing rate limiting logic.
|
|
3
3
|
* It supports configurable time windows, request limits, and automatic cleanup of expired entries.
|
|
4
|
-
* @module utils/security/rateLimiter
|
|
4
|
+
* @module src/utils/security/rateLimiter
|
|
5
5
|
*/
|
|
6
6
|
import { environment } from "../../config/index.js";
|
|
7
7
|
import { BaseErrorCode, McpError } from "../../types-global/errors.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @fileoverview Provides a comprehensive `Sanitization` class for various input cleaning and validation tasks.
|
|
3
3
|
* This module includes utilities for sanitizing HTML, strings, URLs, file paths, JSON, numbers,
|
|
4
4
|
* and for redacting sensitive information from data intended for logging.
|
|
5
|
-
* @module utils/security/sanitization
|
|
5
|
+
* @module src/utils/security/sanitization
|
|
6
6
|
*/
|
|
7
7
|
import path from "path";
|
|
8
8
|
import sanitizeHtml from "sanitize-html";
|
|
@@ -22,8 +22,19 @@ export class Sanitization {
|
|
|
22
22
|
* @private
|
|
23
23
|
*/
|
|
24
24
|
this.sensitiveFields = [
|
|
25
|
-
"password",
|
|
26
|
-
"
|
|
25
|
+
"password",
|
|
26
|
+
"token",
|
|
27
|
+
"secret",
|
|
28
|
+
"key",
|
|
29
|
+
"apiKey",
|
|
30
|
+
"auth",
|
|
31
|
+
"credential",
|
|
32
|
+
"jwt",
|
|
33
|
+
"ssn",
|
|
34
|
+
"credit",
|
|
35
|
+
"card",
|
|
36
|
+
"cvv",
|
|
37
|
+
"authorization",
|
|
27
38
|
];
|
|
28
39
|
/**
|
|
29
40
|
* Default configuration for HTML sanitization.
|
|
@@ -31,9 +42,33 @@ export class Sanitization {
|
|
|
31
42
|
*/
|
|
32
43
|
this.defaultHtmlSanitizeConfig = {
|
|
33
44
|
allowedTags: [
|
|
34
|
-
"h1",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
45
|
+
"h1",
|
|
46
|
+
"h2",
|
|
47
|
+
"h3",
|
|
48
|
+
"h4",
|
|
49
|
+
"h5",
|
|
50
|
+
"h6",
|
|
51
|
+
"p",
|
|
52
|
+
"a",
|
|
53
|
+
"ul",
|
|
54
|
+
"ol",
|
|
55
|
+
"li",
|
|
56
|
+
"b",
|
|
57
|
+
"i",
|
|
58
|
+
"strong",
|
|
59
|
+
"em",
|
|
60
|
+
"strike",
|
|
61
|
+
"code",
|
|
62
|
+
"hr",
|
|
63
|
+
"br",
|
|
64
|
+
"div",
|
|
65
|
+
"table",
|
|
66
|
+
"thead",
|
|
67
|
+
"tbody",
|
|
68
|
+
"tr",
|
|
69
|
+
"th",
|
|
70
|
+
"td",
|
|
71
|
+
"pre",
|
|
37
72
|
],
|
|
38
73
|
allowedAttributes: {
|
|
39
74
|
a: ["href", "name", "target"],
|
|
@@ -120,13 +155,23 @@ export class Sanitization {
|
|
|
120
155
|
case "attribute":
|
|
121
156
|
return sanitizeHtml(input, { allowedTags: [], allowedAttributes: {} });
|
|
122
157
|
case "url":
|
|
123
|
-
if (!validator.isURL(input, {
|
|
124
|
-
|
|
158
|
+
if (!validator.isURL(input, {
|
|
159
|
+
protocols: ["http", "https"],
|
|
160
|
+
require_protocol: true,
|
|
161
|
+
require_host: true,
|
|
162
|
+
})) {
|
|
163
|
+
logger.warning("Potentially invalid URL detected during string sanitization (context: url)", requestContextService.createRequestContext({
|
|
164
|
+
operation: "Sanitization.sanitizeString.urlWarning",
|
|
165
|
+
invalidUrlAttempt: input,
|
|
166
|
+
}));
|
|
125
167
|
return "";
|
|
126
168
|
}
|
|
127
169
|
return validator.trim(input);
|
|
128
170
|
case "javascript":
|
|
129
|
-
logger.error("Attempted JavaScript sanitization via sanitizeString, which is disallowed.", requestContextService.createRequestContext({
|
|
171
|
+
logger.error("Attempted JavaScript sanitization via sanitizeString, which is disallowed.", requestContextService.createRequestContext({
|
|
172
|
+
operation: "Sanitization.sanitizeString.jsAttempt",
|
|
173
|
+
inputSnippet: input.substring(0, 50),
|
|
174
|
+
}));
|
|
130
175
|
throw new McpError(BaseErrorCode.VALIDATION_ERROR, "JavaScript sanitization is not supported through sanitizeString due to security risks.");
|
|
131
176
|
case "text":
|
|
132
177
|
default:
|
|
@@ -152,7 +197,11 @@ export class Sanitization {
|
|
|
152
197
|
sanitizeUrl(input, allowedProtocols = ["http", "https"]) {
|
|
153
198
|
try {
|
|
154
199
|
const trimmedInput = input.trim();
|
|
155
|
-
if (!validator.isURL(trimmedInput, {
|
|
200
|
+
if (!validator.isURL(trimmedInput, {
|
|
201
|
+
protocols: allowedProtocols,
|
|
202
|
+
require_protocol: true,
|
|
203
|
+
require_host: true,
|
|
204
|
+
})) {
|
|
156
205
|
throw new Error("Invalid URL format or protocol not in allowed list.");
|
|
157
206
|
}
|
|
158
207
|
if (trimmedInput.toLowerCase().startsWith("javascript:")) {
|
|
@@ -161,7 +210,9 @@ export class Sanitization {
|
|
|
161
210
|
return trimmedInput;
|
|
162
211
|
}
|
|
163
212
|
catch (error) {
|
|
164
|
-
throw new McpError(BaseErrorCode.VALIDATION_ERROR, error instanceof Error
|
|
213
|
+
throw new McpError(BaseErrorCode.VALIDATION_ERROR, error instanceof Error
|
|
214
|
+
? error.message
|
|
215
|
+
: "Invalid or unsafe URL provided.", { input });
|
|
165
216
|
}
|
|
166
217
|
}
|
|
167
218
|
/**
|
|
@@ -193,12 +244,15 @@ export class Sanitization {
|
|
|
193
244
|
let finalSanitizedPath;
|
|
194
245
|
if (effectiveOptions.rootDir) {
|
|
195
246
|
const fullPath = path.resolve(effectiveOptions.rootDir, normalized);
|
|
196
|
-
if (!fullPath.startsWith(effectiveOptions.rootDir + path.sep) &&
|
|
247
|
+
if (!fullPath.startsWith(effectiveOptions.rootDir + path.sep) &&
|
|
248
|
+
fullPath !== effectiveOptions.rootDir) {
|
|
197
249
|
throw new Error("Path traversal detected: attempts to escape the defined root directory.");
|
|
198
250
|
}
|
|
199
251
|
finalSanitizedPath = path.relative(effectiveOptions.rootDir, fullPath);
|
|
200
|
-
finalSanitizedPath =
|
|
201
|
-
|
|
252
|
+
finalSanitizedPath =
|
|
253
|
+
finalSanitizedPath === "" ? "." : finalSanitizedPath;
|
|
254
|
+
if (path.isAbsolute(finalSanitizedPath) &&
|
|
255
|
+
!effectiveOptions.allowAbsolute) {
|
|
202
256
|
throw new Error("Path resolved to absolute outside root when absolute paths are disallowed.");
|
|
203
257
|
}
|
|
204
258
|
}
|
|
@@ -215,7 +269,8 @@ export class Sanitization {
|
|
|
215
269
|
else {
|
|
216
270
|
const resolvedAgainstCwd = path.resolve(normalized);
|
|
217
271
|
const currentWorkingDir = path.resolve(".");
|
|
218
|
-
if (!resolvedAgainstCwd.startsWith(currentWorkingDir + path.sep) &&
|
|
272
|
+
if (!resolvedAgainstCwd.startsWith(currentWorkingDir + path.sep) &&
|
|
273
|
+
resolvedAgainstCwd !== currentWorkingDir) {
|
|
219
274
|
throw new Error("Relative path traversal detected (escapes current working directory context).");
|
|
220
275
|
}
|
|
221
276
|
finalSanitizedPath = normalized;
|
|
@@ -225,7 +280,9 @@ export class Sanitization {
|
|
|
225
280
|
sanitizedPath: finalSanitizedPath,
|
|
226
281
|
originalInput,
|
|
227
282
|
wasAbsolute: wasAbsoluteInitially,
|
|
228
|
-
convertedToRelative: wasAbsoluteInitially &&
|
|
283
|
+
convertedToRelative: wasAbsoluteInitially &&
|
|
284
|
+
!path.isAbsolute(finalSanitizedPath) &&
|
|
285
|
+
!effectiveOptions.allowAbsolute,
|
|
229
286
|
optionsUsed: effectiveOptions,
|
|
230
287
|
};
|
|
231
288
|
}
|
|
@@ -236,7 +293,9 @@ export class Sanitization {
|
|
|
236
293
|
pathOptionsUsed: effectiveOptions,
|
|
237
294
|
errorMessage: error instanceof Error ? error.message : String(error),
|
|
238
295
|
}));
|
|
239
|
-
throw new McpError(BaseErrorCode.VALIDATION_ERROR, error instanceof Error
|
|
296
|
+
throw new McpError(BaseErrorCode.VALIDATION_ERROR, error instanceof Error
|
|
297
|
+
? error.message
|
|
298
|
+
: "Invalid or unsafe path provided.", { input: originalInput });
|
|
240
299
|
}
|
|
241
300
|
}
|
|
242
301
|
/**
|
|
@@ -260,7 +319,9 @@ export class Sanitization {
|
|
|
260
319
|
catch (error) {
|
|
261
320
|
if (error instanceof McpError)
|
|
262
321
|
throw error;
|
|
263
|
-
throw new McpError(BaseErrorCode.VALIDATION_ERROR, error instanceof Error ? error.message : "Invalid JSON format.", {
|
|
322
|
+
throw new McpError(BaseErrorCode.VALIDATION_ERROR, error instanceof Error ? error.message : "Invalid JSON format.", {
|
|
323
|
+
inputPreview: input.length > 100 ? `${input.substring(0, 100)}...` : input,
|
|
324
|
+
});
|
|
264
325
|
}
|
|
265
326
|
}
|
|
266
327
|
/**
|
|
@@ -324,7 +385,9 @@ export class Sanitization {
|
|
|
324
385
|
try {
|
|
325
386
|
if (!input || typeof input !== "object")
|
|
326
387
|
return input;
|
|
327
|
-
const clonedInput = typeof structuredClone === "function"
|
|
388
|
+
const clonedInput = typeof structuredClone === "function"
|
|
389
|
+
? structuredClone(input)
|
|
390
|
+
: JSON.parse(JSON.stringify(input));
|
|
328
391
|
this.redactSensitiveFields(clonedInput);
|
|
329
392
|
return clonedInput;
|
|
330
393
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-ts-template",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "TypeScript template for building Model Context Protocol (MCP) servers & clients. Features production-ready utilities, stdio/HTTP transports (with JWT auth), examples, and type safety. Ideal starting point for creating MCP-based applications.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|