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.
Files changed (2) hide show
  1. package/dist/index.js +390 -84
  2. 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.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 import_tsyringe15 = __toESM(require_cjs3(), 1);
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 import_tsyringe14 = __toESM(require_cjs3(), 1);
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 import_tsyringe8 = __toESM(require_cjs3(), 1);
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-echo-message.tool.ts
129258
- var TOOL_NAME2 = "template_echo_message";
129259
- var TOOL_TITLE2 = "Template Echo Message";
129260
- var TOOL_DESCRIPTION2 = "Echoes a message back with optional formatting and repetition.";
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 InputSchema2 = z.object({
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 OutputSchema3 = z.object({
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 responseFormatter2(result) {
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: TOOL_NAME2,
129328
- title: TOOL_TITLE2,
129329
- description: TOOL_DESCRIPTION2,
129330
- inputSchema: InputSchema2,
129331
- outputSchema: OutputSchema3,
129332
- annotations: TOOL_ANNOTATIONS2,
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: responseFormatter2
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 TOOL_NAME3 = "template_image_test";
129354
- var TOOL_TITLE3 = "Template Image Test";
129355
- var TOOL_DESCRIPTION3 = "Fetches a random cat image and returns it base64-encoded with the MIME type. Useful for testing image handling.";
129356
- var TOOL_ANNOTATIONS3 = {
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 InputSchema3 = z.object({
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 OutputSchema4 = z.object({
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 responseFormatter3(result) {
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: TOOL_NAME3,
129412
- title: TOOL_TITLE3,
129413
- description: TOOL_DESCRIPTION3,
129414
- inputSchema: InputSchema3,
129415
- outputSchema: OutputSchema4,
129416
- annotations: TOOL_ANNOTATIONS3,
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: responseFormatter3
129668
+ responseFormatter: responseFormatter4
129419
129669
  };
129420
129670
 
129421
129671
  // src/mcp-server/tools/definitions/template-madlibs-elicitation.tool.ts
129422
- var TOOL_NAME4 = "template_madlibs_elicitation";
129423
- var TOOL_TITLE4 = "Mad Libs Elicitation Game";
129424
- 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.";
129425
- var TOOL_ANNOTATIONS4 = {
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 InputSchema4 = z.object({
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 OutputSchema5 = z.object({
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 responseFormatter4(result) {
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: TOOL_NAME4,
129493
- title: TOOL_TITLE4,
129494
- description: TOOL_DESCRIPTION4,
129495
- inputSchema: InputSchema4,
129496
- outputSchema: OutputSchema5,
129497
- annotations: TOOL_ANNOTATIONS4,
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: responseFormatter4
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: responseFormatter5 = defaultResponseFormatter2
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: responseFormatter5(result)
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
- import_tsyringe8.injectable(),
129606
- __legacyDecorateParamTS(0, import_tsyringe8.injectAll(ToolDefinitions)),
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 resources and tools via registries...", context);
129642
- const toolRegistry = import_tsyringe9.container.resolve(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 = import_tsyringe9.container.resolve(ResourceRegistry);
129898
+ const resourceRegistry = import_tsyringe11.container.resolve(ResourceRegistry);
129645
129899
  await resourceRegistry.registerAll(server);
129646
- logger.info("Resources and tools registered successfully", context);
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 resources/tools", {
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 import_tsyringe13 = __toESM(require_cjs3(), 1);
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 import_tsyringe12 = __toESM(require_cjs3(), 1);
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 import_tsyringe10 = __toESM(require_cjs3(), 1);
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
- import_tsyringe10.injectable(),
133949
- __legacyDecorateParamTS(0, import_tsyringe10.inject(AppConfig)),
133950
- __legacyDecorateParamTS(1, import_tsyringe10.inject(Logger2)),
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 import_tsyringe11 = __toESM(require_cjs3(), 1);
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
- import_tsyringe11.injectable(),
134056
- __legacyDecorateParamTS(0, import_tsyringe11.inject(AppConfig)),
134057
- __legacyDecorateParamTS(1, import_tsyringe11.inject(Logger2)),
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
- import_tsyringe12.container.register(JwtStrategy, { useClass: JwtStrategy });
134066
- import_tsyringe12.container.register(OauthStrategy, { useClass: OauthStrategy });
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 import_tsyringe12.container.resolve(JwtStrategy);
134354
+ return import_tsyringe14.container.resolve(JwtStrategy);
134077
134355
  case "oauth":
134078
134356
  logger.debug("Resolving OAuth strategy from container.", context);
134079
- return import_tsyringe12.container.resolve(OauthStrategy);
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-03-26 Stdio Transport)
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
- import_tsyringe13.injectable(),
134566
- __legacyDecorateParamTS(0, import_tsyringe13.inject(AppConfig)),
134567
- __legacyDecorateParamTS(1, import_tsyringe13.inject(Logger2)),
134568
- __legacyDecorateParamTS(2, import_tsyringe13.inject(CreateMcpServerInstance)),
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
- import_tsyringe14.container.registerSingleton(ToolRegistry);
134579
- import_tsyringe14.container.registerSingleton(ResourceRegistry);
134580
- registerTools(import_tsyringe14.container);
134581
- registerResources(import_tsyringe14.container);
134582
- import_tsyringe14.container.register(CreateMcpServerInstance, {
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
- import_tsyringe14.container.registerSingleton(TransportManagerToken, TransportManager);
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 = import_tsyringe15.container;
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",
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",