mcp-ts-template 2.2.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -34
- package/dist/index.js +298 -207
- package/package.json +1 -1
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",
|
|
@@ -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
|
};
|
|
@@ -117731,51 +117779,6 @@ var import_reflect_metadata2 = __toESM(require_Reflect(), 1);
|
|
|
117731
117779
|
// src/utils/internal/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
|
|
|
@@ -119228,9 +119231,12 @@ async function fetchWithTimeout(url, timeoutMs, context, options) {
|
|
|
119228
119231
|
}
|
|
119229
119232
|
}
|
|
119230
119233
|
|
|
119234
|
+
// src/index.ts
|
|
119235
|
+
var import_reflect_metadata3 = __toESM(require_Reflect(), 1);
|
|
119236
|
+
|
|
119231
119237
|
// src/container/index.ts
|
|
119232
119238
|
var import_reflect_metadata = __toESM(require_Reflect(), 1);
|
|
119233
|
-
var
|
|
119239
|
+
var import_tsyringe15 = __toESM(require_cjs3(), 1);
|
|
119234
119240
|
|
|
119235
119241
|
// src/container/registrations/core.ts
|
|
119236
119242
|
var import_tsyringe6 = __toESM(require_cjs3(), 1);
|
|
@@ -125473,7 +125479,7 @@ var registerCoreServices = () => {
|
|
|
125473
125479
|
};
|
|
125474
125480
|
|
|
125475
125481
|
// src/container/registrations/mcp.ts
|
|
125476
|
-
var
|
|
125482
|
+
var import_tsyringe14 = __toESM(require_cjs3(), 1);
|
|
125477
125483
|
|
|
125478
125484
|
// src/mcp-server/resources/resource-registration.ts
|
|
125479
125485
|
var import_tsyringe7 = __toESM(require_cjs3(), 1);
|
|
@@ -128884,7 +128890,7 @@ var registerResources = (container3) => {
|
|
|
128884
128890
|
};
|
|
128885
128891
|
|
|
128886
128892
|
// src/mcp-server/server.ts
|
|
128887
|
-
var
|
|
128893
|
+
var import_tsyringe9 = __toESM(require_cjs3(), 1);
|
|
128888
128894
|
|
|
128889
128895
|
// src/mcp-server/tools/tool-registration.ts
|
|
128890
128896
|
var import_tsyringe8 = __toESM(require_cjs3(), 1);
|
|
@@ -129140,7 +129146,7 @@ var imageTestTool = {
|
|
|
129140
129146
|
responseFormatter: responseFormatter3
|
|
129141
129147
|
};
|
|
129142
129148
|
|
|
129143
|
-
// src/mcp-server/tools/definitions/
|
|
129149
|
+
// src/mcp-server/tools/definitions/template-madlibs-elicitation.tool.ts
|
|
129144
129150
|
var TOOL_NAME4 = "template_madlibs_elicitation";
|
|
129145
129151
|
var TOOL_TITLE4 = "Mad Libs Elicitation Game";
|
|
129146
129152
|
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 +129184,10 @@ async function elicitAndValidate(partOfSpeech, sdkContext) {
|
|
|
129178
129184
|
return validation.data;
|
|
129179
129185
|
}
|
|
129180
129186
|
async function madlibsToolLogic(input, appContext, sdkContext) {
|
|
129181
|
-
logger.debug("Processing Mad Libs logic.", {
|
|
129187
|
+
logger.debug("Processing Mad Libs logic.", {
|
|
129188
|
+
...appContext,
|
|
129189
|
+
toolInput: input
|
|
129190
|
+
});
|
|
129182
129191
|
const noun = input.noun ?? await elicitAndValidate("noun", sdkContext);
|
|
129183
129192
|
const verb = input.verb ?? await elicitAndValidate("verb", sdkContext);
|
|
129184
129193
|
const adjective = input.adjective ?? await elicitAndValidate("adjective", sdkContext);
|
|
@@ -129333,6 +129342,50 @@ var registerTools = (container3) => {
|
|
|
129333
129342
|
}
|
|
129334
129343
|
};
|
|
129335
129344
|
|
|
129345
|
+
// src/mcp-server/server.ts
|
|
129346
|
+
async function createMcpServerInstance() {
|
|
129347
|
+
const context = requestContextService.createRequestContext({
|
|
129348
|
+
operation: "createMcpServerInstance"
|
|
129349
|
+
});
|
|
129350
|
+
logger.info("Initializing MCP server instance", context);
|
|
129351
|
+
requestContextService.configure({
|
|
129352
|
+
appName: config.mcpServerName,
|
|
129353
|
+
appVersion: config.mcpServerVersion,
|
|
129354
|
+
environment: config.environment
|
|
129355
|
+
});
|
|
129356
|
+
const server = new McpServer({
|
|
129357
|
+
name: config.mcpServerName,
|
|
129358
|
+
version: config.mcpServerVersion,
|
|
129359
|
+
description: config.mcpServerDescription
|
|
129360
|
+
}, {
|
|
129361
|
+
capabilities: {
|
|
129362
|
+
logging: {},
|
|
129363
|
+
resources: { listChanged: true },
|
|
129364
|
+
tools: { listChanged: true },
|
|
129365
|
+
elicitation: {}
|
|
129366
|
+
}
|
|
129367
|
+
});
|
|
129368
|
+
try {
|
|
129369
|
+
logger.debug("Registering resources and tools via registries...", context);
|
|
129370
|
+
const toolRegistry = import_tsyringe9.container.resolve(ToolRegistry);
|
|
129371
|
+
await toolRegistry.registerAll(server);
|
|
129372
|
+
const resourceRegistry = import_tsyringe9.container.resolve(ResourceRegistry);
|
|
129373
|
+
await resourceRegistry.registerAll(server);
|
|
129374
|
+
logger.info("Resources and tools registered successfully", context);
|
|
129375
|
+
} catch (err) {
|
|
129376
|
+
logger.error("Failed to register resources/tools", {
|
|
129377
|
+
...context,
|
|
129378
|
+
error: err instanceof Error ? err.message : String(err),
|
|
129379
|
+
stack: err instanceof Error ? err.stack : undefined
|
|
129380
|
+
});
|
|
129381
|
+
throw err;
|
|
129382
|
+
}
|
|
129383
|
+
return server;
|
|
129384
|
+
}
|
|
129385
|
+
|
|
129386
|
+
// src/mcp-server/transports/manager.ts
|
|
129387
|
+
var import_tsyringe13 = __toESM(require_cjs3(), 1);
|
|
129388
|
+
|
|
129336
129389
|
// node_modules/hono/dist/http-exception.js
|
|
129337
129390
|
var HTTPException = class extends Error {
|
|
129338
129391
|
res;
|
|
@@ -131995,7 +132048,7 @@ var cors = (options) => {
|
|
|
131995
132048
|
import http from "http";
|
|
131996
132049
|
import { randomUUID } from "node:crypto";
|
|
131997
132050
|
// src/mcp-server/transports/auth/authFactory.ts
|
|
131998
|
-
var
|
|
132051
|
+
var import_tsyringe12 = __toESM(require_cjs3(), 1);
|
|
131999
132052
|
|
|
132000
132053
|
// node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
132001
132054
|
var encoder = new TextEncoder;
|
|
@@ -133513,7 +133566,7 @@ function createRemoteJWKSet(url, options) {
|
|
|
133513
133566
|
return remoteJWKSet;
|
|
133514
133567
|
}
|
|
133515
133568
|
// src/mcp-server/transports/auth/strategies/jwtStrategy.ts
|
|
133516
|
-
var
|
|
133569
|
+
var import_tsyringe10 = __toESM(require_cjs3(), 1);
|
|
133517
133570
|
class JwtStrategy {
|
|
133518
133571
|
config;
|
|
133519
133572
|
logger;
|
|
@@ -133616,9 +133669,9 @@ class JwtStrategy {
|
|
|
133616
133669
|
}
|
|
133617
133670
|
}
|
|
133618
133671
|
JwtStrategy = __legacyDecorateClassTS([
|
|
133619
|
-
|
|
133620
|
-
__legacyDecorateParamTS(0,
|
|
133621
|
-
__legacyDecorateParamTS(1,
|
|
133672
|
+
import_tsyringe10.injectable(),
|
|
133673
|
+
__legacyDecorateParamTS(0, import_tsyringe10.inject(AppConfig)),
|
|
133674
|
+
__legacyDecorateParamTS(1, import_tsyringe10.inject(Logger2)),
|
|
133622
133675
|
__legacyMetadataTS("design:paramtypes", [
|
|
133623
133676
|
Object,
|
|
133624
133677
|
Object
|
|
@@ -133626,7 +133679,7 @@ JwtStrategy = __legacyDecorateClassTS([
|
|
|
133626
133679
|
], JwtStrategy);
|
|
133627
133680
|
|
|
133628
133681
|
// src/mcp-server/transports/auth/strategies/oauthStrategy.ts
|
|
133629
|
-
var
|
|
133682
|
+
var import_tsyringe11 = __toESM(require_cjs3(), 1);
|
|
133630
133683
|
class OauthStrategy {
|
|
133631
133684
|
config;
|
|
133632
133685
|
logger;
|
|
@@ -133723,9 +133776,9 @@ class OauthStrategy {
|
|
|
133723
133776
|
}
|
|
133724
133777
|
}
|
|
133725
133778
|
OauthStrategy = __legacyDecorateClassTS([
|
|
133726
|
-
|
|
133727
|
-
__legacyDecorateParamTS(0,
|
|
133728
|
-
__legacyDecorateParamTS(1,
|
|
133779
|
+
import_tsyringe11.injectable(),
|
|
133780
|
+
__legacyDecorateParamTS(0, import_tsyringe11.inject(AppConfig)),
|
|
133781
|
+
__legacyDecorateParamTS(1, import_tsyringe11.inject(Logger2)),
|
|
133729
133782
|
__legacyMetadataTS("design:paramtypes", [
|
|
133730
133783
|
Object,
|
|
133731
133784
|
Object
|
|
@@ -133733,8 +133786,8 @@ OauthStrategy = __legacyDecorateClassTS([
|
|
|
133733
133786
|
], OauthStrategy);
|
|
133734
133787
|
|
|
133735
133788
|
// src/mcp-server/transports/auth/authFactory.ts
|
|
133736
|
-
|
|
133737
|
-
|
|
133789
|
+
import_tsyringe12.container.register(JwtStrategy, { useClass: JwtStrategy });
|
|
133790
|
+
import_tsyringe12.container.register(OauthStrategy, { useClass: OauthStrategy });
|
|
133738
133791
|
function createAuthStrategy() {
|
|
133739
133792
|
const context = requestContextService.createRequestContext({
|
|
133740
133793
|
operation: "createAuthStrategy",
|
|
@@ -133744,10 +133797,10 @@ function createAuthStrategy() {
|
|
|
133744
133797
|
switch (config.mcpAuthMode) {
|
|
133745
133798
|
case "jwt":
|
|
133746
133799
|
logger.debug("Resolving JWT strategy from container.", context);
|
|
133747
|
-
return
|
|
133800
|
+
return import_tsyringe12.container.resolve(JwtStrategy);
|
|
133748
133801
|
case "oauth":
|
|
133749
133802
|
logger.debug("Resolving OAuth strategy from container.", context);
|
|
133750
|
-
return
|
|
133803
|
+
return import_tsyringe12.container.resolve(OauthStrategy);
|
|
133751
133804
|
case "none":
|
|
133752
133805
|
logger.info("Authentication is disabled ('none' mode).", context);
|
|
133753
133806
|
return null;
|
|
@@ -133756,6 +133809,53 @@ function createAuthStrategy() {
|
|
|
133756
133809
|
throw new Error(`Unknown authentication mode: ${String(config.mcpAuthMode)}`);
|
|
133757
133810
|
}
|
|
133758
133811
|
}
|
|
133812
|
+
// src/mcp-server/transports/auth/authMiddleware.ts
|
|
133813
|
+
function createAuthMiddleware(strategy) {
|
|
133814
|
+
return async function authMiddleware(c, next) {
|
|
133815
|
+
const context = requestContextService.createRequestContext({
|
|
133816
|
+
operation: "authMiddleware",
|
|
133817
|
+
additionalContext: {
|
|
133818
|
+
method: c.req.method,
|
|
133819
|
+
path: c.req.path
|
|
133820
|
+
}
|
|
133821
|
+
});
|
|
133822
|
+
logger.debug("Initiating authentication check.", context);
|
|
133823
|
+
const authHeader = c.req.header("Authorization");
|
|
133824
|
+
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
133825
|
+
logger.warning("Authorization header missing or invalid.", context);
|
|
133826
|
+
throw new McpError(-32006 /* Unauthorized */, "Missing or invalid Authorization header. Bearer scheme required.", context);
|
|
133827
|
+
}
|
|
133828
|
+
const token = authHeader.substring(7);
|
|
133829
|
+
if (!token) {
|
|
133830
|
+
logger.warning("Bearer token is missing from Authorization header.", context);
|
|
133831
|
+
throw new McpError(-32006 /* Unauthorized */, "Authentication token is missing.", context);
|
|
133832
|
+
}
|
|
133833
|
+
logger.debug("Extracted Bearer token, proceeding to verification.", context);
|
|
133834
|
+
try {
|
|
133835
|
+
const authInfo = await strategy.verify(token);
|
|
133836
|
+
const authLogContext = {
|
|
133837
|
+
...context,
|
|
133838
|
+
...authInfo.tenantId ? { tenantId: authInfo.tenantId } : {},
|
|
133839
|
+
clientId: authInfo.clientId,
|
|
133840
|
+
subject: authInfo.subject,
|
|
133841
|
+
scopes: authInfo.scopes
|
|
133842
|
+
};
|
|
133843
|
+
logger.info("Authentication successful. Auth context populated.", authLogContext);
|
|
133844
|
+
await authContext.run({ authInfo }, next);
|
|
133845
|
+
} catch (error2) {
|
|
133846
|
+
logger.warning("Authentication verification failed.", {
|
|
133847
|
+
...context,
|
|
133848
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
133849
|
+
});
|
|
133850
|
+
throw ErrorHandler.handleError(error2, {
|
|
133851
|
+
operation: "authMiddlewareVerification",
|
|
133852
|
+
context,
|
|
133853
|
+
rethrow: true,
|
|
133854
|
+
errorCode: -32006 /* Unauthorized */
|
|
133855
|
+
});
|
|
133856
|
+
}
|
|
133857
|
+
};
|
|
133858
|
+
}
|
|
133759
133859
|
// src/mcp-server/transports/http/httpErrorHandler.ts
|
|
133760
133860
|
var httpErrorHandler = async (err, c) => {
|
|
133761
133861
|
const context = requestContextService.createRequestContext({
|
|
@@ -133841,6 +133941,13 @@ var httpErrorHandler = async (err, c) => {
|
|
|
133841
133941
|
};
|
|
133842
133942
|
|
|
133843
133943
|
// src/mcp-server/transports/http/httpTransport.ts
|
|
133944
|
+
class McpSessionTransport extends StreamableHTTPTransport {
|
|
133945
|
+
sessionId;
|
|
133946
|
+
constructor(sessionId) {
|
|
133947
|
+
super();
|
|
133948
|
+
this.sessionId = sessionId;
|
|
133949
|
+
}
|
|
133950
|
+
}
|
|
133844
133951
|
function createHttpApp(mcpServer, parentContext) {
|
|
133845
133952
|
const app = new Hono2;
|
|
133846
133953
|
const transportContext = {
|
|
@@ -133875,14 +133982,22 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
133875
133982
|
}
|
|
133876
133983
|
});
|
|
133877
133984
|
});
|
|
133985
|
+
const authStrategy = createAuthStrategy();
|
|
133986
|
+
if (authStrategy) {
|
|
133987
|
+
const authMiddleware = createAuthMiddleware(authStrategy);
|
|
133988
|
+
app.use(config.mcpHttpEndpointPath, authMiddleware);
|
|
133989
|
+
logger.info("Authentication middleware enabled for MCP endpoint.", transportContext);
|
|
133990
|
+
} else {
|
|
133991
|
+
logger.info("Authentication is disabled; MCP endpoint is unprotected.", transportContext);
|
|
133992
|
+
}
|
|
133878
133993
|
app.all(config.mcpHttpEndpointPath, async (c) => {
|
|
133879
133994
|
logger.debug("Handling MCP request.", {
|
|
133880
133995
|
...transportContext,
|
|
133881
133996
|
path: c.req.path,
|
|
133882
133997
|
method: c.req.method
|
|
133883
133998
|
});
|
|
133884
|
-
const
|
|
133885
|
-
transport
|
|
133999
|
+
const sessionId = c.req.header("mcp-session-id") ?? randomUUID();
|
|
134000
|
+
const transport = new McpSessionTransport(sessionId);
|
|
133886
134001
|
const handleRpc = async () => {
|
|
133887
134002
|
await mcpServer.connect(transport);
|
|
133888
134003
|
const response = await transport.handleRequest(c);
|
|
@@ -133891,30 +134006,12 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
133891
134006
|
}
|
|
133892
134007
|
return c.body(null, 204);
|
|
133893
134008
|
};
|
|
133894
|
-
const protectRpc = config.mcpAuthMode !== "none";
|
|
133895
134009
|
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);
|
|
134010
|
+
const store = authContext.getStore();
|
|
134011
|
+
if (store) {
|
|
134012
|
+
return await authContext.run(store, handleRpc);
|
|
133907
134013
|
}
|
|
133908
|
-
|
|
133909
|
-
if (!strategy) {
|
|
133910
|
-
logger.warning("Auth mode indicates protection, but no strategy was created. Proceeding unauthenticated.", transportContext);
|
|
133911
|
-
return await handleRpc();
|
|
133912
|
-
}
|
|
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
|
-
});
|
|
134014
|
+
return await handleRpc();
|
|
133918
134015
|
} catch (err) {
|
|
133919
134016
|
await transport.close?.();
|
|
133920
134017
|
throw err instanceof Error ? err : new Error(String(err));
|
|
@@ -133985,7 +134082,25 @@ async function startHttpTransport(mcpServer, parentContext) {
|
|
|
133985
134082
|
const app = createHttpApp(mcpServer, transportContext);
|
|
133986
134083
|
const server = await startHttpServerWithRetry(app, config.mcpHttpPort, config.mcpHttpHost, config.mcpHttpMaxPortRetries, transportContext);
|
|
133987
134084
|
logger.info("HTTP transport started successfully.", transportContext);
|
|
133988
|
-
return
|
|
134085
|
+
return server;
|
|
134086
|
+
}
|
|
134087
|
+
async function stopHttpTransport(server, parentContext) {
|
|
134088
|
+
const operationContext = {
|
|
134089
|
+
...parentContext,
|
|
134090
|
+
operation: "stopHttpTransport",
|
|
134091
|
+
transportType: "Http"
|
|
134092
|
+
};
|
|
134093
|
+
logger.info("Attempting to stop http transport...", operationContext);
|
|
134094
|
+
return new Promise((resolve, reject) => {
|
|
134095
|
+
server.close((err) => {
|
|
134096
|
+
if (err) {
|
|
134097
|
+
logger.error("Error closing HTTP server.", err, operationContext);
|
|
134098
|
+
return reject(err);
|
|
134099
|
+
}
|
|
134100
|
+
logger.info("HTTP server closed successfully.", operationContext);
|
|
134101
|
+
resolve();
|
|
134102
|
+
});
|
|
134103
|
+
});
|
|
133989
134104
|
}
|
|
133990
134105
|
|
|
133991
134106
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
@@ -134102,6 +134217,7 @@ async function startStdioTransport(server, parentContext) {
|
|
|
134102
134217
|
(MCP Spec: 2025-03-26 Stdio Transport)
|
|
134103
134218
|
`);
|
|
134104
134219
|
}
|
|
134220
|
+
return server;
|
|
134105
134221
|
} catch (err) {
|
|
134106
134222
|
throw ErrorHandler.handleError(err, {
|
|
134107
134223
|
operation: "connectStdioTransport",
|
|
@@ -134111,100 +134227,89 @@ async function startStdioTransport(server, parentContext) {
|
|
|
134111
134227
|
});
|
|
134112
134228
|
}
|
|
134113
134229
|
}
|
|
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;
|
|
134230
|
+
async function stopStdioTransport(server, parentContext) {
|
|
134231
|
+
const operationContext = {
|
|
134232
|
+
...parentContext,
|
|
134233
|
+
operation: "stopStdioTransport",
|
|
134234
|
+
transportType: "Stdio"
|
|
134235
|
+
};
|
|
134236
|
+
logger.info("Attempting to stop stdio transport...", operationContext);
|
|
134237
|
+
if (server) {
|
|
134238
|
+
await server.close();
|
|
134239
|
+
logger.info("Stdio transport stopped successfully.", operationContext);
|
|
134151
134240
|
}
|
|
134152
|
-
return server;
|
|
134153
134241
|
}
|
|
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
|
|
134242
|
+
|
|
134243
|
+
// src/mcp-server/transports/manager.ts
|
|
134244
|
+
class TransportManager {
|
|
134245
|
+
config;
|
|
134246
|
+
logger;
|
|
134247
|
+
createMcpServer;
|
|
134248
|
+
serverInstance = null;
|
|
134249
|
+
constructor(config2, logger2, createMcpServer) {
|
|
134250
|
+
this.config = config2;
|
|
134251
|
+
this.logger = logger2;
|
|
134252
|
+
this.createMcpServer = createMcpServer;
|
|
134253
|
+
}
|
|
134254
|
+
async start() {
|
|
134255
|
+
const context = requestContextService.createRequestContext({
|
|
134256
|
+
operation: "TransportManager.start",
|
|
134257
|
+
transport: this.config.mcpTransportType
|
|
134258
|
+
});
|
|
134259
|
+
this.logger.info(`Starting transport: ${this.config.mcpTransportType}`, context);
|
|
134260
|
+
const mcpServer = await this.createMcpServer();
|
|
134261
|
+
if (this.config.mcpTransportType === "http") {
|
|
134262
|
+
this.serverInstance = await startHttpTransport(mcpServer, context);
|
|
134263
|
+
} else if (this.config.mcpTransportType === "stdio") {
|
|
134264
|
+
this.serverInstance = await startStdioTransport(mcpServer, context);
|
|
134265
|
+
} else {
|
|
134266
|
+
const transportType = String(this.config.mcpTransportType);
|
|
134267
|
+
const error2 = new Error(`Unsupported transport type: ${transportType}`);
|
|
134268
|
+
this.logger.crit(error2.message, context);
|
|
134269
|
+
throw error2;
|
|
134270
|
+
}
|
|
134271
|
+
}
|
|
134272
|
+
async stop(signal) {
|
|
134273
|
+
const context = requestContextService.createRequestContext({
|
|
134274
|
+
operation: "TransportManager.stop",
|
|
134275
|
+
signal
|
|
134193
134276
|
});
|
|
134194
|
-
|
|
134195
|
-
|
|
134277
|
+
if (!this.serverInstance) {
|
|
134278
|
+
this.logger.warning("Stop called but no active server instance found.", context);
|
|
134279
|
+
return;
|
|
134280
|
+
}
|
|
134281
|
+
if (this.config.mcpTransportType === "http") {
|
|
134282
|
+
await stopHttpTransport(this.serverInstance, context);
|
|
134283
|
+
} else if (this.config.mcpTransportType === "stdio") {
|
|
134284
|
+
await stopStdioTransport(this.serverInstance, context);
|
|
134285
|
+
}
|
|
134286
|
+
}
|
|
134287
|
+
getServer() {
|
|
134288
|
+
return this.serverInstance;
|
|
134196
134289
|
}
|
|
134197
134290
|
}
|
|
134291
|
+
TransportManager = __legacyDecorateClassTS([
|
|
134292
|
+
import_tsyringe13.injectable(),
|
|
134293
|
+
__legacyDecorateParamTS(0, import_tsyringe13.inject(AppConfig)),
|
|
134294
|
+
__legacyDecorateParamTS(1, import_tsyringe13.inject(Logger2)),
|
|
134295
|
+
__legacyDecorateParamTS(2, import_tsyringe13.inject(CreateMcpServerInstance)),
|
|
134296
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
134297
|
+
typeof AppConfigType === "undefined" ? Object : AppConfigType,
|
|
134298
|
+
Object,
|
|
134299
|
+
Function
|
|
134300
|
+
])
|
|
134301
|
+
], TransportManager);
|
|
134198
134302
|
|
|
134199
134303
|
// src/container/registrations/mcp.ts
|
|
134200
134304
|
var registerMcpServices = () => {
|
|
134201
|
-
|
|
134202
|
-
|
|
134203
|
-
registerTools(
|
|
134204
|
-
registerResources(
|
|
134205
|
-
|
|
134305
|
+
import_tsyringe14.container.registerSingleton(ToolRegistry);
|
|
134306
|
+
import_tsyringe14.container.registerSingleton(ResourceRegistry);
|
|
134307
|
+
registerTools(import_tsyringe14.container);
|
|
134308
|
+
registerResources(import_tsyringe14.container);
|
|
134309
|
+
import_tsyringe14.container.register(CreateMcpServerInstance, {
|
|
134206
134310
|
useValue: createMcpServerInstance
|
|
134207
134311
|
});
|
|
134312
|
+
import_tsyringe14.container.registerSingleton(TransportManagerToken, TransportManager);
|
|
134208
134313
|
logger.info("MCP services and factories registered with the DI container.");
|
|
134209
134314
|
};
|
|
134210
134315
|
|
|
@@ -134218,12 +134323,11 @@ function composeContainer() {
|
|
|
134218
134323
|
registerMcpServices();
|
|
134219
134324
|
isContainerComposed = true;
|
|
134220
134325
|
}
|
|
134221
|
-
var container_default =
|
|
134326
|
+
var container_default = import_tsyringe15.container;
|
|
134222
134327
|
|
|
134223
134328
|
// src/index.ts
|
|
134224
134329
|
var config2;
|
|
134225
|
-
var
|
|
134226
|
-
var actualHttpServer;
|
|
134330
|
+
var transportManager;
|
|
134227
134331
|
var isShuttingDown = false;
|
|
134228
134332
|
var shutdown = async (signal) => {
|
|
134229
134333
|
if (isShuttingDown) {
|
|
@@ -134236,25 +134340,9 @@ var shutdown = async (signal) => {
|
|
|
134236
134340
|
});
|
|
134237
134341
|
logger.info(`Received ${signal}. Initiating graceful shutdown...`, shutdownContext);
|
|
134238
134342
|
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
|
-
});
|
|
134343
|
+
if (transportManager) {
|
|
134344
|
+
await transportManager.stop(signal);
|
|
134256
134345
|
}
|
|
134257
|
-
await closePromise;
|
|
134258
134346
|
logger.info("Graceful shutdown completed successfully. Exiting.", shutdownContext);
|
|
134259
134347
|
await shutdownOpenTelemetry();
|
|
134260
134348
|
await logger.close();
|
|
@@ -134268,8 +134356,16 @@ var shutdown = async (signal) => {
|
|
|
134268
134356
|
}
|
|
134269
134357
|
};
|
|
134270
134358
|
var start = async () => {
|
|
134271
|
-
|
|
134272
|
-
|
|
134359
|
+
try {
|
|
134360
|
+
composeContainer();
|
|
134361
|
+
config2 = container_default.resolve(AppConfig);
|
|
134362
|
+
} catch (_error) {
|
|
134363
|
+
if (process.stdout.isTTY) {
|
|
134364
|
+
console.error("Halting due to critical configuration error.");
|
|
134365
|
+
}
|
|
134366
|
+
await shutdownOpenTelemetry();
|
|
134367
|
+
process.exit(1);
|
|
134368
|
+
}
|
|
134273
134369
|
await initializePerformance_Hrt();
|
|
134274
134370
|
const validMcpLogLevels = [
|
|
134275
134371
|
"debug",
|
|
@@ -134293,21 +134389,16 @@ var start = async () => {
|
|
|
134293
134389
|
await logger.initialize(validatedMcpLogLevel);
|
|
134294
134390
|
logger.info(`Logger initialized. Effective MCP logging level: ${validatedMcpLogLevel}.`, requestContextService.createRequestContext({ operation: "LoggerInit" }));
|
|
134295
134391
|
logger.info(`Storage service initialized with provider: ${config2.storage.providerType}`, requestContextService.createRequestContext({ operation: "StorageInit" }));
|
|
134296
|
-
|
|
134392
|
+
transportManager = container_default.resolve(TransportManagerToken);
|
|
134297
134393
|
const startupContext = requestContextService.createRequestContext({
|
|
134298
|
-
operation:
|
|
134394
|
+
operation: "ServerStartup",
|
|
134299
134395
|
applicationName: config2.mcpServerName,
|
|
134300
134396
|
applicationVersion: config2.mcpServerVersion,
|
|
134301
134397
|
nodeEnvironment: config2.environment
|
|
134302
134398
|
});
|
|
134303
|
-
logger.info(`Starting ${config2.mcpServerName} (
|
|
134399
|
+
logger.info(`Starting ${config2.mcpServerName} (v${config2.mcpServerVersion})...`, startupContext);
|
|
134304
134400
|
try {
|
|
134305
|
-
|
|
134306
|
-
if (transportType === "http") {
|
|
134307
|
-
actualHttpServer = server;
|
|
134308
|
-
} else if (transportType === "stdio") {
|
|
134309
|
-
mcpStdioServer = server;
|
|
134310
|
-
}
|
|
134401
|
+
await transportManager.start();
|
|
134311
134402
|
logger.info(`${config2.mcpServerName} is now running and ready.`, startupContext);
|
|
134312
134403
|
process.on("SIGTERM", () => void shutdown("SIGTERM"));
|
|
134313
134404
|
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.1",
|
|
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",
|