mcp-ts-template 2.2.3 → 2.2.4
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/dist/index.js +390 -84
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -117536,7 +117536,7 @@ var ErrorSchema = z.object({
|
|
|
117536
117536
|
// package.json
|
|
117537
117537
|
var package_default = {
|
|
117538
117538
|
name: "mcp-ts-template",
|
|
117539
|
-
version: "2.2.
|
|
117539
|
+
version: "2.2.4",
|
|
117540
117540
|
mcpName: "io.github.cyanheads/mcp-ts-template",
|
|
117541
117541
|
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.",
|
|
117542
117542
|
main: "dist/index.js",
|
|
@@ -117782,6 +117782,7 @@ var ConfigSchema = z.object({
|
|
|
117782
117782
|
oauthAudience: z.string().optional(),
|
|
117783
117783
|
oauthJwksCooldownMs: z.coerce.number().default(300000),
|
|
117784
117784
|
oauthJwksTimeoutMs: z.coerce.number().default(5000),
|
|
117785
|
+
mcpServerResourceIdentifier: z.string().url().optional(),
|
|
117785
117786
|
devMcpClientId: z.string().optional(),
|
|
117786
117787
|
devMcpScopes: z.array(z.string()).optional(),
|
|
117787
117788
|
openrouterAppUrl: z.string().default("http://localhost:3000"),
|
|
@@ -117876,6 +117877,7 @@ var parseConfig = () => {
|
|
|
117876
117877
|
oauthAudience: env.OAUTH_AUDIENCE,
|
|
117877
117878
|
oauthJwksCooldownMs: env.OAUTH_JWKS_COOLDOWN_MS,
|
|
117878
117879
|
oauthJwksTimeoutMs: env.OAUTH_JWKS_TIMEOUT_MS,
|
|
117880
|
+
mcpServerResourceIdentifier: env.MCP_SERVER_RESOURCE_IDENTIFIER,
|
|
117879
117881
|
devMcpClientId: env.DEV_MCP_CLIENT_ID,
|
|
117880
117882
|
devMcpScopes: env.DEV_MCP_SCOPES?.split(",").map((s) => s.trim()),
|
|
117881
117883
|
openrouterAppUrl: env.OPENROUTER_APP_URL,
|
|
@@ -119508,7 +119510,7 @@ async function fetchWithTimeout(url, timeoutMs, context, options) {
|
|
|
119508
119510
|
|
|
119509
119511
|
// src/container/index.ts
|
|
119510
119512
|
var import_reflect_metadata = __toESM(require_Reflect(), 1);
|
|
119511
|
-
var
|
|
119513
|
+
var import_tsyringe17 = __toESM(require_cjs3(), 1);
|
|
119512
119514
|
|
|
119513
119515
|
// src/container/registrations/core.ts
|
|
119514
119516
|
var import_tsyringe6 = __toESM(require_cjs3(), 1);
|
|
@@ -125751,7 +125753,7 @@ var registerCoreServices = () => {
|
|
|
125751
125753
|
};
|
|
125752
125754
|
|
|
125753
125755
|
// src/container/registrations/mcp.ts
|
|
125754
|
-
var
|
|
125756
|
+
var import_tsyringe16 = __toESM(require_cjs3(), 1);
|
|
125755
125757
|
|
|
125756
125758
|
// src/mcp-server/resources/resource-registration.ts
|
|
125757
125759
|
var import_tsyringe7 = __toESM(require_cjs3(), 1);
|
|
@@ -129162,10 +129164,133 @@ var registerResources = (container3) => {
|
|
|
129162
129164
|
};
|
|
129163
129165
|
|
|
129164
129166
|
// src/mcp-server/server.ts
|
|
129167
|
+
var import_tsyringe11 = __toESM(require_cjs3(), 1);
|
|
129168
|
+
|
|
129169
|
+
// src/mcp-server/prompts/prompt-registration.ts
|
|
129170
|
+
var import_tsyringe8 = __toESM(require_cjs3(), 1);
|
|
129171
|
+
|
|
129172
|
+
// src/mcp-server/prompts/definitions/code-review.prompt.ts
|
|
129173
|
+
var PROMPT_NAME = "code_review";
|
|
129174
|
+
var PROMPT_DESCRIPTION = "Generates a structured code review prompt for analyzing code quality, security, and performance.";
|
|
129175
|
+
var ArgumentsSchema = z.object({
|
|
129176
|
+
language: z.string().optional().describe("Programming language of the code to review."),
|
|
129177
|
+
focus: z.string().optional().describe("The primary focus area for the code review ('security' | 'performance' | 'style' | 'general'). Defaults to 'general'."),
|
|
129178
|
+
includeExamples: z.string().optional().describe("Whether to include example improvements in the review ('true' | 'false'). Defaults to 'false'.")
|
|
129179
|
+
});
|
|
129180
|
+
var codeReviewPrompt = {
|
|
129181
|
+
name: PROMPT_NAME,
|
|
129182
|
+
description: PROMPT_DESCRIPTION,
|
|
129183
|
+
argumentsSchema: ArgumentsSchema,
|
|
129184
|
+
generate: (args) => {
|
|
129185
|
+
const focus = args.focus || "general";
|
|
129186
|
+
const includeExamples = args.includeExamples === "true";
|
|
129187
|
+
const focusGuidance = {
|
|
129188
|
+
security: `- Security vulnerabilities and potential exploits
|
|
129189
|
+
- Input validation and sanitization
|
|
129190
|
+
- Authentication and authorization issues
|
|
129191
|
+
- Data exposure risks`,
|
|
129192
|
+
performance: `- Algorithmic complexity and bottlenecks
|
|
129193
|
+
- Memory usage and leaks
|
|
129194
|
+
- Database query optimization
|
|
129195
|
+
- Caching opportunities`,
|
|
129196
|
+
style: `- Code readability and clarity
|
|
129197
|
+
- Naming conventions
|
|
129198
|
+
- Code organization and structure
|
|
129199
|
+
- Documentation completeness`,
|
|
129200
|
+
general: `- Overall code quality
|
|
129201
|
+
- Security considerations
|
|
129202
|
+
- Performance implications
|
|
129203
|
+
- Maintainability and readability`
|
|
129204
|
+
};
|
|
129205
|
+
const examplesSection = includeExamples ? `
|
|
129206
|
+
|
|
129207
|
+
For each significant finding, provide a concrete example of how to improve the code.` : "";
|
|
129208
|
+
return [
|
|
129209
|
+
{
|
|
129210
|
+
role: "user",
|
|
129211
|
+
content: {
|
|
129212
|
+
type: "text",
|
|
129213
|
+
text: `You are an expert code reviewer${args.language ? ` specializing in ${args.language}` : ""}. Please conduct a thorough code review with a focus on ${focus}.
|
|
129214
|
+
|
|
129215
|
+
Review the code for:
|
|
129216
|
+
${focusGuidance[focus] || focusGuidance["general"]}
|
|
129217
|
+
|
|
129218
|
+
Structure your review as follows:
|
|
129219
|
+
1. **Summary**: 2-3 sentence overview of the code's quality
|
|
129220
|
+
2. **Key Findings**: Bullet-point list of important observations
|
|
129221
|
+
3. **Critical Issues**: Any must-fix problems (if found)
|
|
129222
|
+
4. **Recommendations**: Suggested improvements prioritized by impact${examplesSection}
|
|
129223
|
+
|
|
129224
|
+
Be constructive, specific, and actionable in your feedback.`
|
|
129225
|
+
}
|
|
129226
|
+
}
|
|
129227
|
+
];
|
|
129228
|
+
}
|
|
129229
|
+
};
|
|
129230
|
+
|
|
129231
|
+
// src/mcp-server/prompts/definitions/index.ts
|
|
129232
|
+
var allPromptDefinitions = [codeReviewPrompt];
|
|
129233
|
+
|
|
129234
|
+
// src/mcp-server/prompts/prompt-registration.ts
|
|
129235
|
+
class PromptRegistry {
|
|
129236
|
+
logger;
|
|
129237
|
+
constructor(logger2) {
|
|
129238
|
+
this.logger = logger2;
|
|
129239
|
+
}
|
|
129240
|
+
registerAll(server) {
|
|
129241
|
+
const context = requestContextService.createRequestContext({
|
|
129242
|
+
operation: "PromptRegistry.registerAll"
|
|
129243
|
+
});
|
|
129244
|
+
this.logger.debug(`Registering ${allPromptDefinitions.length} prompts...`, context);
|
|
129245
|
+
for (const promptDef of allPromptDefinitions) {
|
|
129246
|
+
this.logger.debug(`Registering prompt: ${promptDef.name}`, context);
|
|
129247
|
+
server.registerPrompt(promptDef.name, {
|
|
129248
|
+
description: promptDef.description,
|
|
129249
|
+
...promptDef.argumentsSchema && {
|
|
129250
|
+
argsSchema: promptDef.argumentsSchema.shape
|
|
129251
|
+
}
|
|
129252
|
+
}, async (args) => {
|
|
129253
|
+
const messages = await promptDef.generate(args);
|
|
129254
|
+
return { messages };
|
|
129255
|
+
});
|
|
129256
|
+
this.logger.info(`Registered prompt: ${promptDef.name}`, context);
|
|
129257
|
+
}
|
|
129258
|
+
this.logger.info(`Successfully registered ${allPromptDefinitions.length} prompts`, context);
|
|
129259
|
+
}
|
|
129260
|
+
}
|
|
129261
|
+
PromptRegistry = __legacyDecorateClassTS([
|
|
129262
|
+
import_tsyringe8.injectable(),
|
|
129263
|
+
__legacyDecorateParamTS(0, import_tsyringe8.inject(Logger2)),
|
|
129264
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
129265
|
+
Object
|
|
129266
|
+
])
|
|
129267
|
+
], PromptRegistry);
|
|
129268
|
+
|
|
129269
|
+
// src/mcp-server/roots/roots-registration.ts
|
|
129165
129270
|
var import_tsyringe9 = __toESM(require_cjs3(), 1);
|
|
129271
|
+
class RootsRegistry {
|
|
129272
|
+
logger;
|
|
129273
|
+
constructor(logger2) {
|
|
129274
|
+
this.logger = logger2;
|
|
129275
|
+
}
|
|
129276
|
+
registerAll(_server) {
|
|
129277
|
+
const context = requestContextService.createRequestContext({
|
|
129278
|
+
operation: "RootsRegistry.registerAll"
|
|
129279
|
+
});
|
|
129280
|
+
this.logger.debug("Roots capability enabled (client-provided roots)", context);
|
|
129281
|
+
this.logger.info("Roots capability registered successfully", context);
|
|
129282
|
+
}
|
|
129283
|
+
}
|
|
129284
|
+
RootsRegistry = __legacyDecorateClassTS([
|
|
129285
|
+
import_tsyringe9.injectable(),
|
|
129286
|
+
__legacyDecorateParamTS(0, import_tsyringe9.inject(Logger2)),
|
|
129287
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
129288
|
+
Object
|
|
129289
|
+
])
|
|
129290
|
+
], RootsRegistry);
|
|
129166
129291
|
|
|
129167
129292
|
// src/mcp-server/tools/tool-registration.ts
|
|
129168
|
-
var
|
|
129293
|
+
var import_tsyringe10 = __toESM(require_cjs3(), 1);
|
|
129169
129294
|
|
|
129170
129295
|
// src/mcp-server/tools/definitions/template-cat-fact.tool.ts
|
|
129171
129296
|
var TOOL_NAME = "template_cat_fact";
|
|
@@ -129254,11 +129379,136 @@ var catFactTool = {
|
|
|
129254
129379
|
responseFormatter
|
|
129255
129380
|
};
|
|
129256
129381
|
|
|
129257
|
-
// src/mcp-server/tools/definitions/template-
|
|
129258
|
-
var TOOL_NAME2 = "
|
|
129259
|
-
var TOOL_TITLE2 = "
|
|
129260
|
-
var TOOL_DESCRIPTION2 = "
|
|
129382
|
+
// src/mcp-server/tools/definitions/template-code-review-sampling.tool.ts
|
|
129383
|
+
var TOOL_NAME2 = "template_code_review_sampling";
|
|
129384
|
+
var TOOL_TITLE2 = "Code Review with Sampling";
|
|
129385
|
+
var TOOL_DESCRIPTION2 = "Demonstrates MCP sampling by requesting an LLM to review code snippets. The tool uses the client's LLM to generate a code review summary.";
|
|
129261
129386
|
var TOOL_ANNOTATIONS2 = {
|
|
129387
|
+
readOnlyHint: true,
|
|
129388
|
+
idempotentHint: false,
|
|
129389
|
+
openWorldHint: true
|
|
129390
|
+
};
|
|
129391
|
+
var InputSchema2 = z.object({
|
|
129392
|
+
code: z.string().min(1, "Code snippet cannot be empty.").max(1e4, "Code snippet too large (max 10000 characters).").describe("The code snippet to review."),
|
|
129393
|
+
language: z.string().optional().describe('Programming language of the code (e.g., "typescript", "python").'),
|
|
129394
|
+
focus: z.enum(["security", "performance", "style", "general"]).default("general").describe("The focus area for the code review."),
|
|
129395
|
+
maxTokens: z.number().int().min(100).max(2000).default(500).describe("Maximum tokens for the LLM response.")
|
|
129396
|
+
}).describe("Request an LLM-powered code review via sampling.");
|
|
129397
|
+
var OutputSchema3 = z.object({
|
|
129398
|
+
code: z.string().describe("The original code snippet."),
|
|
129399
|
+
language: z.string().optional().describe("The programming language."),
|
|
129400
|
+
focus: z.string().describe("The review focus area."),
|
|
129401
|
+
review: z.string().describe("The LLM-generated code review summary."),
|
|
129402
|
+
tokenUsage: z.object({
|
|
129403
|
+
requested: z.number().describe("Requested max tokens."),
|
|
129404
|
+
actual: z.number().optional().describe("Actual tokens used (if available).")
|
|
129405
|
+
}).optional().describe("Token usage information.")
|
|
129406
|
+
}).describe("Code review tool response payload.");
|
|
129407
|
+
function hasSamplingCapability(ctx) {
|
|
129408
|
+
return typeof ctx?.createMessage === "function";
|
|
129409
|
+
}
|
|
129410
|
+
async function codeReviewToolLogic(input, appContext, sdkContext) {
|
|
129411
|
+
logger.debug("Processing code review with sampling.", {
|
|
129412
|
+
...appContext,
|
|
129413
|
+
toolInput: { ...input, code: `${input.code.substring(0, 100)}...` }
|
|
129414
|
+
});
|
|
129415
|
+
if (!hasSamplingCapability(sdkContext)) {
|
|
129416
|
+
throw new McpError(-32600 /* InvalidRequest */, "Sampling capability is not available. The client does not support MCP sampling.", { requestId: appContext.requestId, operation: "codeReview.sample" });
|
|
129417
|
+
}
|
|
129418
|
+
const focusInstructions = {
|
|
129419
|
+
security: "Focus on security vulnerabilities, input validation, and potential exploits.",
|
|
129420
|
+
performance: "Focus on performance bottlenecks, algorithmic complexity, and optimization opportunities.",
|
|
129421
|
+
style: "Focus on code style, readability, naming conventions, and best practices.",
|
|
129422
|
+
general: "Provide a comprehensive review covering security, performance, and code quality."
|
|
129423
|
+
};
|
|
129424
|
+
const prompt = `You are an expert code reviewer. Please review the following ${input.language || "code"} snippet.
|
|
129425
|
+
|
|
129426
|
+
${focusInstructions[input.focus]}
|
|
129427
|
+
|
|
129428
|
+
Provide a concise, structured review with:
|
|
129429
|
+
1. Summary (2-3 sentences)
|
|
129430
|
+
2. Key findings (bullet points)
|
|
129431
|
+
3. Recommendations (if applicable)
|
|
129432
|
+
|
|
129433
|
+
Code to review:
|
|
129434
|
+
\`\`\`${input.language || ""}
|
|
129435
|
+
${input.code}
|
|
129436
|
+
\`\`\`
|
|
129437
|
+
|
|
129438
|
+
Your review:`;
|
|
129439
|
+
logger.debug("Requesting LLM completion via sampling...", {
|
|
129440
|
+
...appContext,
|
|
129441
|
+
maxTokens: input.maxTokens,
|
|
129442
|
+
focus: input.focus
|
|
129443
|
+
});
|
|
129444
|
+
try {
|
|
129445
|
+
const samplingResult = await sdkContext.createMessage({
|
|
129446
|
+
messages: [
|
|
129447
|
+
{
|
|
129448
|
+
role: "user",
|
|
129449
|
+
content: {
|
|
129450
|
+
type: "text",
|
|
129451
|
+
text: prompt
|
|
129452
|
+
}
|
|
129453
|
+
}
|
|
129454
|
+
],
|
|
129455
|
+
maxTokens: input.maxTokens,
|
|
129456
|
+
temperature: 0.3,
|
|
129457
|
+
modelPreferences: {
|
|
129458
|
+
hints: [{ name: "claude-3-5-sonnet-20241022" }],
|
|
129459
|
+
intelligencePriority: 0.8,
|
|
129460
|
+
speedPriority: 0.2
|
|
129461
|
+
}
|
|
129462
|
+
});
|
|
129463
|
+
logger.info("Sampling completed successfully.", {
|
|
129464
|
+
...appContext,
|
|
129465
|
+
model: samplingResult.model,
|
|
129466
|
+
stopReason: samplingResult.stopReason
|
|
129467
|
+
});
|
|
129468
|
+
const response = {
|
|
129469
|
+
code: input.code,
|
|
129470
|
+
language: input.language,
|
|
129471
|
+
focus: input.focus,
|
|
129472
|
+
review: samplingResult.content.text,
|
|
129473
|
+
tokenUsage: {
|
|
129474
|
+
requested: input.maxTokens
|
|
129475
|
+
}
|
|
129476
|
+
};
|
|
129477
|
+
return response;
|
|
129478
|
+
} catch (error2) {
|
|
129479
|
+
logger.error("Sampling request failed.", {
|
|
129480
|
+
...appContext,
|
|
129481
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
129482
|
+
});
|
|
129483
|
+
throw new McpError(-32603 /* InternalError */, `Failed to complete sampling request: ${error2 instanceof Error ? error2.message : "Unknown error"}`, { requestId: appContext.requestId, operation: "codeReview.sample" });
|
|
129484
|
+
}
|
|
129485
|
+
}
|
|
129486
|
+
function responseFormatter2(result) {
|
|
129487
|
+
return [
|
|
129488
|
+
{
|
|
129489
|
+
type: "text",
|
|
129490
|
+
text: `# Code Review (${result.focus})
|
|
129491
|
+
|
|
129492
|
+
${result.review}`
|
|
129493
|
+
}
|
|
129494
|
+
];
|
|
129495
|
+
}
|
|
129496
|
+
var codeReviewSamplingTool = {
|
|
129497
|
+
name: TOOL_NAME2,
|
|
129498
|
+
title: TOOL_TITLE2,
|
|
129499
|
+
description: TOOL_DESCRIPTION2,
|
|
129500
|
+
inputSchema: InputSchema2,
|
|
129501
|
+
outputSchema: OutputSchema3,
|
|
129502
|
+
annotations: TOOL_ANNOTATIONS2,
|
|
129503
|
+
logic: withToolAuth(["tool:code-review:use"], codeReviewToolLogic),
|
|
129504
|
+
responseFormatter: responseFormatter2
|
|
129505
|
+
};
|
|
129506
|
+
|
|
129507
|
+
// src/mcp-server/tools/definitions/template-echo-message.tool.ts
|
|
129508
|
+
var TOOL_NAME3 = "template_echo_message";
|
|
129509
|
+
var TOOL_TITLE3 = "Template Echo Message";
|
|
129510
|
+
var TOOL_DESCRIPTION3 = "Echoes a message back with optional formatting and repetition.";
|
|
129511
|
+
var TOOL_ANNOTATIONS3 = {
|
|
129262
129512
|
readOnlyHint: true,
|
|
129263
129513
|
idempotentHint: true,
|
|
129264
129514
|
openWorldHint: false
|
|
@@ -129268,13 +129518,13 @@ var DEFAULT_MODE = "standard";
|
|
|
129268
129518
|
var DEFAULT_REPEAT = 1;
|
|
129269
129519
|
var DEFAULT_INCLUDE_TIMESTAMP = false;
|
|
129270
129520
|
var TEST_ERROR_TRIGGER_MESSAGE = "TRIGGER_ERROR";
|
|
129271
|
-
var
|
|
129521
|
+
var InputSchema3 = z.object({
|
|
129272
129522
|
message: z.string().min(1, "Message cannot be empty.").max(1000, "Message cannot exceed 1000 characters.").describe(`The message to echo back. To trigger a test error, provide '${TEST_ERROR_TRIGGER_MESSAGE}'.`),
|
|
129273
129523
|
mode: z.enum(ECHO_MODES).default(DEFAULT_MODE).describe("How to format the message ('standard' | 'uppercase' | 'lowercase')."),
|
|
129274
129524
|
repeat: z.number().int().min(1).max(5).default(DEFAULT_REPEAT).describe("Number of times to repeat the formatted message."),
|
|
129275
129525
|
includeTimestamp: z.boolean().default(DEFAULT_INCLUDE_TIMESTAMP).describe("Whether to include an ISO 8601 timestamp in the response.")
|
|
129276
129526
|
}).describe("Echo a message with optional formatting and repetition.");
|
|
129277
|
-
var
|
|
129527
|
+
var OutputSchema4 = z.object({
|
|
129278
129528
|
originalMessage: z.string().describe("The original message provided in the input."),
|
|
129279
129529
|
formattedMessage: z.string().describe("The message after applying the specified formatting."),
|
|
129280
129530
|
repeatedMessage: z.string().describe("The final message repeated the requested number of times."),
|
|
@@ -129308,7 +129558,7 @@ async function echoToolLogic(input, appContext, _sdkContext) {
|
|
|
129308
129558
|
};
|
|
129309
129559
|
return Promise.resolve(response);
|
|
129310
129560
|
}
|
|
129311
|
-
function
|
|
129561
|
+
function responseFormatter3(result) {
|
|
129312
129562
|
const preview = result.repeatedMessage.length > 200 ? `${result.repeatedMessage.slice(0, 197)}…` : result.repeatedMessage;
|
|
129313
129563
|
const lines = [
|
|
129314
129564
|
`Echo (mode=${result.mode}, repeat=${result.repeatCount})`,
|
|
@@ -129324,14 +129574,14 @@ function responseFormatter2(result) {
|
|
|
129324
129574
|
];
|
|
129325
129575
|
}
|
|
129326
129576
|
var echoTool = {
|
|
129327
|
-
name:
|
|
129328
|
-
title:
|
|
129329
|
-
description:
|
|
129330
|
-
inputSchema:
|
|
129331
|
-
outputSchema:
|
|
129332
|
-
annotations:
|
|
129577
|
+
name: TOOL_NAME3,
|
|
129578
|
+
title: TOOL_TITLE3,
|
|
129579
|
+
description: TOOL_DESCRIPTION3,
|
|
129580
|
+
inputSchema: InputSchema3,
|
|
129581
|
+
outputSchema: OutputSchema4,
|
|
129582
|
+
annotations: TOOL_ANNOTATIONS3,
|
|
129333
129583
|
logic: withToolAuth(["tool:echo:read"], echoToolLogic),
|
|
129334
|
-
responseFormatter:
|
|
129584
|
+
responseFormatter: responseFormatter3
|
|
129335
129585
|
};
|
|
129336
129586
|
|
|
129337
129587
|
// src/utils/internal/encoding.ts
|
|
@@ -129350,19 +129600,19 @@ function arrayBufferToBase64(buffer) {
|
|
|
129350
129600
|
}
|
|
129351
129601
|
|
|
129352
129602
|
// src/mcp-server/tools/definitions/template-image-test.tool.ts
|
|
129353
|
-
var
|
|
129354
|
-
var
|
|
129355
|
-
var
|
|
129356
|
-
var
|
|
129603
|
+
var TOOL_NAME4 = "template_image_test";
|
|
129604
|
+
var TOOL_TITLE4 = "Template Image Test";
|
|
129605
|
+
var TOOL_DESCRIPTION4 = "Fetches a random cat image and returns it base64-encoded with the MIME type. Useful for testing image handling.";
|
|
129606
|
+
var TOOL_ANNOTATIONS4 = {
|
|
129357
129607
|
readOnlyHint: true,
|
|
129358
129608
|
openWorldHint: true
|
|
129359
129609
|
};
|
|
129360
129610
|
var CAT_API_URL = "https://cataas.com/cat";
|
|
129361
129611
|
var API_TIMEOUT_MS = 5000;
|
|
129362
|
-
var
|
|
129612
|
+
var InputSchema4 = z.object({
|
|
129363
129613
|
trigger: z.boolean().optional().default(true).describe("A trigger to invoke the tool and fetch a new cat image.")
|
|
129364
129614
|
}).describe("Parameters for fetching a random image.");
|
|
129365
|
-
var
|
|
129615
|
+
var OutputSchema5 = z.object({
|
|
129366
129616
|
data: z.string().describe("Base64 encoded image data."),
|
|
129367
129617
|
mimeType: z.string().describe("The MIME type of the image (e.g., 'image/jpeg').")
|
|
129368
129618
|
}).describe("Image tool response payload.");
|
|
@@ -129398,7 +129648,7 @@ async function imageTestToolLogic(input, appContext, _sdkContext) {
|
|
|
129398
129648
|
});
|
|
129399
129649
|
return result;
|
|
129400
129650
|
}
|
|
129401
|
-
function
|
|
129651
|
+
function responseFormatter4(result) {
|
|
129402
129652
|
return [
|
|
129403
129653
|
{
|
|
129404
129654
|
type: "image",
|
|
@@ -129408,31 +129658,31 @@ function responseFormatter3(result) {
|
|
|
129408
129658
|
];
|
|
129409
129659
|
}
|
|
129410
129660
|
var imageTestTool = {
|
|
129411
|
-
name:
|
|
129412
|
-
title:
|
|
129413
|
-
description:
|
|
129414
|
-
inputSchema:
|
|
129415
|
-
outputSchema:
|
|
129416
|
-
annotations:
|
|
129661
|
+
name: TOOL_NAME4,
|
|
129662
|
+
title: TOOL_TITLE4,
|
|
129663
|
+
description: TOOL_DESCRIPTION4,
|
|
129664
|
+
inputSchema: InputSchema4,
|
|
129665
|
+
outputSchema: OutputSchema5,
|
|
129666
|
+
annotations: TOOL_ANNOTATIONS4,
|
|
129417
129667
|
logic: withToolAuth(["tool:image_test:read"], imageTestToolLogic),
|
|
129418
|
-
responseFormatter:
|
|
129668
|
+
responseFormatter: responseFormatter4
|
|
129419
129669
|
};
|
|
129420
129670
|
|
|
129421
129671
|
// src/mcp-server/tools/definitions/template-madlibs-elicitation.tool.ts
|
|
129422
|
-
var
|
|
129423
|
-
var
|
|
129424
|
-
var
|
|
129425
|
-
var
|
|
129672
|
+
var TOOL_NAME5 = "template_madlibs_elicitation";
|
|
129673
|
+
var TOOL_TITLE5 = "Mad Libs Elicitation Game";
|
|
129674
|
+
var TOOL_DESCRIPTION5 = "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.";
|
|
129675
|
+
var TOOL_ANNOTATIONS5 = {
|
|
129426
129676
|
readOnlyHint: true,
|
|
129427
129677
|
idempotentHint: false,
|
|
129428
129678
|
openWorldHint: false
|
|
129429
129679
|
};
|
|
129430
|
-
var
|
|
129680
|
+
var InputSchema5 = z.object({
|
|
129431
129681
|
noun: z.string().optional().describe("A noun for the story."),
|
|
129432
129682
|
verb: z.string().optional().describe("A verb (past tense) for the story."),
|
|
129433
129683
|
adjective: z.string().optional().describe("An adjective for the story.")
|
|
129434
129684
|
}).describe("Inputs for the Mad Libs game. Any missing fields will be elicited.");
|
|
129435
|
-
var
|
|
129685
|
+
var OutputSchema6 = z.object({
|
|
129436
129686
|
story: z.string().describe("The final, generated Mad Libs story."),
|
|
129437
129687
|
noun: z.string().describe("The noun used in the story."),
|
|
129438
129688
|
verb: z.string().describe("The verb used in the story."),
|
|
@@ -129472,7 +129722,7 @@ async function madlibsToolLogic(input, appContext, sdkContext) {
|
|
|
129472
129722
|
};
|
|
129473
129723
|
return Promise.resolve(response);
|
|
129474
129724
|
}
|
|
129475
|
-
function
|
|
129725
|
+
function responseFormatter5(result) {
|
|
129476
129726
|
return [
|
|
129477
129727
|
{
|
|
129478
129728
|
type: "text",
|
|
@@ -129489,19 +129739,20 @@ function responseFormatter4(result) {
|
|
|
129489
129739
|
];
|
|
129490
129740
|
}
|
|
129491
129741
|
var madlibsElicitationTool = {
|
|
129492
|
-
name:
|
|
129493
|
-
title:
|
|
129494
|
-
description:
|
|
129495
|
-
inputSchema:
|
|
129496
|
-
outputSchema:
|
|
129497
|
-
annotations:
|
|
129742
|
+
name: TOOL_NAME5,
|
|
129743
|
+
title: TOOL_TITLE5,
|
|
129744
|
+
description: TOOL_DESCRIPTION5,
|
|
129745
|
+
inputSchema: InputSchema5,
|
|
129746
|
+
outputSchema: OutputSchema6,
|
|
129747
|
+
annotations: TOOL_ANNOTATIONS5,
|
|
129498
129748
|
logic: withToolAuth(["tool:madlibs:play"], madlibsToolLogic),
|
|
129499
|
-
responseFormatter:
|
|
129749
|
+
responseFormatter: responseFormatter5
|
|
129500
129750
|
};
|
|
129501
129751
|
|
|
129502
129752
|
// src/mcp-server/tools/definitions/index.ts
|
|
129503
129753
|
var allToolDefinitions = [
|
|
129504
129754
|
catFactTool,
|
|
129755
|
+
codeReviewSamplingTool,
|
|
129505
129756
|
echoTool,
|
|
129506
129757
|
imageTestTool,
|
|
129507
129758
|
madlibsElicitationTool
|
|
@@ -129514,7 +129765,7 @@ var defaultResponseFormatter2 = (result) => [
|
|
|
129514
129765
|
function createMcpToolHandler({
|
|
129515
129766
|
toolName,
|
|
129516
129767
|
logic,
|
|
129517
|
-
responseFormatter:
|
|
129768
|
+
responseFormatter: responseFormatter6 = defaultResponseFormatter2
|
|
129518
129769
|
}) {
|
|
129519
129770
|
return async (input, callContext) => {
|
|
129520
129771
|
const sdkContext = callContext;
|
|
@@ -129531,7 +129782,7 @@ function createMcpToolHandler({
|
|
|
129531
129782
|
const result = await measureToolExecution(() => logic(input, appContext, sdkContext), { ...appContext, toolName }, input);
|
|
129532
129783
|
return {
|
|
129533
129784
|
structuredContent: result,
|
|
129534
|
-
content:
|
|
129785
|
+
content: responseFormatter6(result)
|
|
129535
129786
|
};
|
|
129536
129787
|
} catch (error2) {
|
|
129537
129788
|
const mcpError = ErrorHandler.handleError(error2, {
|
|
@@ -129602,8 +129853,8 @@ class ToolRegistry {
|
|
|
129602
129853
|
}
|
|
129603
129854
|
}
|
|
129604
129855
|
ToolRegistry = __legacyDecorateClassTS([
|
|
129605
|
-
|
|
129606
|
-
__legacyDecorateParamTS(0,
|
|
129856
|
+
import_tsyringe10.injectable(),
|
|
129857
|
+
__legacyDecorateParamTS(0, import_tsyringe10.injectAll(ToolDefinitions)),
|
|
129607
129858
|
__legacyMetadataTS("design:paramtypes", [
|
|
129608
129859
|
Array
|
|
129609
129860
|
])
|
|
@@ -129634,18 +129885,25 @@ async function createMcpServerInstance() {
|
|
|
129634
129885
|
logging: {},
|
|
129635
129886
|
resources: { listChanged: true },
|
|
129636
129887
|
tools: { listChanged: true },
|
|
129637
|
-
elicitation: {}
|
|
129888
|
+
elicitation: {},
|
|
129889
|
+
sampling: {},
|
|
129890
|
+
prompts: { listChanged: true },
|
|
129891
|
+
roots: { listChanged: true }
|
|
129638
129892
|
}
|
|
129639
129893
|
});
|
|
129640
129894
|
try {
|
|
129641
|
-
logger.debug("Registering
|
|
129642
|
-
const toolRegistry =
|
|
129895
|
+
logger.debug("Registering all MCP capabilities via registries...", context);
|
|
129896
|
+
const toolRegistry = import_tsyringe11.container.resolve(ToolRegistry);
|
|
129643
129897
|
await toolRegistry.registerAll(server);
|
|
129644
|
-
const resourceRegistry =
|
|
129898
|
+
const resourceRegistry = import_tsyringe11.container.resolve(ResourceRegistry);
|
|
129645
129899
|
await resourceRegistry.registerAll(server);
|
|
129646
|
-
|
|
129900
|
+
const promptRegistry = import_tsyringe11.container.resolve(PromptRegistry);
|
|
129901
|
+
promptRegistry.registerAll(server);
|
|
129902
|
+
const rootsRegistry = import_tsyringe11.container.resolve(RootsRegistry);
|
|
129903
|
+
rootsRegistry.registerAll(server);
|
|
129904
|
+
logger.info("All MCP capabilities registered successfully", context);
|
|
129647
129905
|
} catch (err) {
|
|
129648
|
-
logger.error("Failed to register
|
|
129906
|
+
logger.error("Failed to register MCP capabilities", {
|
|
129649
129907
|
...context,
|
|
129650
129908
|
error: err instanceof Error ? err.message : String(err),
|
|
129651
129909
|
stack: err instanceof Error ? err.stack : undefined
|
|
@@ -129656,7 +129914,7 @@ async function createMcpServerInstance() {
|
|
|
129656
129914
|
}
|
|
129657
129915
|
|
|
129658
129916
|
// src/mcp-server/transports/manager.ts
|
|
129659
|
-
var
|
|
129917
|
+
var import_tsyringe15 = __toESM(require_cjs3(), 1);
|
|
129660
129918
|
|
|
129661
129919
|
// node_modules/hono/dist/http-exception.js
|
|
129662
129920
|
var HTTPException = class extends Error {
|
|
@@ -132324,7 +132582,7 @@ var cors = (options) => {
|
|
|
132324
132582
|
import http from "http";
|
|
132325
132583
|
import { randomUUID } from "node:crypto";
|
|
132326
132584
|
// src/mcp-server/transports/auth/authFactory.ts
|
|
132327
|
-
var
|
|
132585
|
+
var import_tsyringe14 = __toESM(require_cjs3(), 1);
|
|
132328
132586
|
|
|
132329
132587
|
// node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
132330
132588
|
var encoder = new TextEncoder;
|
|
@@ -133842,7 +134100,7 @@ function createRemoteJWKSet(url, options) {
|
|
|
133842
134100
|
return remoteJWKSet;
|
|
133843
134101
|
}
|
|
133844
134102
|
// src/mcp-server/transports/auth/strategies/jwtStrategy.ts
|
|
133845
|
-
var
|
|
134103
|
+
var import_tsyringe12 = __toESM(require_cjs3(), 1);
|
|
133846
134104
|
class JwtStrategy {
|
|
133847
134105
|
config;
|
|
133848
134106
|
logger;
|
|
@@ -133945,9 +134203,9 @@ class JwtStrategy {
|
|
|
133945
134203
|
}
|
|
133946
134204
|
}
|
|
133947
134205
|
JwtStrategy = __legacyDecorateClassTS([
|
|
133948
|
-
|
|
133949
|
-
__legacyDecorateParamTS(0,
|
|
133950
|
-
__legacyDecorateParamTS(1,
|
|
134206
|
+
import_tsyringe12.injectable(),
|
|
134207
|
+
__legacyDecorateParamTS(0, import_tsyringe12.inject(AppConfig)),
|
|
134208
|
+
__legacyDecorateParamTS(1, import_tsyringe12.inject(Logger2)),
|
|
133951
134209
|
__legacyMetadataTS("design:paramtypes", [
|
|
133952
134210
|
Object,
|
|
133953
134211
|
Object
|
|
@@ -133955,7 +134213,7 @@ JwtStrategy = __legacyDecorateClassTS([
|
|
|
133955
134213
|
], JwtStrategy);
|
|
133956
134214
|
|
|
133957
134215
|
// src/mcp-server/transports/auth/strategies/oauthStrategy.ts
|
|
133958
|
-
var
|
|
134216
|
+
var import_tsyringe13 = __toESM(require_cjs3(), 1);
|
|
133959
134217
|
class OauthStrategy {
|
|
133960
134218
|
config;
|
|
133961
134219
|
logger;
|
|
@@ -134006,6 +134264,26 @@ class OauthStrategy {
|
|
|
134006
134264
|
...context,
|
|
134007
134265
|
claims: payload
|
|
134008
134266
|
});
|
|
134267
|
+
if (this.config.mcpServerResourceIdentifier) {
|
|
134268
|
+
const resourceClaim = payload.resource || payload.aud;
|
|
134269
|
+
const expectedResource = this.config.mcpServerResourceIdentifier;
|
|
134270
|
+
const isResourceValid = Array.isArray(resourceClaim) && resourceClaim.includes(expectedResource) || resourceClaim === expectedResource;
|
|
134271
|
+
if (!isResourceValid) {
|
|
134272
|
+
this.logger.warning("Token resource indicator mismatch. Token was not issued for this MCP server.", {
|
|
134273
|
+
...context,
|
|
134274
|
+
expected: expectedResource,
|
|
134275
|
+
received: resourceClaim
|
|
134276
|
+
});
|
|
134277
|
+
throw new McpError(-32005 /* Forbidden */, "Token was not issued for this MCP server. Resource indicator mismatch.", {
|
|
134278
|
+
expected: expectedResource,
|
|
134279
|
+
received: resourceClaim
|
|
134280
|
+
});
|
|
134281
|
+
}
|
|
134282
|
+
this.logger.debug("RFC 8707 resource indicator validated successfully.", {
|
|
134283
|
+
...context,
|
|
134284
|
+
resource: expectedResource
|
|
134285
|
+
});
|
|
134286
|
+
}
|
|
134009
134287
|
const scopes = typeof payload.scope === "string" ? payload.scope.split(" ") : [];
|
|
134010
134288
|
if (scopes.length === 0) {
|
|
134011
134289
|
this.logger.warning("Invalid token: missing or empty 'scope' claim.", context);
|
|
@@ -134052,9 +134330,9 @@ class OauthStrategy {
|
|
|
134052
134330
|
}
|
|
134053
134331
|
}
|
|
134054
134332
|
OauthStrategy = __legacyDecorateClassTS([
|
|
134055
|
-
|
|
134056
|
-
__legacyDecorateParamTS(0,
|
|
134057
|
-
__legacyDecorateParamTS(1,
|
|
134333
|
+
import_tsyringe13.injectable(),
|
|
134334
|
+
__legacyDecorateParamTS(0, import_tsyringe13.inject(AppConfig)),
|
|
134335
|
+
__legacyDecorateParamTS(1, import_tsyringe13.inject(Logger2)),
|
|
134058
134336
|
__legacyMetadataTS("design:paramtypes", [
|
|
134059
134337
|
Object,
|
|
134060
134338
|
Object
|
|
@@ -134062,8 +134340,8 @@ OauthStrategy = __legacyDecorateClassTS([
|
|
|
134062
134340
|
], OauthStrategy);
|
|
134063
134341
|
|
|
134064
134342
|
// src/mcp-server/transports/auth/authFactory.ts
|
|
134065
|
-
|
|
134066
|
-
|
|
134343
|
+
import_tsyringe14.container.register(JwtStrategy, { useClass: JwtStrategy });
|
|
134344
|
+
import_tsyringe14.container.register(OauthStrategy, { useClass: OauthStrategy });
|
|
134067
134345
|
function createAuthStrategy() {
|
|
134068
134346
|
const context = requestContextService.createRequestContext({
|
|
134069
134347
|
operation: "createAuthStrategy",
|
|
@@ -134073,10 +134351,10 @@ function createAuthStrategy() {
|
|
|
134073
134351
|
switch (config.mcpAuthMode) {
|
|
134074
134352
|
case "jwt":
|
|
134075
134353
|
logger.debug("Resolving JWT strategy from container.", context);
|
|
134076
|
-
return
|
|
134354
|
+
return import_tsyringe14.container.resolve(JwtStrategy);
|
|
134077
134355
|
case "oauth":
|
|
134078
134356
|
logger.debug("Resolving OAuth strategy from container.", context);
|
|
134079
|
-
return
|
|
134357
|
+
return import_tsyringe14.container.resolve(OauthStrategy);
|
|
134080
134358
|
case "none":
|
|
134081
134359
|
logger.info("Authentication is disabled ('none' mode).", context);
|
|
134082
134360
|
return null;
|
|
@@ -134245,6 +134523,18 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
134245
134523
|
}));
|
|
134246
134524
|
app.onError(httpErrorHandler);
|
|
134247
134525
|
app.get("/healthz", (c) => c.json({ status: "ok" }));
|
|
134526
|
+
app.get("/.well-known/oauth-protected-resource", (c) => {
|
|
134527
|
+
if (!config.oauthIssuerUrl) {
|
|
134528
|
+
return c.json({ error: "OAuth not configured on this server" }, { status: 404 });
|
|
134529
|
+
}
|
|
134530
|
+
return c.json({
|
|
134531
|
+
resource: config.mcpServerResourceIdentifier || config.oauthAudience,
|
|
134532
|
+
authorization_servers: [config.oauthIssuerUrl],
|
|
134533
|
+
bearer_methods_supported: ["header"],
|
|
134534
|
+
resource_signing_alg_values_supported: ["RS256", "ES256", "PS256"],
|
|
134535
|
+
...config.oauthJwksUri && { jwks_uri: config.oauthJwksUri }
|
|
134536
|
+
});
|
|
134537
|
+
});
|
|
134248
134538
|
app.get(config.mcpHttpEndpointPath, (c) => {
|
|
134249
134539
|
return c.json({
|
|
134250
134540
|
status: "ok",
|
|
@@ -134267,11 +134557,21 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
134267
134557
|
logger.info("Authentication is disabled; MCP endpoint is unprotected.", transportContext);
|
|
134268
134558
|
}
|
|
134269
134559
|
app.all(config.mcpHttpEndpointPath, async (c) => {
|
|
134560
|
+
const protocolVersion = c.req.header("mcp-protocol-version") ?? "2025-03-26";
|
|
134270
134561
|
logger.debug("Handling MCP request.", {
|
|
134271
134562
|
...transportContext,
|
|
134272
134563
|
path: c.req.path,
|
|
134273
|
-
method: c.req.method
|
|
134564
|
+
method: c.req.method,
|
|
134565
|
+
protocolVersion
|
|
134274
134566
|
});
|
|
134567
|
+
const supportedVersions = ["2025-03-26", "2025-06-18"];
|
|
134568
|
+
if (!supportedVersions.includes(protocolVersion)) {
|
|
134569
|
+
logger.warning("Unsupported MCP protocol version requested.", {
|
|
134570
|
+
...transportContext,
|
|
134571
|
+
protocolVersion,
|
|
134572
|
+
supportedVersions
|
|
134573
|
+
});
|
|
134574
|
+
}
|
|
134275
134575
|
const sessionId = c.req.header("mcp-session-id") ?? randomUUID();
|
|
134276
134576
|
const transport = new McpSessionTransport(sessionId);
|
|
134277
134577
|
const handleRpc = async () => {
|
|
@@ -134289,7 +134589,13 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
134289
134589
|
}
|
|
134290
134590
|
return await handleRpc();
|
|
134291
134591
|
} catch (err) {
|
|
134292
|
-
await transport.close?.()
|
|
134592
|
+
await transport.close?.().catch((closeErr) => {
|
|
134593
|
+
logger.warning("Failed to close transport after error", {
|
|
134594
|
+
...transportContext,
|
|
134595
|
+
sessionId,
|
|
134596
|
+
error: closeErr instanceof Error ? closeErr.message : String(closeErr)
|
|
134597
|
+
});
|
|
134598
|
+
});
|
|
134293
134599
|
throw err instanceof Error ? err : new Error(String(err));
|
|
134294
134600
|
}
|
|
134295
134601
|
});
|
|
@@ -134488,7 +134794,7 @@ async function startStdioTransport(server, parentContext) {
|
|
|
134488
134794
|
logger.info("MCP Server connected and listening via stdio transport.", operationContext);
|
|
134489
134795
|
logStartupBanner(`
|
|
134490
134796
|
\uD83D\uDE80 MCP Server running in STDIO mode.
|
|
134491
|
-
(MCP Spec: 2025-
|
|
134797
|
+
(MCP Spec: 2025-06-18 Stdio Transport)
|
|
134492
134798
|
`);
|
|
134493
134799
|
return server;
|
|
134494
134800
|
} catch (err) {
|
|
@@ -134562,10 +134868,10 @@ class TransportManager {
|
|
|
134562
134868
|
}
|
|
134563
134869
|
}
|
|
134564
134870
|
TransportManager = __legacyDecorateClassTS([
|
|
134565
|
-
|
|
134566
|
-
__legacyDecorateParamTS(0,
|
|
134567
|
-
__legacyDecorateParamTS(1,
|
|
134568
|
-
__legacyDecorateParamTS(2,
|
|
134871
|
+
import_tsyringe15.injectable(),
|
|
134872
|
+
__legacyDecorateParamTS(0, import_tsyringe15.inject(AppConfig)),
|
|
134873
|
+
__legacyDecorateParamTS(1, import_tsyringe15.inject(Logger2)),
|
|
134874
|
+
__legacyDecorateParamTS(2, import_tsyringe15.inject(CreateMcpServerInstance)),
|
|
134569
134875
|
__legacyMetadataTS("design:paramtypes", [
|
|
134570
134876
|
typeof AppConfigType === "undefined" ? Object : AppConfigType,
|
|
134571
134877
|
Object,
|
|
@@ -134575,14 +134881,14 @@ TransportManager = __legacyDecorateClassTS([
|
|
|
134575
134881
|
|
|
134576
134882
|
// src/container/registrations/mcp.ts
|
|
134577
134883
|
var registerMcpServices = () => {
|
|
134578
|
-
|
|
134579
|
-
|
|
134580
|
-
registerTools(
|
|
134581
|
-
registerResources(
|
|
134582
|
-
|
|
134884
|
+
import_tsyringe16.container.registerSingleton(ToolRegistry);
|
|
134885
|
+
import_tsyringe16.container.registerSingleton(ResourceRegistry);
|
|
134886
|
+
registerTools(import_tsyringe16.container);
|
|
134887
|
+
registerResources(import_tsyringe16.container);
|
|
134888
|
+
import_tsyringe16.container.register(CreateMcpServerInstance, {
|
|
134583
134889
|
useValue: createMcpServerInstance
|
|
134584
134890
|
});
|
|
134585
|
-
|
|
134891
|
+
import_tsyringe16.container.registerSingleton(TransportManagerToken, TransportManager);
|
|
134586
134892
|
logger.info("MCP services and factories registered with the DI container.");
|
|
134587
134893
|
};
|
|
134588
134894
|
|
|
@@ -134596,7 +134902,7 @@ function composeContainer() {
|
|
|
134596
134902
|
registerMcpServices();
|
|
134597
134903
|
isContainerComposed = true;
|
|
134598
134904
|
}
|
|
134599
|
-
var container_default =
|
|
134905
|
+
var container_default = import_tsyringe17.container;
|
|
134600
134906
|
|
|
134601
134907
|
// src/index.ts
|
|
134602
134908
|
var config2;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-ts-template",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.4",
|
|
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",
|