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.
Files changed (3) hide show
  1. package/README.md +39 -34
  2. package/dist/index.js +336 -234
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  <div align="center">
7
7
 
8
- [![Version](https://img.shields.io/badge/Version-2.2.0-blue.svg?style=flat-square)](./CHANGELOG.md) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2025--06--18-8A2BE2.svg?style=flat-square)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-06-18/changelog.mdx) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.18.2-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Status](https://img.shields.io/badge/Status-Stable-brightgreen.svg?style=flat-square)](https://github.com/cyanheads/mcp-ts-template/issues) [![TypeScript](https://img.shields.io/badge/TypeScript-^5.9-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.2.22-blueviolet.svg?style=flat-square)](https://bun.sh/) [![Code Coverage](https://img.shields.io/badge/Coverage-83.55%25-brightgreen.svg?style=flat-square)](./coverage/lcov-report/)
8
+ [![Version](https://img.shields.io/badge/Version-2.2.2-blue.svg?style=flat-square)](./CHANGELOG.md) [![MCP Spec](https://img.shields.io/badge/MCP%20Spec-2025--06--18-8A2BE2.svg?style=flat-square)](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-06-18/changelog.mdx) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^1.18.2-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Status](https://img.shields.io/badge/Status-Stable-brightgreen.svg?style=flat-square)](https://github.com/cyanheads/mcp-ts-template/issues) [![TypeScript](https://img.shields.io/badge/TypeScript-^5.9-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.2.22-blueviolet.svg?style=flat-square)](https://bun.sh/) [![Code Coverage](https://img.shields.io/badge/Coverage-87.86%25-brightgreen.svg?style=flat-square)](./coverage/lcov-report/)
9
9
 
10
10
  </div>
11
11
 
@@ -30,18 +30,20 @@
30
30
 
31
31
  ### Installation
32
32
 
33
- 1.
34
- **Clone the repository:**
33
+ 1. **Clone the repository:**
34
+
35
35
  ```sh
36
36
  git clone https://github.com/cyanheads/mcp-ts-template.git
37
37
  ```
38
- 2.
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
- 3.
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 { SdkContext, ToolDefinition } from '@/mcp-server/tools/utils/toolDefinition.js';
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 | Description | Default |
184
- | :--- | :--- | :--- |
185
- | `MCP_TRANSPORT_TYPE` | The transport to use: `stdio` or `http`. | `http` |
186
- | `MCP_HTTP_PORT` | The port for the HTTP server. | `3010` |
187
- | `MCP_AUTH_MODE` | Authentication mode: `none`, `jwt`, or `oauth`. | `none` |
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` | Set to `true` to enable OpenTelemetry. | `false` |
190
- | `LOG_LEVEL` | The minimum level for logging. | `info` |
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
- **Build the Worker bundle**:
237
+ 1. **Build the Worker bundle**:
238
+
234
239
  ```sh
235
240
  bun build:worker
236
241
  ```
237
- 2.
238
- **Run locally with Wrangler**:
242
+
243
+ 2. **Run locally with Wrangler**:
244
+
239
245
  ```sh
240
246
  bun deploy:dev
241
247
  ```
242
- 3.
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 | Purpose & Contents |
252
- | :--- | :--- |
253
- | `src/mcp-server/tools/definitions` | Your tool definitions (`*.tool.ts`). This is where you add new capabilities. |
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` | Implementations for HTTP and STDIO transports, including auth middleware. |
256
- | `src/storage` | The `StorageService` abstraction and all storage provider implementations. |
257
- | `src/services` | Integrations with external services (e.g., the default OpenRouter LLM provider). |
258
- | `src/container` | Dependency injection container registrations and tokens. |
259
- | `src/utils` | Core utilities for logging, error handling, performance, security, and telemetry. |
260
- | `src/config` | Environment variable parsing and validation with Zod. |
261
- | `tests/` | Unit and integration tests, mirroring the `src/` directory structure. |
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.8",
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 --config vitest.config.ts",
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
- process.exit(1);
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/errorHandler.ts
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 (e) {
118582
- return `Error converting error to string: ${e instanceof Error ? e.message : "Unknown conversion error"}`;
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 (error) {
118734
- throw ErrorHandler.handleError(error, { ...options, rethrow: true });
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
- performanceNow = () => globalWithPerf.performance.now();
118798
+ const perf = globalWithPerf.performance;
118799
+ performanceNow = () => perf?.now() ?? Date.now();
118788
118800
  } else {
118789
118801
  try {
118790
- const { performance: nodePerformance } = await import("perf_hooks");
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
- return Buffer.byteLength(json, "utf8");
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 import_tsyringe14 = __toESM(require_cjs3(), 1);
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 import_tsyringe13 = __toESM(require_cjs3(), 1);
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 import_tsyringe12 = __toESM(require_cjs3(), 1);
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/template_madlibs_elicitation.tool.ts
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.", { ...appContext, toolInput: input });
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 import_tsyringe11 = __toESM(require_cjs3(), 1);
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 import_tsyringe9 = __toESM(require_cjs3(), 1);
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
- import_tsyringe9.injectable(),
133620
- __legacyDecorateParamTS(0, import_tsyringe9.inject(AppConfig)),
133621
- __legacyDecorateParamTS(1, import_tsyringe9.inject(Logger2)),
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 import_tsyringe10 = __toESM(require_cjs3(), 1);
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
- import_tsyringe10.injectable(),
133727
- __legacyDecorateParamTS(0, import_tsyringe10.inject(AppConfig)),
133728
- __legacyDecorateParamTS(1, import_tsyringe10.inject(Logger2)),
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
- import_tsyringe11.container.register(JwtStrategy, { useClass: JwtStrategy });
133737
- import_tsyringe11.container.register(OauthStrategy, { useClass: OauthStrategy });
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 import_tsyringe11.container.resolve(JwtStrategy);
133811
+ return import_tsyringe12.container.resolve(JwtStrategy);
133748
133812
  case "oauth":
133749
133813
  logger.debug("Resolving OAuth strategy from container.", context);
133750
- return import_tsyringe11.container.resolve(OauthStrategy);
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 transport = new StreamableHTTPTransport;
133885
- transport.sessionId = c.req.header("mcp-session-id") ?? randomUUID();
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
- if (!protectRpc) {
133897
- return await handleRpc();
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
- const token = authHeader.substring(7);
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 { app, server };
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
- // src/mcp-server/server.ts
134115
- async function createMcpServerInstance() {
134116
- const context = requestContextService.createRequestContext({
134117
- operation: "createMcpServerInstance"
134118
- });
134119
- logger.info("Initializing MCP server instance", context);
134120
- requestContextService.configure({
134121
- appName: config.mcpServerName,
134122
- appVersion: config.mcpServerVersion,
134123
- environment: config.environment
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
- async function startTransport() {
134155
- const transportType = config.mcpTransportType;
134156
- const context = requestContextService.createRequestContext({
134157
- operation: "startTransport",
134158
- transport: transportType
134159
- });
134160
- logger.info(`Starting transport: ${transportType}`, context);
134161
- if (transportType === "http") {
134162
- const mcpServer = await createMcpServerInstance();
134163
- const { server } = await startHttpTransport(mcpServer, context);
134164
- return { server };
134165
- }
134166
- if (transportType === "stdio") {
134167
- const server = await createMcpServerInstance();
134168
- await startStdioTransport(server, context);
134169
- return { server };
134170
- }
134171
- logger.crit(`Unsupported transport type configured: ${transportType}`, context);
134172
- throw new Error(`Unsupported transport type: ${transportType}. Must be 'stdio' or 'http'.`);
134173
- }
134174
- async function initializeAndStartServer() {
134175
- const context = requestContextService.createRequestContext({
134176
- operation: "initializeAndStartServer"
134177
- });
134178
- logger.info("MCP Server initialization sequence started.", context);
134179
- try {
134180
- const result = await startTransport();
134181
- logger.info("MCP Server initialization sequence completed successfully.", context);
134182
- return result;
134183
- } catch (err) {
134184
- logger.crit("Critical error during MCP server initialization.", {
134185
- ...context,
134186
- error: err instanceof Error ? err.message : String(err),
134187
- stack: err instanceof Error ? err.stack : undefined
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
- logger.info("Exiting process due to critical initialization error.", context);
134195
- process.exit(1);
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
- import_tsyringe13.container.registerSingleton(ToolRegistry);
134202
- import_tsyringe13.container.registerSingleton(ResourceRegistry);
134203
- registerTools(import_tsyringe13.container);
134204
- registerResources(import_tsyringe13.container);
134205
- import_tsyringe13.container.register(CreateMcpServerInstance, {
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 = import_tsyringe14.container;
134337
+ var container_default = import_tsyringe15.container;
134222
134338
 
134223
134339
  // src/index.ts
134224
134340
  var config2;
134225
- var mcpStdioServer;
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
- let closePromise = Promise.resolve();
134240
- const transportType = config2.mcpTransportType;
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
- composeContainer();
134272
- config2 = container_default.resolve(AppConfig);
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
- const transportType = config2.mcpTransportType;
134403
+ transportManager = container_default.resolve(TransportManagerToken);
134297
134404
  const startupContext = requestContextService.createRequestContext({
134298
- operation: `ServerStartupSequence_${transportType}`,
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} (Version: ${config2.mcpServerVersion}, Transport: ${transportType}, Env: ${config2.environment})...`, startupContext);
134410
+ logger.info(`Starting ${config2.mcpServerName} (v${config2.mcpServerVersion})...`, startupContext);
134304
134411
  try {
134305
- const { server } = await initializeAndStartServer();
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.0",
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 --config vitest.config.ts",
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"