mcp-ts-template 2.2.0 → 2.2.2
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 +39 -34
- package/dist/index.js +336 -234
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
<div align="center">
|
|
7
7
|
|
|
8
|
-
[](./CHANGELOG.md) [](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-06-18/changelog.mdx) [](https://modelcontextprotocol.io/) [](./LICENSE) [](https://github.com/cyanheads/mcp-ts-template/issues) [](https://www.typescriptlang.org/) [](https://bun.sh/) [](./coverage/lcov-report/)
|
|
9
9
|
|
|
10
10
|
</div>
|
|
11
11
|
|
|
@@ -30,18 +30,20 @@
|
|
|
30
30
|
|
|
31
31
|
### Installation
|
|
32
32
|
|
|
33
|
-
1.
|
|
34
|
-
|
|
33
|
+
1. **Clone the repository:**
|
|
34
|
+
|
|
35
35
|
```sh
|
|
36
36
|
git clone https://github.com/cyanheads/mcp-ts-template.git
|
|
37
37
|
```
|
|
38
|
-
|
|
39
|
-
**Navigate into the directory:**
|
|
38
|
+
|
|
39
|
+
2. **Navigate into the directory:**
|
|
40
|
+
|
|
40
41
|
```sh
|
|
41
42
|
cd mcp-ts-template
|
|
42
43
|
```
|
|
43
|
-
|
|
44
|
-
**Install dependencies:**
|
|
44
|
+
|
|
45
|
+
3. **Install dependencies:**
|
|
46
|
+
|
|
45
47
|
```sh
|
|
46
48
|
bun install
|
|
47
49
|
```
|
|
@@ -60,7 +62,10 @@ This tool echoes back a message with optional formatting. You can find the full
|
|
|
60
62
|
```ts
|
|
61
63
|
// Located at: src/mcp-server/tools/definitions/template-echo-message.tool.ts
|
|
62
64
|
import { z } from 'zod';
|
|
63
|
-
import type {
|
|
65
|
+
import type {
|
|
66
|
+
SdkContext,
|
|
67
|
+
ToolDefinition,
|
|
68
|
+
} from '@/mcp-server/tools/utils/toolDefinition.js';
|
|
64
69
|
import { withToolAuth } from '@/mcp-server/transports/auth/lib/withAuth.js';
|
|
65
70
|
import { type RequestContext, logger } from '@/utils/index.js';
|
|
66
71
|
|
|
@@ -180,14 +185,14 @@ Like the tool, `echoResourceDefinition` is registered in `src/mcp-server/resourc
|
|
|
180
185
|
|
|
181
186
|
All configuration is centralized and validated at startup in `src/config/index.ts`. Key environment variables in your `.env` file include:
|
|
182
187
|
|
|
183
|
-
| Variable
|
|
184
|
-
|
|
|
185
|
-
| `MCP_TRANSPORT_TYPE`
|
|
186
|
-
| `MCP_HTTP_PORT`
|
|
187
|
-
| `MCP_AUTH_MODE`
|
|
188
|
+
| Variable | Description | Default |
|
|
189
|
+
| :---------------------- | :----------------------------------------------------------------------------- | :---------- |
|
|
190
|
+
| `MCP_TRANSPORT_TYPE` | The transport to use: `stdio` or `http`. | `http` |
|
|
191
|
+
| `MCP_HTTP_PORT` | The port for the HTTP server. | `3010` |
|
|
192
|
+
| `MCP_AUTH_MODE` | Authentication mode: `none`, `jwt`, or `oauth`. | `none` |
|
|
188
193
|
| `STORAGE_PROVIDER_TYPE` | Storage backend: `in-memory`, `filesystem`, `supabase`, `cloudflare-kv`, `r2`. | `in-memory` |
|
|
189
|
-
| `OTEL_ENABLED`
|
|
190
|
-
| `LOG_LEVEL`
|
|
194
|
+
| `OTEL_ENABLED` | Set to `true` to enable OpenTelemetry. | `false` |
|
|
195
|
+
| `LOG_LEVEL` | The minimum level for logging. | `info` |
|
|
191
196
|
|
|
192
197
|
### Authentication & Authorization
|
|
193
198
|
|
|
@@ -229,36 +234,36 @@ All configuration is centralized and validated at startup in `src/config/index.t
|
|
|
229
234
|
|
|
230
235
|
### Cloudflare Workers
|
|
231
236
|
|
|
232
|
-
1.
|
|
233
|
-
|
|
237
|
+
1. **Build the Worker bundle**:
|
|
238
|
+
|
|
234
239
|
```sh
|
|
235
240
|
bun build:worker
|
|
236
241
|
```
|
|
237
|
-
|
|
238
|
-
**Run locally with Wrangler**:
|
|
242
|
+
|
|
243
|
+
2. **Run locally with Wrangler**:
|
|
244
|
+
|
|
239
245
|
```sh
|
|
240
246
|
bun deploy:dev
|
|
241
247
|
```
|
|
242
|
-
|
|
243
|
-
**Deploy to Cloudflare**:
|
|
244
|
-
`sh
|
|
248
|
+
|
|
249
|
+
3. **Deploy to Cloudflare**:
|
|
250
|
+
`sh
|
|
245
251
|
bun deploy:prod
|
|
246
|
-
`
|
|
247
|
-
> **Note**: The `wrangler.toml` file is pre-configured to enable `nodejs_compat` for best results.
|
|
252
|
+
` > **Note**: The `wrangler.toml` file is pre-configured to enable `nodejs_compat` for best results.
|
|
248
253
|
|
|
249
254
|
## 📂 Project Structure
|
|
250
255
|
|
|
251
|
-
| Directory
|
|
252
|
-
|
|
|
253
|
-
| `src/mcp-server/tools/definitions`
|
|
256
|
+
| Directory | Purpose & Contents |
|
|
257
|
+
| :------------------------------------- | :----------------------------------------------------------------------------------- |
|
|
258
|
+
| `src/mcp-server/tools/definitions` | Your tool definitions (`*.tool.ts`). This is where you add new capabilities. |
|
|
254
259
|
| `src/mcp-server/resources/definitions` | Your resource definitions (`*.resource.ts`). This is where you add new data sources. |
|
|
255
|
-
| `src/mcp-server/transports`
|
|
256
|
-
| `src/storage`
|
|
257
|
-
| `src/services`
|
|
258
|
-
| `src/container`
|
|
259
|
-
| `src/utils`
|
|
260
|
-
| `src/config`
|
|
261
|
-
| `tests/`
|
|
260
|
+
| `src/mcp-server/transports` | Implementations for HTTP and STDIO transports, including auth middleware. |
|
|
261
|
+
| `src/storage` | The `StorageService` abstraction and all storage provider implementations. |
|
|
262
|
+
| `src/services` | Integrations with external services (e.g., the default OpenRouter LLM provider). |
|
|
263
|
+
| `src/container` | Dependency injection container registrations and tokens. |
|
|
264
|
+
| `src/utils` | Core utilities for logging, error handling, performance, security, and telemetry. |
|
|
265
|
+
| `src/config` | Environment variable parsing and validation with Zod. |
|
|
266
|
+
| `tests/` | Unit and integration tests, mirroring the `src/` directory structure. |
|
|
262
267
|
|
|
263
268
|
## 🧑💻 Agent Development Guide
|
|
264
269
|
|
package/dist/index.js
CHANGED
|
@@ -117226,10 +117226,55 @@ var z = /* @__PURE__ */ Object.freeze({
|
|
|
117226
117226
|
quotelessJson,
|
|
117227
117227
|
ZodError
|
|
117228
117228
|
});
|
|
117229
|
+
|
|
117230
|
+
// src/types-global/errors.ts
|
|
117231
|
+
var JsonRpcErrorCode;
|
|
117232
|
+
((JsonRpcErrorCode2) => {
|
|
117233
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["ParseError"] = -32700] = "ParseError";
|
|
117234
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["InvalidRequest"] = -32600] = "InvalidRequest";
|
|
117235
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["MethodNotFound"] = -32601] = "MethodNotFound";
|
|
117236
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["InvalidParams"] = -32602] = "InvalidParams";
|
|
117237
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["InternalError"] = -32603] = "InternalError";
|
|
117238
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["ServiceUnavailable"] = -32000] = "ServiceUnavailable";
|
|
117239
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["NotFound"] = -32001] = "NotFound";
|
|
117240
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["Conflict"] = -32002] = "Conflict";
|
|
117241
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["RateLimited"] = -32003] = "RateLimited";
|
|
117242
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["Timeout"] = -32004] = "Timeout";
|
|
117243
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["Forbidden"] = -32005] = "Forbidden";
|
|
117244
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["Unauthorized"] = -32006] = "Unauthorized";
|
|
117245
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["ValidationError"] = -32007] = "ValidationError";
|
|
117246
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["ConfigurationError"] = -32008] = "ConfigurationError";
|
|
117247
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["InitializationFailed"] = -32009] = "InitializationFailed";
|
|
117248
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["DatabaseError"] = -32010] = "DatabaseError";
|
|
117249
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["SerializationError"] = -32070] = "SerializationError";
|
|
117250
|
+
JsonRpcErrorCode2[JsonRpcErrorCode2["UnknownError"] = -32099] = "UnknownError";
|
|
117251
|
+
})(JsonRpcErrorCode ||= {});
|
|
117252
|
+
|
|
117253
|
+
class McpError extends Error {
|
|
117254
|
+
code;
|
|
117255
|
+
data;
|
|
117256
|
+
constructor(code, message, data, options) {
|
|
117257
|
+
super(message, options);
|
|
117258
|
+
this.code = code;
|
|
117259
|
+
if (data) {
|
|
117260
|
+
this.data = data;
|
|
117261
|
+
}
|
|
117262
|
+
this.name = "McpError";
|
|
117263
|
+
Object.setPrototypeOf(this, McpError.prototype);
|
|
117264
|
+
if (Error.captureStackTrace) {
|
|
117265
|
+
Error.captureStackTrace(this, McpError);
|
|
117266
|
+
}
|
|
117267
|
+
}
|
|
117268
|
+
}
|
|
117269
|
+
var ErrorSchema = z.object({
|
|
117270
|
+
code: z.nativeEnum(JsonRpcErrorCode).describe("Standardized error code from JsonRpcErrorCode enum"),
|
|
117271
|
+
message: z.string().min(1, "Error message cannot be empty.").describe("Detailed human-readable error message"),
|
|
117272
|
+
data: z.record(z.string(), z.unknown()).optional().describe("Optional structured data providing more context about the error")
|
|
117273
|
+
}).describe("Schema for validating structured error objects, ensuring consistency in error reporting.");
|
|
117229
117274
|
// package.json
|
|
117230
117275
|
var package_default = {
|
|
117231
117276
|
name: "mcp-ts-template",
|
|
117232
|
-
version: "2.1
|
|
117277
|
+
version: "2.2.1",
|
|
117233
117278
|
mcpName: "io.github.cyanheads/mcp-ts-template",
|
|
117234
117279
|
description: "The definitive, production-grade template for building powerful and scalable Model Context Protocol (MCP) servers with TypeScript, featuring built-in observability (OpenTelemetry), declarative tooling, robust error handling, and a modular, DI-driven architecture.",
|
|
117235
117280
|
main: "dist/index.js",
|
|
@@ -117285,7 +117330,7 @@ var package_default = {
|
|
|
117285
117330
|
inspector: "bunx mcp-inspector --config mcp.json --server mcp-ts-template",
|
|
117286
117331
|
"db:duckdb-example": "MCP_LOG_LEVEL=debug tsc && node dist/storage/duckdbExample.js",
|
|
117287
117332
|
test: "bun test --config vitest.config.ts",
|
|
117288
|
-
"test:coverage": "bun test --coverage
|
|
117333
|
+
"test:coverage": "bun test --coverage",
|
|
117289
117334
|
audit: "bun audit",
|
|
117290
117335
|
"audit:fix": "bun audit --fix",
|
|
117291
117336
|
"publish-mcp": "bun scripts/validate-mcp-publish-schema.ts"
|
|
@@ -117383,6 +117428,7 @@ var package_default = {
|
|
|
117383
117428
|
"mcp",
|
|
117384
117429
|
"model-context-protocol",
|
|
117385
117430
|
"mcp-server",
|
|
117431
|
+
"elicitation",
|
|
117386
117432
|
"observability",
|
|
117387
117433
|
"opentelemetry",
|
|
117388
117434
|
"otel",
|
|
@@ -117420,7 +117466,7 @@ var package_default = {
|
|
|
117420
117466
|
// src/config/index.ts
|
|
117421
117467
|
var packageManifest = package_default;
|
|
117422
117468
|
var hasFileSystemAccess = typeof process !== "undefined" && typeof process.versions === "object" && process.versions !== null && typeof process.versions.node === "string";
|
|
117423
|
-
import_dotenv.default.config();
|
|
117469
|
+
import_dotenv.default.config({ quiet: true });
|
|
117424
117470
|
var emptyStringAsUndefined = (val) => {
|
|
117425
117471
|
if (typeof val === "string" && val.trim() === "") {
|
|
117426
117472
|
return;
|
|
@@ -117639,7 +117685,9 @@ var parseConfig = () => {
|
|
|
117639
117685
|
if (process.stdout.isTTY) {
|
|
117640
117686
|
console.error("❌ Invalid configuration found. Please check your environment variables.", parsedConfig.error.flatten().fieldErrors);
|
|
117641
117687
|
}
|
|
117642
|
-
|
|
117688
|
+
throw new McpError(-32008 /* ConfigurationError */, "Invalid application configuration.", {
|
|
117689
|
+
validationErrors: parsedConfig.error.flatten().fieldErrors
|
|
117690
|
+
});
|
|
117643
117691
|
}
|
|
117644
117692
|
return parsedConfig.data;
|
|
117645
117693
|
};
|
|
@@ -117728,54 +117776,9 @@ async function shutdownOpenTelemetry() {
|
|
|
117728
117776
|
// src/index.ts
|
|
117729
117777
|
var import_reflect_metadata2 = __toESM(require_Reflect(), 1);
|
|
117730
117778
|
|
|
117731
|
-
// src/utils/internal/errorHandler.ts
|
|
117779
|
+
// src/utils/internal/error-handler/errorHandler.ts
|
|
117732
117780
|
var import_api3 = __toESM(require_src(), 1);
|
|
117733
117781
|
|
|
117734
|
-
// src/types-global/errors.ts
|
|
117735
|
-
var JsonRpcErrorCode;
|
|
117736
|
-
((JsonRpcErrorCode2) => {
|
|
117737
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["ParseError"] = -32700] = "ParseError";
|
|
117738
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["InvalidRequest"] = -32600] = "InvalidRequest";
|
|
117739
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["MethodNotFound"] = -32601] = "MethodNotFound";
|
|
117740
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["InvalidParams"] = -32602] = "InvalidParams";
|
|
117741
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["InternalError"] = -32603] = "InternalError";
|
|
117742
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["ServiceUnavailable"] = -32000] = "ServiceUnavailable";
|
|
117743
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["NotFound"] = -32001] = "NotFound";
|
|
117744
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["Conflict"] = -32002] = "Conflict";
|
|
117745
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["RateLimited"] = -32003] = "RateLimited";
|
|
117746
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["Timeout"] = -32004] = "Timeout";
|
|
117747
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["Forbidden"] = -32005] = "Forbidden";
|
|
117748
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["Unauthorized"] = -32006] = "Unauthorized";
|
|
117749
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["ValidationError"] = -32007] = "ValidationError";
|
|
117750
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["ConfigurationError"] = -32008] = "ConfigurationError";
|
|
117751
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["InitializationFailed"] = -32009] = "InitializationFailed";
|
|
117752
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["DatabaseError"] = -32010] = "DatabaseError";
|
|
117753
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["SerializationError"] = -32070] = "SerializationError";
|
|
117754
|
-
JsonRpcErrorCode2[JsonRpcErrorCode2["UnknownError"] = -32099] = "UnknownError";
|
|
117755
|
-
})(JsonRpcErrorCode ||= {});
|
|
117756
|
-
|
|
117757
|
-
class McpError extends Error {
|
|
117758
|
-
code;
|
|
117759
|
-
data;
|
|
117760
|
-
constructor(code, message, data, options) {
|
|
117761
|
-
super(message, options);
|
|
117762
|
-
this.code = code;
|
|
117763
|
-
if (data) {
|
|
117764
|
-
this.data = data;
|
|
117765
|
-
}
|
|
117766
|
-
this.name = "McpError";
|
|
117767
|
-
Object.setPrototypeOf(this, McpError.prototype);
|
|
117768
|
-
if (Error.captureStackTrace) {
|
|
117769
|
-
Error.captureStackTrace(this, McpError);
|
|
117770
|
-
}
|
|
117771
|
-
}
|
|
117772
|
-
}
|
|
117773
|
-
var ErrorSchema = z.object({
|
|
117774
|
-
code: z.nativeEnum(JsonRpcErrorCode).describe("Standardized error code from JsonRpcErrorCode enum"),
|
|
117775
|
-
message: z.string().min(1, "Error message cannot be empty.").describe("Detailed human-readable error message"),
|
|
117776
|
-
data: z.record(z.string(), z.unknown()).optional().describe("Optional structured data providing more context about the error")
|
|
117777
|
-
}).describe("Schema for validating structured error objects, ensuring consistency in error reporting.");
|
|
117778
|
-
|
|
117779
117782
|
// src/utils/internal/logger.ts
|
|
117780
117783
|
var import_pino = __toESM(require_pino(), 1);
|
|
117781
117784
|
|
|
@@ -118461,7 +118464,7 @@ class Logger {
|
|
|
118461
118464
|
}
|
|
118462
118465
|
var logger = Logger.getInstance();
|
|
118463
118466
|
|
|
118464
|
-
// src/utils/internal/
|
|
118467
|
+
// src/utils/internal/error-handler/mappings.ts
|
|
118465
118468
|
var ERROR_TYPE_MAPPINGS = {
|
|
118466
118469
|
SyntaxError: -32007 /* ValidationError */,
|
|
118467
118470
|
TypeError: -32007 /* ValidationError */,
|
|
@@ -118513,6 +118516,8 @@ var COMMON_ERROR_PATTERNS = [
|
|
|
118513
118516
|
errorCode: -32007 /* ValidationError */
|
|
118514
118517
|
}
|
|
118515
118518
|
];
|
|
118519
|
+
|
|
118520
|
+
// src/utils/internal/error-handler/helpers.ts
|
|
118516
118521
|
function createSafeRegex(pattern) {
|
|
118517
118522
|
if (pattern instanceof RegExp) {
|
|
118518
118523
|
let flags = pattern.flags.replace("g", "");
|
|
@@ -118539,23 +118544,23 @@ function getErrorName(error) {
|
|
|
118539
118544
|
return `${typeof error}Encountered`;
|
|
118540
118545
|
}
|
|
118541
118546
|
function getErrorMessage(error) {
|
|
118542
|
-
if (error instanceof Error) {
|
|
118543
|
-
if ("errors" in error && Array.isArray(error.errors)) {
|
|
118544
|
-
const inner = error.errors.map((e) => e instanceof Error ? e.message : String(e)).filter(Boolean).slice(0, 3).join("; ");
|
|
118545
|
-
return inner ? `${error.message}: ${inner}` : error.message;
|
|
118546
|
-
}
|
|
118547
|
-
return error.message;
|
|
118548
|
-
}
|
|
118549
|
-
if (error === null) {
|
|
118550
|
-
return "Null value encountered as error";
|
|
118551
|
-
}
|
|
118552
|
-
if (error === undefined) {
|
|
118553
|
-
return "Undefined value encountered as error";
|
|
118554
|
-
}
|
|
118555
|
-
if (typeof error === "string") {
|
|
118556
|
-
return error;
|
|
118557
|
-
}
|
|
118558
118547
|
try {
|
|
118548
|
+
if (error instanceof Error) {
|
|
118549
|
+
if ("errors" in error && Array.isArray(error.errors)) {
|
|
118550
|
+
const inner = error.errors.map((e) => e instanceof Error ? e.message : String(e)).filter(Boolean).slice(0, 3).join("; ");
|
|
118551
|
+
return inner ? `${error.message}: ${inner}` : error.message;
|
|
118552
|
+
}
|
|
118553
|
+
return error.message;
|
|
118554
|
+
}
|
|
118555
|
+
if (error === null) {
|
|
118556
|
+
return "Null value encountered as error";
|
|
118557
|
+
}
|
|
118558
|
+
if (error === undefined) {
|
|
118559
|
+
return "Undefined value encountered as error";
|
|
118560
|
+
}
|
|
118561
|
+
if (typeof error === "string") {
|
|
118562
|
+
return error;
|
|
118563
|
+
}
|
|
118559
118564
|
if (typeof error === "number" || typeof error === "boolean") {
|
|
118560
118565
|
return String(error);
|
|
118561
118566
|
}
|
|
@@ -118578,11 +118583,12 @@ function getErrorMessage(error) {
|
|
|
118578
118583
|
return error.toString();
|
|
118579
118584
|
}
|
|
118580
118585
|
return "[unrepresentable error]";
|
|
118581
|
-
} catch (
|
|
118582
|
-
return `Error converting error to string: ${
|
|
118586
|
+
} catch (conversionError) {
|
|
118587
|
+
return `Error converting error to string: ${conversionError instanceof Error ? conversionError.message : "Unknown conversion error"}`;
|
|
118583
118588
|
}
|
|
118584
118589
|
}
|
|
118585
118590
|
|
|
118591
|
+
// src/utils/internal/error-handler/errorHandler.ts
|
|
118586
118592
|
class ErrorHandler {
|
|
118587
118593
|
static determineErrorCode(error) {
|
|
118588
118594
|
if (error instanceof McpError) {
|
|
@@ -118730,12 +118736,14 @@ class ErrorHandler {
|
|
|
118730
118736
|
static async tryCatch(fn, options) {
|
|
118731
118737
|
try {
|
|
118732
118738
|
return await Promise.resolve(fn());
|
|
118733
|
-
} catch (
|
|
118734
|
-
throw ErrorHandler.handleError(
|
|
118739
|
+
} catch (caughtError) {
|
|
118740
|
+
throw ErrorHandler.handleError(caughtError, {
|
|
118741
|
+
...options,
|
|
118742
|
+
rethrow: true
|
|
118743
|
+
});
|
|
118735
118744
|
}
|
|
118736
118745
|
}
|
|
118737
118746
|
}
|
|
118738
|
-
|
|
118739
118747
|
// src/utils/internal/runtime.ts
|
|
118740
118748
|
var safeHas = (key) => {
|
|
118741
118749
|
try {
|
|
@@ -118781,15 +118789,20 @@ var ATTR_MCP_TOOL_MEMORY_HEAP_USED_DELTA = "mcp.tool.memory_heap_used_bytes.delt
|
|
|
118781
118789
|
|
|
118782
118790
|
// src/utils/internal/performance.ts
|
|
118783
118791
|
var performanceNow = () => Date.now();
|
|
118792
|
+
async function loadPerfHooks() {
|
|
118793
|
+
return import("perf_hooks");
|
|
118794
|
+
}
|
|
118784
118795
|
async function initializePerformance_Hrt() {
|
|
118785
118796
|
const globalWithPerf = globalThis;
|
|
118786
118797
|
if (typeof globalWithPerf.performance?.now === "function") {
|
|
118787
|
-
|
|
118798
|
+
const perf = globalWithPerf.performance;
|
|
118799
|
+
performanceNow = () => perf?.now() ?? Date.now();
|
|
118788
118800
|
} else {
|
|
118789
118801
|
try {
|
|
118790
|
-
const { performance: nodePerformance } = await
|
|
118802
|
+
const { performance: nodePerformance } = await loadPerfHooks();
|
|
118791
118803
|
performanceNow = () => nodePerformance.now();
|
|
118792
118804
|
} catch (_e) {
|
|
118805
|
+
performanceNow = () => Date.now();
|
|
118793
118806
|
logger.warning("Could not import perf_hooks, falling back to Date.now() for performance timing.");
|
|
118794
118807
|
}
|
|
118795
118808
|
}
|
|
@@ -118801,7 +118814,8 @@ var toBytes = (payload) => {
|
|
|
118801
118814
|
try {
|
|
118802
118815
|
const json = JSON.stringify(payload);
|
|
118803
118816
|
if (typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function") {
|
|
118804
|
-
|
|
118817
|
+
const bytes = Buffer.byteLength(json, "utf8");
|
|
118818
|
+
return bytes;
|
|
118805
118819
|
}
|
|
118806
118820
|
if (typeof TextEncoder !== "undefined") {
|
|
118807
118821
|
return new TextEncoder().encode(json).length;
|
|
@@ -119228,9 +119242,12 @@ async function fetchWithTimeout(url, timeoutMs, context, options) {
|
|
|
119228
119242
|
}
|
|
119229
119243
|
}
|
|
119230
119244
|
|
|
119245
|
+
// src/index.ts
|
|
119246
|
+
var import_reflect_metadata3 = __toESM(require_Reflect(), 1);
|
|
119247
|
+
|
|
119231
119248
|
// src/container/index.ts
|
|
119232
119249
|
var import_reflect_metadata = __toESM(require_Reflect(), 1);
|
|
119233
|
-
var
|
|
119250
|
+
var import_tsyringe15 = __toESM(require_cjs3(), 1);
|
|
119234
119251
|
|
|
119235
119252
|
// src/container/registrations/core.ts
|
|
119236
119253
|
var import_tsyringe6 = __toESM(require_cjs3(), 1);
|
|
@@ -125473,7 +125490,7 @@ var registerCoreServices = () => {
|
|
|
125473
125490
|
};
|
|
125474
125491
|
|
|
125475
125492
|
// src/container/registrations/mcp.ts
|
|
125476
|
-
var
|
|
125493
|
+
var import_tsyringe14 = __toESM(require_cjs3(), 1);
|
|
125477
125494
|
|
|
125478
125495
|
// src/mcp-server/resources/resource-registration.ts
|
|
125479
125496
|
var import_tsyringe7 = __toESM(require_cjs3(), 1);
|
|
@@ -128884,7 +128901,7 @@ var registerResources = (container3) => {
|
|
|
128884
128901
|
};
|
|
128885
128902
|
|
|
128886
128903
|
// src/mcp-server/server.ts
|
|
128887
|
-
var
|
|
128904
|
+
var import_tsyringe9 = __toESM(require_cjs3(), 1);
|
|
128888
128905
|
|
|
128889
128906
|
// src/mcp-server/tools/tool-registration.ts
|
|
128890
128907
|
var import_tsyringe8 = __toESM(require_cjs3(), 1);
|
|
@@ -129140,7 +129157,7 @@ var imageTestTool = {
|
|
|
129140
129157
|
responseFormatter: responseFormatter3
|
|
129141
129158
|
};
|
|
129142
129159
|
|
|
129143
|
-
// src/mcp-server/tools/definitions/
|
|
129160
|
+
// src/mcp-server/tools/definitions/template-madlibs-elicitation.tool.ts
|
|
129144
129161
|
var TOOL_NAME4 = "template_madlibs_elicitation";
|
|
129145
129162
|
var TOOL_TITLE4 = "Mad Libs Elicitation Game";
|
|
129146
129163
|
var TOOL_DESCRIPTION4 = "Plays a game of Mad Libs. If any parts of speech (noun, verb, adjective) are missing, it will use elicitation to ask the user for them.";
|
|
@@ -129178,7 +129195,10 @@ async function elicitAndValidate(partOfSpeech, sdkContext) {
|
|
|
129178
129195
|
return validation.data;
|
|
129179
129196
|
}
|
|
129180
129197
|
async function madlibsToolLogic(input, appContext, sdkContext) {
|
|
129181
|
-
logger.debug("Processing Mad Libs logic.", {
|
|
129198
|
+
logger.debug("Processing Mad Libs logic.", {
|
|
129199
|
+
...appContext,
|
|
129200
|
+
toolInput: input
|
|
129201
|
+
});
|
|
129182
129202
|
const noun = input.noun ?? await elicitAndValidate("noun", sdkContext);
|
|
129183
129203
|
const verb = input.verb ?? await elicitAndValidate("verb", sdkContext);
|
|
129184
129204
|
const adjective = input.adjective ?? await elicitAndValidate("adjective", sdkContext);
|
|
@@ -129333,6 +129353,50 @@ var registerTools = (container3) => {
|
|
|
129333
129353
|
}
|
|
129334
129354
|
};
|
|
129335
129355
|
|
|
129356
|
+
// src/mcp-server/server.ts
|
|
129357
|
+
async function createMcpServerInstance() {
|
|
129358
|
+
const context = requestContextService.createRequestContext({
|
|
129359
|
+
operation: "createMcpServerInstance"
|
|
129360
|
+
});
|
|
129361
|
+
logger.info("Initializing MCP server instance", context);
|
|
129362
|
+
requestContextService.configure({
|
|
129363
|
+
appName: config.mcpServerName,
|
|
129364
|
+
appVersion: config.mcpServerVersion,
|
|
129365
|
+
environment: config.environment
|
|
129366
|
+
});
|
|
129367
|
+
const server = new McpServer({
|
|
129368
|
+
name: config.mcpServerName,
|
|
129369
|
+
version: config.mcpServerVersion,
|
|
129370
|
+
description: config.mcpServerDescription
|
|
129371
|
+
}, {
|
|
129372
|
+
capabilities: {
|
|
129373
|
+
logging: {},
|
|
129374
|
+
resources: { listChanged: true },
|
|
129375
|
+
tools: { listChanged: true },
|
|
129376
|
+
elicitation: {}
|
|
129377
|
+
}
|
|
129378
|
+
});
|
|
129379
|
+
try {
|
|
129380
|
+
logger.debug("Registering resources and tools via registries...", context);
|
|
129381
|
+
const toolRegistry = import_tsyringe9.container.resolve(ToolRegistry);
|
|
129382
|
+
await toolRegistry.registerAll(server);
|
|
129383
|
+
const resourceRegistry = import_tsyringe9.container.resolve(ResourceRegistry);
|
|
129384
|
+
await resourceRegistry.registerAll(server);
|
|
129385
|
+
logger.info("Resources and tools registered successfully", context);
|
|
129386
|
+
} catch (err) {
|
|
129387
|
+
logger.error("Failed to register resources/tools", {
|
|
129388
|
+
...context,
|
|
129389
|
+
error: err instanceof Error ? err.message : String(err),
|
|
129390
|
+
stack: err instanceof Error ? err.stack : undefined
|
|
129391
|
+
});
|
|
129392
|
+
throw err;
|
|
129393
|
+
}
|
|
129394
|
+
return server;
|
|
129395
|
+
}
|
|
129396
|
+
|
|
129397
|
+
// src/mcp-server/transports/manager.ts
|
|
129398
|
+
var import_tsyringe13 = __toESM(require_cjs3(), 1);
|
|
129399
|
+
|
|
129336
129400
|
// node_modules/hono/dist/http-exception.js
|
|
129337
129401
|
var HTTPException = class extends Error {
|
|
129338
129402
|
res;
|
|
@@ -131995,7 +132059,7 @@ var cors = (options) => {
|
|
|
131995
132059
|
import http from "http";
|
|
131996
132060
|
import { randomUUID } from "node:crypto";
|
|
131997
132061
|
// src/mcp-server/transports/auth/authFactory.ts
|
|
131998
|
-
var
|
|
132062
|
+
var import_tsyringe12 = __toESM(require_cjs3(), 1);
|
|
131999
132063
|
|
|
132000
132064
|
// node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
132001
132065
|
var encoder = new TextEncoder;
|
|
@@ -133513,7 +133577,7 @@ function createRemoteJWKSet(url, options) {
|
|
|
133513
133577
|
return remoteJWKSet;
|
|
133514
133578
|
}
|
|
133515
133579
|
// src/mcp-server/transports/auth/strategies/jwtStrategy.ts
|
|
133516
|
-
var
|
|
133580
|
+
var import_tsyringe10 = __toESM(require_cjs3(), 1);
|
|
133517
133581
|
class JwtStrategy {
|
|
133518
133582
|
config;
|
|
133519
133583
|
logger;
|
|
@@ -133616,9 +133680,9 @@ class JwtStrategy {
|
|
|
133616
133680
|
}
|
|
133617
133681
|
}
|
|
133618
133682
|
JwtStrategy = __legacyDecorateClassTS([
|
|
133619
|
-
|
|
133620
|
-
__legacyDecorateParamTS(0,
|
|
133621
|
-
__legacyDecorateParamTS(1,
|
|
133683
|
+
import_tsyringe10.injectable(),
|
|
133684
|
+
__legacyDecorateParamTS(0, import_tsyringe10.inject(AppConfig)),
|
|
133685
|
+
__legacyDecorateParamTS(1, import_tsyringe10.inject(Logger2)),
|
|
133622
133686
|
__legacyMetadataTS("design:paramtypes", [
|
|
133623
133687
|
Object,
|
|
133624
133688
|
Object
|
|
@@ -133626,7 +133690,7 @@ JwtStrategy = __legacyDecorateClassTS([
|
|
|
133626
133690
|
], JwtStrategy);
|
|
133627
133691
|
|
|
133628
133692
|
// src/mcp-server/transports/auth/strategies/oauthStrategy.ts
|
|
133629
|
-
var
|
|
133693
|
+
var import_tsyringe11 = __toESM(require_cjs3(), 1);
|
|
133630
133694
|
class OauthStrategy {
|
|
133631
133695
|
config;
|
|
133632
133696
|
logger;
|
|
@@ -133723,9 +133787,9 @@ class OauthStrategy {
|
|
|
133723
133787
|
}
|
|
133724
133788
|
}
|
|
133725
133789
|
OauthStrategy = __legacyDecorateClassTS([
|
|
133726
|
-
|
|
133727
|
-
__legacyDecorateParamTS(0,
|
|
133728
|
-
__legacyDecorateParamTS(1,
|
|
133790
|
+
import_tsyringe11.injectable(),
|
|
133791
|
+
__legacyDecorateParamTS(0, import_tsyringe11.inject(AppConfig)),
|
|
133792
|
+
__legacyDecorateParamTS(1, import_tsyringe11.inject(Logger2)),
|
|
133729
133793
|
__legacyMetadataTS("design:paramtypes", [
|
|
133730
133794
|
Object,
|
|
133731
133795
|
Object
|
|
@@ -133733,8 +133797,8 @@ OauthStrategy = __legacyDecorateClassTS([
|
|
|
133733
133797
|
], OauthStrategy);
|
|
133734
133798
|
|
|
133735
133799
|
// src/mcp-server/transports/auth/authFactory.ts
|
|
133736
|
-
|
|
133737
|
-
|
|
133800
|
+
import_tsyringe12.container.register(JwtStrategy, { useClass: JwtStrategy });
|
|
133801
|
+
import_tsyringe12.container.register(OauthStrategy, { useClass: OauthStrategy });
|
|
133738
133802
|
function createAuthStrategy() {
|
|
133739
133803
|
const context = requestContextService.createRequestContext({
|
|
133740
133804
|
operation: "createAuthStrategy",
|
|
@@ -133744,10 +133808,10 @@ function createAuthStrategy() {
|
|
|
133744
133808
|
switch (config.mcpAuthMode) {
|
|
133745
133809
|
case "jwt":
|
|
133746
133810
|
logger.debug("Resolving JWT strategy from container.", context);
|
|
133747
|
-
return
|
|
133811
|
+
return import_tsyringe12.container.resolve(JwtStrategy);
|
|
133748
133812
|
case "oauth":
|
|
133749
133813
|
logger.debug("Resolving OAuth strategy from container.", context);
|
|
133750
|
-
return
|
|
133814
|
+
return import_tsyringe12.container.resolve(OauthStrategy);
|
|
133751
133815
|
case "none":
|
|
133752
133816
|
logger.info("Authentication is disabled ('none' mode).", context);
|
|
133753
133817
|
return null;
|
|
@@ -133756,6 +133820,53 @@ function createAuthStrategy() {
|
|
|
133756
133820
|
throw new Error(`Unknown authentication mode: ${String(config.mcpAuthMode)}`);
|
|
133757
133821
|
}
|
|
133758
133822
|
}
|
|
133823
|
+
// src/mcp-server/transports/auth/authMiddleware.ts
|
|
133824
|
+
function createAuthMiddleware(strategy) {
|
|
133825
|
+
return async function authMiddleware(c, next) {
|
|
133826
|
+
const context = requestContextService.createRequestContext({
|
|
133827
|
+
operation: "authMiddleware",
|
|
133828
|
+
additionalContext: {
|
|
133829
|
+
method: c.req.method,
|
|
133830
|
+
path: c.req.path
|
|
133831
|
+
}
|
|
133832
|
+
});
|
|
133833
|
+
logger.debug("Initiating authentication check.", context);
|
|
133834
|
+
const authHeader = c.req.header("Authorization");
|
|
133835
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
133836
|
+
logger.warning("Authorization header missing or invalid.", context);
|
|
133837
|
+
throw new McpError(-32006 /* Unauthorized */, "Missing or invalid Authorization header. Bearer scheme required.", context);
|
|
133838
|
+
}
|
|
133839
|
+
const token = authHeader.substring(7);
|
|
133840
|
+
if (!token) {
|
|
133841
|
+
logger.warning("Bearer token is missing from Authorization header.", context);
|
|
133842
|
+
throw new McpError(-32006 /* Unauthorized */, "Authentication token is missing.", context);
|
|
133843
|
+
}
|
|
133844
|
+
logger.debug("Extracted Bearer token, proceeding to verification.", context);
|
|
133845
|
+
try {
|
|
133846
|
+
const authInfo = await strategy.verify(token);
|
|
133847
|
+
const authLogContext = {
|
|
133848
|
+
...context,
|
|
133849
|
+
...authInfo.tenantId ? { tenantId: authInfo.tenantId } : {},
|
|
133850
|
+
clientId: authInfo.clientId,
|
|
133851
|
+
subject: authInfo.subject,
|
|
133852
|
+
scopes: authInfo.scopes
|
|
133853
|
+
};
|
|
133854
|
+
logger.info("Authentication successful. Auth context populated.", authLogContext);
|
|
133855
|
+
await authContext.run({ authInfo }, next);
|
|
133856
|
+
} catch (error2) {
|
|
133857
|
+
logger.warning("Authentication verification failed.", {
|
|
133858
|
+
...context,
|
|
133859
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
133860
|
+
});
|
|
133861
|
+
throw ErrorHandler.handleError(error2, {
|
|
133862
|
+
operation: "authMiddlewareVerification",
|
|
133863
|
+
context,
|
|
133864
|
+
rethrow: true,
|
|
133865
|
+
errorCode: -32006 /* Unauthorized */
|
|
133866
|
+
});
|
|
133867
|
+
}
|
|
133868
|
+
};
|
|
133869
|
+
}
|
|
133759
133870
|
// src/mcp-server/transports/http/httpErrorHandler.ts
|
|
133760
133871
|
var httpErrorHandler = async (err, c) => {
|
|
133761
133872
|
const context = requestContextService.createRequestContext({
|
|
@@ -133841,6 +133952,13 @@ var httpErrorHandler = async (err, c) => {
|
|
|
133841
133952
|
};
|
|
133842
133953
|
|
|
133843
133954
|
// src/mcp-server/transports/http/httpTransport.ts
|
|
133955
|
+
class McpSessionTransport extends StreamableHTTPTransport {
|
|
133956
|
+
sessionId;
|
|
133957
|
+
constructor(sessionId) {
|
|
133958
|
+
super();
|
|
133959
|
+
this.sessionId = sessionId;
|
|
133960
|
+
}
|
|
133961
|
+
}
|
|
133844
133962
|
function createHttpApp(mcpServer, parentContext) {
|
|
133845
133963
|
const app = new Hono2;
|
|
133846
133964
|
const transportContext = {
|
|
@@ -133875,14 +133993,22 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
133875
133993
|
}
|
|
133876
133994
|
});
|
|
133877
133995
|
});
|
|
133996
|
+
const authStrategy = createAuthStrategy();
|
|
133997
|
+
if (authStrategy) {
|
|
133998
|
+
const authMiddleware = createAuthMiddleware(authStrategy);
|
|
133999
|
+
app.use(config.mcpHttpEndpointPath, authMiddleware);
|
|
134000
|
+
logger.info("Authentication middleware enabled for MCP endpoint.", transportContext);
|
|
134001
|
+
} else {
|
|
134002
|
+
logger.info("Authentication is disabled; MCP endpoint is unprotected.", transportContext);
|
|
134003
|
+
}
|
|
133878
134004
|
app.all(config.mcpHttpEndpointPath, async (c) => {
|
|
133879
134005
|
logger.debug("Handling MCP request.", {
|
|
133880
134006
|
...transportContext,
|
|
133881
134007
|
path: c.req.path,
|
|
133882
134008
|
method: c.req.method
|
|
133883
134009
|
});
|
|
133884
|
-
const
|
|
133885
|
-
transport
|
|
134010
|
+
const sessionId = c.req.header("mcp-session-id") ?? randomUUID();
|
|
134011
|
+
const transport = new McpSessionTransport(sessionId);
|
|
133886
134012
|
const handleRpc = async () => {
|
|
133887
134013
|
await mcpServer.connect(transport);
|
|
133888
134014
|
const response = await transport.handleRequest(c);
|
|
@@ -133891,30 +134017,12 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
133891
134017
|
}
|
|
133892
134018
|
return c.body(null, 204);
|
|
133893
134019
|
};
|
|
133894
|
-
const protectRpc = config.mcpAuthMode !== "none";
|
|
133895
134020
|
try {
|
|
133896
|
-
|
|
133897
|
-
|
|
133898
|
-
|
|
133899
|
-
const authHeader = c.req.header("Authorization");
|
|
133900
|
-
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
133901
|
-
logger.warning("Authorization header missing or invalid (HTTP JSON-RPC).", {
|
|
133902
|
-
...transportContext,
|
|
133903
|
-
method: c.req.method,
|
|
133904
|
-
path: c.req.path
|
|
133905
|
-
});
|
|
133906
|
-
throw new McpError(-32006 /* Unauthorized */, "Missing or invalid Authorization header. Bearer scheme required.", transportContext);
|
|
133907
|
-
}
|
|
133908
|
-
const strategy = createAuthStrategy();
|
|
133909
|
-
if (!strategy) {
|
|
133910
|
-
logger.warning("Auth mode indicates protection, but no strategy was created. Proceeding unauthenticated.", transportContext);
|
|
133911
|
-
return await handleRpc();
|
|
134021
|
+
const store = authContext.getStore();
|
|
134022
|
+
if (store) {
|
|
134023
|
+
return await authContext.run(store, handleRpc);
|
|
133912
134024
|
}
|
|
133913
|
-
|
|
133914
|
-
const authInfo = await strategy.verify(token);
|
|
133915
|
-
return await authContext.run({ authInfo }, async () => {
|
|
133916
|
-
return await handleRpc();
|
|
133917
|
-
});
|
|
134025
|
+
return await handleRpc();
|
|
133918
134026
|
} catch (err) {
|
|
133919
134027
|
await transport.close?.();
|
|
133920
134028
|
throw err instanceof Error ? err : new Error(String(err));
|
|
@@ -133985,7 +134093,25 @@ async function startHttpTransport(mcpServer, parentContext) {
|
|
|
133985
134093
|
const app = createHttpApp(mcpServer, transportContext);
|
|
133986
134094
|
const server = await startHttpServerWithRetry(app, config.mcpHttpPort, config.mcpHttpHost, config.mcpHttpMaxPortRetries, transportContext);
|
|
133987
134095
|
logger.info("HTTP transport started successfully.", transportContext);
|
|
133988
|
-
return
|
|
134096
|
+
return server;
|
|
134097
|
+
}
|
|
134098
|
+
async function stopHttpTransport(server, parentContext) {
|
|
134099
|
+
const operationContext = {
|
|
134100
|
+
...parentContext,
|
|
134101
|
+
operation: "stopHttpTransport",
|
|
134102
|
+
transportType: "Http"
|
|
134103
|
+
};
|
|
134104
|
+
logger.info("Attempting to stop http transport...", operationContext);
|
|
134105
|
+
return new Promise((resolve, reject) => {
|
|
134106
|
+
server.close((err) => {
|
|
134107
|
+
if (err) {
|
|
134108
|
+
logger.error("Error closing HTTP server.", err, operationContext);
|
|
134109
|
+
return reject(err);
|
|
134110
|
+
}
|
|
134111
|
+
logger.info("HTTP server closed successfully.", operationContext);
|
|
134112
|
+
resolve();
|
|
134113
|
+
});
|
|
134114
|
+
});
|
|
133989
134115
|
}
|
|
133990
134116
|
|
|
133991
134117
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
@@ -134102,6 +134228,7 @@ async function startStdioTransport(server, parentContext) {
|
|
|
134102
134228
|
(MCP Spec: 2025-03-26 Stdio Transport)
|
|
134103
134229
|
`);
|
|
134104
134230
|
}
|
|
134231
|
+
return server;
|
|
134105
134232
|
} catch (err) {
|
|
134106
134233
|
throw ErrorHandler.handleError(err, {
|
|
134107
134234
|
operation: "connectStdioTransport",
|
|
@@ -134111,100 +134238,89 @@ async function startStdioTransport(server, parentContext) {
|
|
|
134111
134238
|
});
|
|
134112
134239
|
}
|
|
134113
134240
|
}
|
|
134114
|
-
|
|
134115
|
-
|
|
134116
|
-
|
|
134117
|
-
operation: "
|
|
134118
|
-
|
|
134119
|
-
|
|
134120
|
-
|
|
134121
|
-
|
|
134122
|
-
|
|
134123
|
-
|
|
134124
|
-
});
|
|
134125
|
-
const server = new McpServer({
|
|
134126
|
-
name: config.mcpServerName,
|
|
134127
|
-
version: config.mcpServerVersion,
|
|
134128
|
-
description: config.mcpServerDescription
|
|
134129
|
-
}, {
|
|
134130
|
-
capabilities: {
|
|
134131
|
-
logging: {},
|
|
134132
|
-
resources: { listChanged: true },
|
|
134133
|
-
tools: { listChanged: true },
|
|
134134
|
-
elicitation: {}
|
|
134135
|
-
}
|
|
134136
|
-
});
|
|
134137
|
-
try {
|
|
134138
|
-
logger.debug("Registering resources and tools via registries...", context);
|
|
134139
|
-
const toolRegistry = import_tsyringe12.container.resolve(ToolRegistry);
|
|
134140
|
-
await toolRegistry.registerAll(server);
|
|
134141
|
-
const resourceRegistry = import_tsyringe12.container.resolve(ResourceRegistry);
|
|
134142
|
-
await resourceRegistry.registerAll(server);
|
|
134143
|
-
logger.info("Resources and tools registered successfully", context);
|
|
134144
|
-
} catch (err) {
|
|
134145
|
-
logger.error("Failed to register resources/tools", {
|
|
134146
|
-
...context,
|
|
134147
|
-
error: err instanceof Error ? err.message : String(err),
|
|
134148
|
-
stack: err instanceof Error ? err.stack : undefined
|
|
134149
|
-
});
|
|
134150
|
-
throw err;
|
|
134241
|
+
async function stopStdioTransport(server, parentContext) {
|
|
134242
|
+
const operationContext = {
|
|
134243
|
+
...parentContext,
|
|
134244
|
+
operation: "stopStdioTransport",
|
|
134245
|
+
transportType: "Stdio"
|
|
134246
|
+
};
|
|
134247
|
+
logger.info("Attempting to stop stdio transport...", operationContext);
|
|
134248
|
+
if (server) {
|
|
134249
|
+
await server.close();
|
|
134250
|
+
logger.info("Stdio transport stopped successfully.", operationContext);
|
|
134151
134251
|
}
|
|
134152
|
-
return server;
|
|
134153
134252
|
}
|
|
134154
|
-
|
|
134155
|
-
|
|
134156
|
-
|
|
134157
|
-
|
|
134158
|
-
|
|
134159
|
-
|
|
134160
|
-
|
|
134161
|
-
|
|
134162
|
-
|
|
134163
|
-
|
|
134164
|
-
|
|
134165
|
-
}
|
|
134166
|
-
|
|
134167
|
-
const
|
|
134168
|
-
|
|
134169
|
-
|
|
134170
|
-
|
|
134171
|
-
|
|
134172
|
-
|
|
134173
|
-
|
|
134174
|
-
|
|
134175
|
-
|
|
134176
|
-
|
|
134177
|
-
|
|
134178
|
-
|
|
134179
|
-
|
|
134180
|
-
|
|
134181
|
-
|
|
134182
|
-
|
|
134183
|
-
}
|
|
134184
|
-
|
|
134185
|
-
|
|
134186
|
-
|
|
134187
|
-
|
|
134188
|
-
});
|
|
134189
|
-
ErrorHandler.handleError(err, {
|
|
134190
|
-
...context,
|
|
134191
|
-
operation: "initializeAndStartServer_Catch",
|
|
134192
|
-
critical: true
|
|
134253
|
+
|
|
134254
|
+
// src/mcp-server/transports/manager.ts
|
|
134255
|
+
class TransportManager {
|
|
134256
|
+
config;
|
|
134257
|
+
logger;
|
|
134258
|
+
createMcpServer;
|
|
134259
|
+
serverInstance = null;
|
|
134260
|
+
constructor(config2, logger2, createMcpServer) {
|
|
134261
|
+
this.config = config2;
|
|
134262
|
+
this.logger = logger2;
|
|
134263
|
+
this.createMcpServer = createMcpServer;
|
|
134264
|
+
}
|
|
134265
|
+
async start() {
|
|
134266
|
+
const context = requestContextService.createRequestContext({
|
|
134267
|
+
operation: "TransportManager.start",
|
|
134268
|
+
transport: this.config.mcpTransportType
|
|
134269
|
+
});
|
|
134270
|
+
this.logger.info(`Starting transport: ${this.config.mcpTransportType}`, context);
|
|
134271
|
+
const mcpServer = await this.createMcpServer();
|
|
134272
|
+
if (this.config.mcpTransportType === "http") {
|
|
134273
|
+
this.serverInstance = await startHttpTransport(mcpServer, context);
|
|
134274
|
+
} else if (this.config.mcpTransportType === "stdio") {
|
|
134275
|
+
this.serverInstance = await startStdioTransport(mcpServer, context);
|
|
134276
|
+
} else {
|
|
134277
|
+
const transportType = String(this.config.mcpTransportType);
|
|
134278
|
+
const error2 = new Error(`Unsupported transport type: ${transportType}`);
|
|
134279
|
+
this.logger.crit(error2.message, context);
|
|
134280
|
+
throw error2;
|
|
134281
|
+
}
|
|
134282
|
+
}
|
|
134283
|
+
async stop(signal) {
|
|
134284
|
+
const context = requestContextService.createRequestContext({
|
|
134285
|
+
operation: "TransportManager.stop",
|
|
134286
|
+
signal
|
|
134193
134287
|
});
|
|
134194
|
-
|
|
134195
|
-
|
|
134288
|
+
if (!this.serverInstance) {
|
|
134289
|
+
this.logger.warning("Stop called but no active server instance found.", context);
|
|
134290
|
+
return;
|
|
134291
|
+
}
|
|
134292
|
+
if (this.config.mcpTransportType === "http") {
|
|
134293
|
+
await stopHttpTransport(this.serverInstance, context);
|
|
134294
|
+
} else if (this.config.mcpTransportType === "stdio") {
|
|
134295
|
+
await stopStdioTransport(this.serverInstance, context);
|
|
134296
|
+
}
|
|
134297
|
+
}
|
|
134298
|
+
getServer() {
|
|
134299
|
+
return this.serverInstance;
|
|
134196
134300
|
}
|
|
134197
134301
|
}
|
|
134302
|
+
TransportManager = __legacyDecorateClassTS([
|
|
134303
|
+
import_tsyringe13.injectable(),
|
|
134304
|
+
__legacyDecorateParamTS(0, import_tsyringe13.inject(AppConfig)),
|
|
134305
|
+
__legacyDecorateParamTS(1, import_tsyringe13.inject(Logger2)),
|
|
134306
|
+
__legacyDecorateParamTS(2, import_tsyringe13.inject(CreateMcpServerInstance)),
|
|
134307
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
134308
|
+
typeof AppConfigType === "undefined" ? Object : AppConfigType,
|
|
134309
|
+
Object,
|
|
134310
|
+
Function
|
|
134311
|
+
])
|
|
134312
|
+
], TransportManager);
|
|
134198
134313
|
|
|
134199
134314
|
// src/container/registrations/mcp.ts
|
|
134200
134315
|
var registerMcpServices = () => {
|
|
134201
|
-
|
|
134202
|
-
|
|
134203
|
-
registerTools(
|
|
134204
|
-
registerResources(
|
|
134205
|
-
|
|
134316
|
+
import_tsyringe14.container.registerSingleton(ToolRegistry);
|
|
134317
|
+
import_tsyringe14.container.registerSingleton(ResourceRegistry);
|
|
134318
|
+
registerTools(import_tsyringe14.container);
|
|
134319
|
+
registerResources(import_tsyringe14.container);
|
|
134320
|
+
import_tsyringe14.container.register(CreateMcpServerInstance, {
|
|
134206
134321
|
useValue: createMcpServerInstance
|
|
134207
134322
|
});
|
|
134323
|
+
import_tsyringe14.container.registerSingleton(TransportManagerToken, TransportManager);
|
|
134208
134324
|
logger.info("MCP services and factories registered with the DI container.");
|
|
134209
134325
|
};
|
|
134210
134326
|
|
|
@@ -134218,12 +134334,11 @@ function composeContainer() {
|
|
|
134218
134334
|
registerMcpServices();
|
|
134219
134335
|
isContainerComposed = true;
|
|
134220
134336
|
}
|
|
134221
|
-
var container_default =
|
|
134337
|
+
var container_default = import_tsyringe15.container;
|
|
134222
134338
|
|
|
134223
134339
|
// src/index.ts
|
|
134224
134340
|
var config2;
|
|
134225
|
-
var
|
|
134226
|
-
var actualHttpServer;
|
|
134341
|
+
var transportManager;
|
|
134227
134342
|
var isShuttingDown = false;
|
|
134228
134343
|
var shutdown = async (signal) => {
|
|
134229
134344
|
if (isShuttingDown) {
|
|
@@ -134236,25 +134351,9 @@ var shutdown = async (signal) => {
|
|
|
134236
134351
|
});
|
|
134237
134352
|
logger.info(`Received ${signal}. Initiating graceful shutdown...`, shutdownContext);
|
|
134238
134353
|
try {
|
|
134239
|
-
|
|
134240
|
-
|
|
134241
|
-
if (transportType === "stdio" && mcpStdioServer) {
|
|
134242
|
-
logger.info("Attempting to close main MCP server (STDIO)...", shutdownContext);
|
|
134243
|
-
closePromise = mcpStdioServer.close();
|
|
134244
|
-
} else if (transportType === "http" && actualHttpServer) {
|
|
134245
|
-
logger.info("Attempting to close HTTP server...", shutdownContext);
|
|
134246
|
-
closePromise = new Promise((resolve, reject) => {
|
|
134247
|
-
actualHttpServer.close((err) => {
|
|
134248
|
-
if (err) {
|
|
134249
|
-
logger.error("Error closing HTTP server.", err, shutdownContext);
|
|
134250
|
-
return reject(err);
|
|
134251
|
-
}
|
|
134252
|
-
logger.info("HTTP server closed successfully.", shutdownContext);
|
|
134253
|
-
resolve();
|
|
134254
|
-
});
|
|
134255
|
-
});
|
|
134354
|
+
if (transportManager) {
|
|
134355
|
+
await transportManager.stop(signal);
|
|
134256
134356
|
}
|
|
134257
|
-
await closePromise;
|
|
134258
134357
|
logger.info("Graceful shutdown completed successfully. Exiting.", shutdownContext);
|
|
134259
134358
|
await shutdownOpenTelemetry();
|
|
134260
134359
|
await logger.close();
|
|
@@ -134268,8 +134367,16 @@ var shutdown = async (signal) => {
|
|
|
134268
134367
|
}
|
|
134269
134368
|
};
|
|
134270
134369
|
var start = async () => {
|
|
134271
|
-
|
|
134272
|
-
|
|
134370
|
+
try {
|
|
134371
|
+
composeContainer();
|
|
134372
|
+
config2 = container_default.resolve(AppConfig);
|
|
134373
|
+
} catch (_error) {
|
|
134374
|
+
if (process.stdout.isTTY) {
|
|
134375
|
+
console.error("Halting due to critical configuration error.");
|
|
134376
|
+
}
|
|
134377
|
+
await shutdownOpenTelemetry();
|
|
134378
|
+
process.exit(1);
|
|
134379
|
+
}
|
|
134273
134380
|
await initializePerformance_Hrt();
|
|
134274
134381
|
const validMcpLogLevels = [
|
|
134275
134382
|
"debug",
|
|
@@ -134293,21 +134400,16 @@ var start = async () => {
|
|
|
134293
134400
|
await logger.initialize(validatedMcpLogLevel);
|
|
134294
134401
|
logger.info(`Logger initialized. Effective MCP logging level: ${validatedMcpLogLevel}.`, requestContextService.createRequestContext({ operation: "LoggerInit" }));
|
|
134295
134402
|
logger.info(`Storage service initialized with provider: ${config2.storage.providerType}`, requestContextService.createRequestContext({ operation: "StorageInit" }));
|
|
134296
|
-
|
|
134403
|
+
transportManager = container_default.resolve(TransportManagerToken);
|
|
134297
134404
|
const startupContext = requestContextService.createRequestContext({
|
|
134298
|
-
operation:
|
|
134405
|
+
operation: "ServerStartup",
|
|
134299
134406
|
applicationName: config2.mcpServerName,
|
|
134300
134407
|
applicationVersion: config2.mcpServerVersion,
|
|
134301
134408
|
nodeEnvironment: config2.environment
|
|
134302
134409
|
});
|
|
134303
|
-
logger.info(`Starting ${config2.mcpServerName} (
|
|
134410
|
+
logger.info(`Starting ${config2.mcpServerName} (v${config2.mcpServerVersion})...`, startupContext);
|
|
134304
134411
|
try {
|
|
134305
|
-
|
|
134306
|
-
if (transportType === "http") {
|
|
134307
|
-
actualHttpServer = server;
|
|
134308
|
-
} else if (transportType === "stdio") {
|
|
134309
|
-
mcpStdioServer = server;
|
|
134310
|
-
}
|
|
134412
|
+
await transportManager.start();
|
|
134311
134413
|
logger.info(`${config2.mcpServerName} is now running and ready.`, startupContext);
|
|
134312
134414
|
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
134313
134415
|
process.on("SIGINT", () => void shutdown("SIGINT"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-ts-template",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"mcpName": "io.github.cyanheads/mcp-ts-template",
|
|
5
5
|
"description": "The definitive, production-grade template for building powerful and scalable Model Context Protocol (MCP) servers with TypeScript, featuring built-in observability (OpenTelemetry), declarative tooling, robust error handling, and a modular, DI-driven architecture.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"inspector": "bunx mcp-inspector --config mcp.json --server mcp-ts-template",
|
|
57
57
|
"db:duckdb-example": "MCP_LOG_LEVEL=debug tsc && node dist/storage/duckdbExample.js",
|
|
58
58
|
"test": "bun test --config vitest.config.ts",
|
|
59
|
-
"test:coverage": "bun test --coverage
|
|
59
|
+
"test:coverage": "bun test --coverage",
|
|
60
60
|
"audit": "bun audit",
|
|
61
61
|
"audit:fix": "bun audit --fix",
|
|
62
62
|
"publish-mcp": "bun scripts/validate-mcp-publish-schema.ts"
|