mcp-ts-template 2.2.3 → 2.2.5
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 +816 -108
- 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);
|
|
@@ -125172,9 +125174,25 @@ class StorageService2 {
|
|
|
125172
125174
|
const tenantId = requireTenantId(context);
|
|
125173
125175
|
return this.provider.delete(tenantId, key, context);
|
|
125174
125176
|
}
|
|
125175
|
-
list(prefix, context) {
|
|
125177
|
+
list(prefix, context, options) {
|
|
125178
|
+
const tenantId = requireTenantId(context);
|
|
125179
|
+
return this.provider.list(tenantId, prefix, context, options);
|
|
125180
|
+
}
|
|
125181
|
+
getMany(keys, context) {
|
|
125182
|
+
const tenantId = requireTenantId(context);
|
|
125183
|
+
return this.provider.getMany(tenantId, keys, context);
|
|
125184
|
+
}
|
|
125185
|
+
setMany(entries, context, options) {
|
|
125186
|
+
const tenantId = requireTenantId(context);
|
|
125187
|
+
return this.provider.setMany(tenantId, entries, context, options);
|
|
125188
|
+
}
|
|
125189
|
+
deleteMany(keys, context) {
|
|
125190
|
+
const tenantId = requireTenantId(context);
|
|
125191
|
+
return this.provider.deleteMany(tenantId, keys, context);
|
|
125192
|
+
}
|
|
125193
|
+
clear(context) {
|
|
125176
125194
|
const tenantId = requireTenantId(context);
|
|
125177
|
-
return this.provider.
|
|
125195
|
+
return this.provider.clear(tenantId, context);
|
|
125178
125196
|
}
|
|
125179
125197
|
}
|
|
125180
125198
|
StorageService2 = __legacyDecorateClassTS([
|
|
@@ -125192,6 +125210,7 @@ var import_tsyringe5 = __toESM(require_cjs3(), 1);
|
|
|
125192
125210
|
import { existsSync, mkdirSync } from "fs";
|
|
125193
125211
|
import { readFile, readdir, rm, writeFile } from "fs/promises";
|
|
125194
125212
|
import path2 from "path";
|
|
125213
|
+
var DEFAULT_LIST_LIMIT = 1000;
|
|
125195
125214
|
var FILE_ENVELOPE_VERSION = 1;
|
|
125196
125215
|
|
|
125197
125216
|
class FileSystemProvider {
|
|
@@ -125319,7 +125338,7 @@ class FileSystemProvider {
|
|
|
125319
125338
|
}
|
|
125320
125339
|
return results;
|
|
125321
125340
|
}
|
|
125322
|
-
async list(tenantId, prefix, context) {
|
|
125341
|
+
async list(tenantId, prefix, context, options) {
|
|
125323
125342
|
return ErrorHandler.tryCatch(async () => {
|
|
125324
125343
|
const tenantPath = this.getTenantPath(tenantId);
|
|
125325
125344
|
const allKeys = await this.listFilesRecursively(tenantPath, tenantPath);
|
|
@@ -125337,16 +125356,93 @@ class FileSystemProvider {
|
|
|
125337
125356
|
continue;
|
|
125338
125357
|
}
|
|
125339
125358
|
}
|
|
125340
|
-
|
|
125359
|
+
validKeys.sort();
|
|
125360
|
+
const limit2 = options?.limit ?? DEFAULT_LIST_LIMIT;
|
|
125361
|
+
let startIndex = 0;
|
|
125362
|
+
if (options?.cursor) {
|
|
125363
|
+
const cursorIndex = validKeys.indexOf(options.cursor);
|
|
125364
|
+
if (cursorIndex !== -1) {
|
|
125365
|
+
startIndex = cursorIndex + 1;
|
|
125366
|
+
}
|
|
125367
|
+
}
|
|
125368
|
+
const paginatedKeys = validKeys.slice(startIndex, startIndex + limit2);
|
|
125369
|
+
const nextCursor = startIndex + limit2 < validKeys.length ? paginatedKeys[paginatedKeys.length - 1] : undefined;
|
|
125370
|
+
return {
|
|
125371
|
+
keys: paginatedKeys,
|
|
125372
|
+
nextCursor
|
|
125373
|
+
};
|
|
125341
125374
|
}, {
|
|
125342
125375
|
operation: "FileSystemProvider.list",
|
|
125343
125376
|
context,
|
|
125344
125377
|
input: { tenantId, prefix }
|
|
125345
125378
|
});
|
|
125346
125379
|
}
|
|
125380
|
+
async getMany(tenantId, keys, context) {
|
|
125381
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125382
|
+
const results = new Map;
|
|
125383
|
+
for (const key of keys) {
|
|
125384
|
+
const value = await this.get(tenantId, key, context);
|
|
125385
|
+
if (value !== null) {
|
|
125386
|
+
results.set(key, value);
|
|
125387
|
+
}
|
|
125388
|
+
}
|
|
125389
|
+
return results;
|
|
125390
|
+
}, {
|
|
125391
|
+
operation: "FileSystemProvider.getMany",
|
|
125392
|
+
context,
|
|
125393
|
+
input: { tenantId, keyCount: keys.length }
|
|
125394
|
+
});
|
|
125395
|
+
}
|
|
125396
|
+
async setMany(tenantId, entries, context, options) {
|
|
125397
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125398
|
+
for (const [key, value] of entries.entries()) {
|
|
125399
|
+
await this.set(tenantId, key, value, context, options);
|
|
125400
|
+
}
|
|
125401
|
+
}, {
|
|
125402
|
+
operation: "FileSystemProvider.setMany",
|
|
125403
|
+
context,
|
|
125404
|
+
input: { tenantId, entryCount: entries.size }
|
|
125405
|
+
});
|
|
125406
|
+
}
|
|
125407
|
+
async deleteMany(tenantId, keys, context) {
|
|
125408
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125409
|
+
let deletedCount = 0;
|
|
125410
|
+
for (const key of keys) {
|
|
125411
|
+
const deleted = await this.delete(tenantId, key, context);
|
|
125412
|
+
if (deleted) {
|
|
125413
|
+
deletedCount++;
|
|
125414
|
+
}
|
|
125415
|
+
}
|
|
125416
|
+
return deletedCount;
|
|
125417
|
+
}, {
|
|
125418
|
+
operation: "FileSystemProvider.deleteMany",
|
|
125419
|
+
context,
|
|
125420
|
+
input: { tenantId, keyCount: keys.length }
|
|
125421
|
+
});
|
|
125422
|
+
}
|
|
125423
|
+
async clear(tenantId, context) {
|
|
125424
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125425
|
+
const tenantPath = this.getTenantPath(tenantId);
|
|
125426
|
+
const allKeys = await this.listFilesRecursively(tenantPath, tenantPath);
|
|
125427
|
+
let deletedCount = 0;
|
|
125428
|
+
for (const key of allKeys) {
|
|
125429
|
+
const deleted = await this.delete(tenantId, key, context);
|
|
125430
|
+
if (deleted) {
|
|
125431
|
+
deletedCount++;
|
|
125432
|
+
}
|
|
125433
|
+
}
|
|
125434
|
+
return deletedCount;
|
|
125435
|
+
}, {
|
|
125436
|
+
operation: "FileSystemProvider.clear",
|
|
125437
|
+
context,
|
|
125438
|
+
input: { tenantId }
|
|
125439
|
+
});
|
|
125440
|
+
}
|
|
125347
125441
|
}
|
|
125348
125442
|
|
|
125349
125443
|
// src/storage/providers/inMemory/inMemoryProvider.ts
|
|
125444
|
+
var DEFAULT_LIST_LIMIT2 = 1000;
|
|
125445
|
+
|
|
125350
125446
|
class InMemoryProvider {
|
|
125351
125447
|
store = new Map;
|
|
125352
125448
|
getTenantStore(tenantId) {
|
|
@@ -125386,21 +125482,71 @@ class InMemoryProvider {
|
|
|
125386
125482
|
const tenantStore = this.getTenantStore(tenantId);
|
|
125387
125483
|
return Promise.resolve(tenantStore.delete(key));
|
|
125388
125484
|
}
|
|
125389
|
-
list(tenantId, prefix, context) {
|
|
125390
|
-
logger.debug(`[InMemoryProvider] Listing keys with prefix: ${prefix} for tenant: ${tenantId}`, context);
|
|
125485
|
+
list(tenantId, prefix, context, options) {
|
|
125486
|
+
logger.debug(`[InMemoryProvider] Listing keys with prefix: ${prefix} for tenant: ${tenantId}`, { ...context, options });
|
|
125391
125487
|
const tenantStore = this.getTenantStore(tenantId);
|
|
125392
125488
|
const now = Date.now();
|
|
125393
|
-
const
|
|
125489
|
+
const allKeys = [];
|
|
125394
125490
|
for (const [key, entry] of tenantStore.entries()) {
|
|
125395
125491
|
if (key.startsWith(prefix)) {
|
|
125396
125492
|
if (entry.expiresAt && now > entry.expiresAt) {
|
|
125397
125493
|
tenantStore.delete(key);
|
|
125398
125494
|
} else {
|
|
125399
|
-
|
|
125495
|
+
allKeys.push(key);
|
|
125400
125496
|
}
|
|
125401
125497
|
}
|
|
125402
125498
|
}
|
|
125403
|
-
|
|
125499
|
+
allKeys.sort();
|
|
125500
|
+
const limit2 = options?.limit ?? DEFAULT_LIST_LIMIT2;
|
|
125501
|
+
let startIndex = 0;
|
|
125502
|
+
if (options?.cursor) {
|
|
125503
|
+
const cursorIndex = allKeys.indexOf(options.cursor);
|
|
125504
|
+
if (cursorIndex !== -1) {
|
|
125505
|
+
startIndex = cursorIndex + 1;
|
|
125506
|
+
}
|
|
125507
|
+
}
|
|
125508
|
+
const paginatedKeys = allKeys.slice(startIndex, startIndex + limit2);
|
|
125509
|
+
const nextCursor = startIndex + limit2 < allKeys.length ? paginatedKeys[paginatedKeys.length - 1] : undefined;
|
|
125510
|
+
return Promise.resolve({
|
|
125511
|
+
keys: paginatedKeys,
|
|
125512
|
+
nextCursor
|
|
125513
|
+
});
|
|
125514
|
+
}
|
|
125515
|
+
async getMany(tenantId, keys, context) {
|
|
125516
|
+
logger.debug(`[InMemoryProvider] Getting ${keys.length} keys for tenant: ${tenantId}`, context);
|
|
125517
|
+
const results = new Map;
|
|
125518
|
+
for (const key of keys) {
|
|
125519
|
+
const value = await this.get(tenantId, key, context);
|
|
125520
|
+
if (value !== null) {
|
|
125521
|
+
results.set(key, value);
|
|
125522
|
+
}
|
|
125523
|
+
}
|
|
125524
|
+
return results;
|
|
125525
|
+
}
|
|
125526
|
+
async setMany(tenantId, entries, context, options) {
|
|
125527
|
+
logger.debug(`[InMemoryProvider] Setting ${entries.size} keys for tenant: ${tenantId}`, context);
|
|
125528
|
+
for (const [key, value] of entries.entries()) {
|
|
125529
|
+
await this.set(tenantId, key, value, context, options);
|
|
125530
|
+
}
|
|
125531
|
+
}
|
|
125532
|
+
async deleteMany(tenantId, keys, context) {
|
|
125533
|
+
logger.debug(`[InMemoryProvider] Deleting ${keys.length} keys for tenant: ${tenantId}`, context);
|
|
125534
|
+
let deletedCount = 0;
|
|
125535
|
+
for (const key of keys) {
|
|
125536
|
+
const deleted = await this.delete(tenantId, key, context);
|
|
125537
|
+
if (deleted) {
|
|
125538
|
+
deletedCount++;
|
|
125539
|
+
}
|
|
125540
|
+
}
|
|
125541
|
+
return deletedCount;
|
|
125542
|
+
}
|
|
125543
|
+
clear(tenantId, context) {
|
|
125544
|
+
logger.debug(`[InMemoryProvider] Clearing all keys for tenant: ${tenantId}`, context);
|
|
125545
|
+
const tenantStore = this.getTenantStore(tenantId);
|
|
125546
|
+
const count = tenantStore.size;
|
|
125547
|
+
tenantStore.clear();
|
|
125548
|
+
logger.info(`[InMemoryProvider] Cleared ${count} keys for tenant: ${tenantId}`, context);
|
|
125549
|
+
return Promise.resolve(count);
|
|
125404
125550
|
}
|
|
125405
125551
|
}
|
|
125406
125552
|
|
|
@@ -125408,6 +125554,7 @@ class InMemoryProvider {
|
|
|
125408
125554
|
var import_tsyringe4 = __toESM(require_cjs3(), 1);
|
|
125409
125555
|
var import_supabase_js = __toESM(require_main6(), 1);
|
|
125410
125556
|
var TABLE_NAME = "kv_store";
|
|
125557
|
+
var DEFAULT_LIST_LIMIT3 = 1000;
|
|
125411
125558
|
|
|
125412
125559
|
class SupabaseProvider {
|
|
125413
125560
|
client;
|
|
@@ -125467,17 +125614,101 @@ class SupabaseProvider {
|
|
|
125467
125614
|
input: { tenantId, key }
|
|
125468
125615
|
});
|
|
125469
125616
|
}
|
|
125470
|
-
async list(tenantId, prefix, context) {
|
|
125617
|
+
async list(tenantId, prefix, context, options) {
|
|
125471
125618
|
return ErrorHandler.tryCatch(async () => {
|
|
125472
125619
|
const now = new Date().toISOString();
|
|
125473
|
-
const
|
|
125620
|
+
const limit2 = options?.limit ?? DEFAULT_LIST_LIMIT3;
|
|
125621
|
+
let query = this.getClient().from(TABLE_NAME).select("key").eq("tenant_id", tenantId).like("key", `${prefix}%`).or(`expires_at.is.null,expires_at.gt.${now}`).order("key", { ascending: true }).limit(limit2 + 1);
|
|
125622
|
+
if (options?.cursor) {
|
|
125623
|
+
query = query.gt("key", options.cursor);
|
|
125624
|
+
}
|
|
125625
|
+
const { data, error: error2 } = await query;
|
|
125474
125626
|
if (error2)
|
|
125475
125627
|
throw error2;
|
|
125476
|
-
|
|
125628
|
+
const keys = data?.map((item) => item.key) ?? [];
|
|
125629
|
+
const hasMore = keys.length > limit2;
|
|
125630
|
+
const resultKeys = hasMore ? keys.slice(0, limit2) : keys;
|
|
125631
|
+
const nextCursor = hasMore ? resultKeys[resultKeys.length - 1] : undefined;
|
|
125632
|
+
return {
|
|
125633
|
+
keys: resultKeys,
|
|
125634
|
+
nextCursor
|
|
125635
|
+
};
|
|
125477
125636
|
}, {
|
|
125478
125637
|
operation: "SupabaseProvider.list",
|
|
125479
125638
|
context,
|
|
125480
|
-
input: { tenantId, prefix }
|
|
125639
|
+
input: { tenantId, prefix, options }
|
|
125640
|
+
});
|
|
125641
|
+
}
|
|
125642
|
+
async getMany(tenantId, keys, context) {
|
|
125643
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125644
|
+
if (keys.length === 0) {
|
|
125645
|
+
return new Map;
|
|
125646
|
+
}
|
|
125647
|
+
const { data, error: error2 } = await this.getClient().from(TABLE_NAME).select("key, value, expires_at").eq("tenant_id", tenantId).in("key", keys);
|
|
125648
|
+
if (error2)
|
|
125649
|
+
throw error2;
|
|
125650
|
+
const results = new Map;
|
|
125651
|
+
for (const row of data ?? []) {
|
|
125652
|
+
if (!row.expires_at || new Date(row.expires_at).getTime() >= Date.now()) {
|
|
125653
|
+
results.set(row.key, row.value);
|
|
125654
|
+
} else {
|
|
125655
|
+
await this.delete(tenantId, row.key, context);
|
|
125656
|
+
}
|
|
125657
|
+
}
|
|
125658
|
+
return results;
|
|
125659
|
+
}, {
|
|
125660
|
+
operation: "SupabaseProvider.getMany",
|
|
125661
|
+
context,
|
|
125662
|
+
input: { tenantId, keyCount: keys.length }
|
|
125663
|
+
});
|
|
125664
|
+
}
|
|
125665
|
+
async setMany(tenantId, entries, context, options) {
|
|
125666
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125667
|
+
if (entries.size === 0) {
|
|
125668
|
+
return;
|
|
125669
|
+
}
|
|
125670
|
+
const expires_at = options?.ttl ? new Date(Date.now() + options.ttl * 1000).toISOString() : null;
|
|
125671
|
+
const rows = Array.from(entries.entries()).map(([key, value]) => ({
|
|
125672
|
+
tenant_id: tenantId,
|
|
125673
|
+
key,
|
|
125674
|
+
value,
|
|
125675
|
+
expires_at
|
|
125676
|
+
}));
|
|
125677
|
+
const { error: error2 } = await this.getClient().from(TABLE_NAME).upsert(rows);
|
|
125678
|
+
if (error2)
|
|
125679
|
+
throw error2;
|
|
125680
|
+
}, {
|
|
125681
|
+
operation: "SupabaseProvider.setMany",
|
|
125682
|
+
context,
|
|
125683
|
+
input: { tenantId, entryCount: entries.size }
|
|
125684
|
+
});
|
|
125685
|
+
}
|
|
125686
|
+
async deleteMany(tenantId, keys, context) {
|
|
125687
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125688
|
+
if (keys.length === 0) {
|
|
125689
|
+
return 0;
|
|
125690
|
+
}
|
|
125691
|
+
const { error: error2, count } = await this.getClient().from(TABLE_NAME).delete({ count: "exact" }).eq("tenant_id", tenantId).in("key", keys);
|
|
125692
|
+
if (error2)
|
|
125693
|
+
throw error2;
|
|
125694
|
+
return count ?? 0;
|
|
125695
|
+
}, {
|
|
125696
|
+
operation: "SupabaseProvider.deleteMany",
|
|
125697
|
+
context,
|
|
125698
|
+
input: { tenantId, keyCount: keys.length }
|
|
125699
|
+
});
|
|
125700
|
+
}
|
|
125701
|
+
async clear(tenantId, context) {
|
|
125702
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125703
|
+
const { error: error2, count } = await this.getClient().from(TABLE_NAME).delete({ count: "exact" }).eq("tenant_id", tenantId);
|
|
125704
|
+
if (error2)
|
|
125705
|
+
throw error2;
|
|
125706
|
+
logger.info(`[SupabaseProvider] Cleared ${count ?? 0} keys for tenant: ${tenantId}`, context);
|
|
125707
|
+
return count ?? 0;
|
|
125708
|
+
}, {
|
|
125709
|
+
operation: "SupabaseProvider.clear",
|
|
125710
|
+
context,
|
|
125711
|
+
input: { tenantId }
|
|
125481
125712
|
});
|
|
125482
125713
|
}
|
|
125483
125714
|
}
|
|
@@ -125491,10 +125722,14 @@ SupabaseProvider = __legacyDecorateClassTS([
|
|
|
125491
125722
|
|
|
125492
125723
|
// src/storage/providers/cloudflare/r2Provider.ts
|
|
125493
125724
|
var R2_ENVELOPE_VERSION = 1;
|
|
125725
|
+
var DEFAULT_LIST_LIMIT4 = 1000;
|
|
125494
125726
|
|
|
125495
125727
|
class R2Provider {
|
|
125496
125728
|
bucket;
|
|
125497
125729
|
constructor(bucket) {
|
|
125730
|
+
if (!bucket) {
|
|
125731
|
+
throw new McpError(-32008 /* ConfigurationError */, "R2Provider requires a valid R2Bucket instance.");
|
|
125732
|
+
}
|
|
125498
125733
|
this.bucket = bucket;
|
|
125499
125734
|
}
|
|
125500
125735
|
getR2Key(tenantId, key) {
|
|
@@ -125579,27 +125814,115 @@ class R2Provider {
|
|
|
125579
125814
|
input: { tenantId, key }
|
|
125580
125815
|
});
|
|
125581
125816
|
}
|
|
125582
|
-
async list(tenantId, prefix, context) {
|
|
125817
|
+
async list(tenantId, prefix, context, options) {
|
|
125583
125818
|
const r2Prefix = this.getR2Key(tenantId, prefix);
|
|
125584
125819
|
return ErrorHandler.tryCatch(async () => {
|
|
125585
|
-
logger.debug(`[R2Provider] Listing keys with prefix: ${r2Prefix}`,
|
|
125586
|
-
|
|
125820
|
+
logger.debug(`[R2Provider] Listing keys with prefix: ${r2Prefix}`, {
|
|
125821
|
+
...context,
|
|
125822
|
+
options
|
|
125823
|
+
});
|
|
125824
|
+
const limit2 = options?.limit ?? DEFAULT_LIST_LIMIT4;
|
|
125825
|
+
const listOptions = {
|
|
125826
|
+
prefix: r2Prefix,
|
|
125827
|
+
limit: limit2 + 1
|
|
125828
|
+
};
|
|
125829
|
+
if (options?.cursor) {
|
|
125830
|
+
listOptions.cursor = options.cursor;
|
|
125831
|
+
}
|
|
125832
|
+
const listed = await this.bucket.list(listOptions);
|
|
125587
125833
|
const tenantPrefix = `${tenantId}:`;
|
|
125588
125834
|
const keys = listed.objects.map((obj) => obj.key.startsWith(tenantPrefix) ? obj.key.substring(tenantPrefix.length) : obj.key);
|
|
125589
|
-
|
|
125590
|
-
|
|
125835
|
+
const hasMore = keys.length > limit2;
|
|
125836
|
+
const resultKeys = hasMore ? keys.slice(0, limit2) : keys;
|
|
125837
|
+
const nextCursor = "cursor" in listed && listed.truncated ? listed.cursor : undefined;
|
|
125838
|
+
logger.debug(`[R2Provider] Found ${resultKeys.length} keys with prefix: ${r2Prefix}`, context);
|
|
125839
|
+
return {
|
|
125840
|
+
keys: resultKeys,
|
|
125841
|
+
nextCursor
|
|
125842
|
+
};
|
|
125591
125843
|
}, {
|
|
125592
125844
|
operation: "R2Provider.list",
|
|
125593
125845
|
context,
|
|
125594
|
-
input: { tenantId, prefix }
|
|
125846
|
+
input: { tenantId, prefix, options }
|
|
125847
|
+
});
|
|
125848
|
+
}
|
|
125849
|
+
async getMany(tenantId, keys, context) {
|
|
125850
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125851
|
+
const results = new Map;
|
|
125852
|
+
for (const key of keys) {
|
|
125853
|
+
const value = await this.get(tenantId, key, context);
|
|
125854
|
+
if (value !== null) {
|
|
125855
|
+
results.set(key, value);
|
|
125856
|
+
}
|
|
125857
|
+
}
|
|
125858
|
+
return results;
|
|
125859
|
+
}, {
|
|
125860
|
+
operation: "R2Provider.getMany",
|
|
125861
|
+
context,
|
|
125862
|
+
input: { tenantId, keyCount: keys.length }
|
|
125863
|
+
});
|
|
125864
|
+
}
|
|
125865
|
+
async setMany(tenantId, entries, context, options) {
|
|
125866
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125867
|
+
const promises = Array.from(entries.entries()).map(([key, value]) => this.set(tenantId, key, value, context, options));
|
|
125868
|
+
await Promise.all(promises);
|
|
125869
|
+
}, {
|
|
125870
|
+
operation: "R2Provider.setMany",
|
|
125871
|
+
context,
|
|
125872
|
+
input: { tenantId, entryCount: entries.size }
|
|
125873
|
+
});
|
|
125874
|
+
}
|
|
125875
|
+
async deleteMany(tenantId, keys, context) {
|
|
125876
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125877
|
+
const promises = keys.map((key) => this.delete(tenantId, key, context));
|
|
125878
|
+
const results = await Promise.all(promises);
|
|
125879
|
+
return results.filter((deleted) => deleted).length;
|
|
125880
|
+
}, {
|
|
125881
|
+
operation: "R2Provider.deleteMany",
|
|
125882
|
+
context,
|
|
125883
|
+
input: { tenantId, keyCount: keys.length }
|
|
125884
|
+
});
|
|
125885
|
+
}
|
|
125886
|
+
async clear(tenantId, context) {
|
|
125887
|
+
return ErrorHandler.tryCatch(async () => {
|
|
125888
|
+
const r2Prefix = `${tenantId}:`;
|
|
125889
|
+
let deletedCount = 0;
|
|
125890
|
+
let cursor;
|
|
125891
|
+
let hasMore = true;
|
|
125892
|
+
while (hasMore) {
|
|
125893
|
+
const listOpts = {
|
|
125894
|
+
prefix: r2Prefix,
|
|
125895
|
+
limit: 1000
|
|
125896
|
+
};
|
|
125897
|
+
if (cursor) {
|
|
125898
|
+
listOpts.cursor = cursor;
|
|
125899
|
+
}
|
|
125900
|
+
const listed = await this.bucket.list(listOpts);
|
|
125901
|
+
const deletePromises = listed.objects.map((obj) => this.bucket.delete(obj.key));
|
|
125902
|
+
await Promise.all(deletePromises);
|
|
125903
|
+
deletedCount += listed.objects.length;
|
|
125904
|
+
hasMore = listed.truncated;
|
|
125905
|
+
cursor = "cursor" in listed ? listed.cursor : undefined;
|
|
125906
|
+
}
|
|
125907
|
+
logger.info(`[R2Provider] Cleared ${deletedCount} keys for tenant: ${tenantId}`, context);
|
|
125908
|
+
return deletedCount;
|
|
125909
|
+
}, {
|
|
125910
|
+
operation: "R2Provider.clear",
|
|
125911
|
+
context,
|
|
125912
|
+
input: { tenantId }
|
|
125595
125913
|
});
|
|
125596
125914
|
}
|
|
125597
125915
|
}
|
|
125598
125916
|
|
|
125599
125917
|
// src/storage/providers/cloudflare/kvProvider.ts
|
|
125918
|
+
var DEFAULT_LIST_LIMIT5 = 1000;
|
|
125919
|
+
|
|
125600
125920
|
class KvProvider {
|
|
125601
125921
|
kv;
|
|
125602
125922
|
constructor(kv) {
|
|
125923
|
+
if (!kv) {
|
|
125924
|
+
throw new McpError(-32008 /* ConfigurationError */, "KvProvider requires a valid KVNamespace instance.");
|
|
125925
|
+
}
|
|
125603
125926
|
this.kv = kv;
|
|
125604
125927
|
}
|
|
125605
125928
|
getKvKey(tenantId, key) {
|
|
@@ -125659,19 +125982,100 @@ class KvProvider {
|
|
|
125659
125982
|
input: { tenantId, key }
|
|
125660
125983
|
});
|
|
125661
125984
|
}
|
|
125662
|
-
async list(tenantId, prefix, context) {
|
|
125985
|
+
async list(tenantId, prefix, context, options) {
|
|
125663
125986
|
const kvPrefix = this.getKvKey(tenantId, prefix);
|
|
125664
125987
|
return ErrorHandler.tryCatch(async () => {
|
|
125665
|
-
logger.debug(`[KvProvider] Listing keys with prefix: ${kvPrefix}`,
|
|
125666
|
-
|
|
125988
|
+
logger.debug(`[KvProvider] Listing keys with prefix: ${kvPrefix}`, {
|
|
125989
|
+
...context,
|
|
125990
|
+
options
|
|
125991
|
+
});
|
|
125992
|
+
const limit2 = options?.limit ?? DEFAULT_LIST_LIMIT5;
|
|
125993
|
+
const listOptions = {
|
|
125994
|
+
prefix: kvPrefix,
|
|
125995
|
+
limit: limit2
|
|
125996
|
+
};
|
|
125997
|
+
if (options?.cursor) {
|
|
125998
|
+
listOptions.cursor = options.cursor;
|
|
125999
|
+
}
|
|
126000
|
+
const listed = await this.kv.list(listOptions);
|
|
125667
126001
|
const tenantPrefix = `${tenantId}:`;
|
|
125668
126002
|
const keys = listed.keys.map((keyInfo) => keyInfo.name.startsWith(tenantPrefix) ? keyInfo.name.substring(tenantPrefix.length) : keyInfo.name);
|
|
126003
|
+
const nextCursor = "cursor" in listed && !listed.list_complete ? listed.cursor : undefined;
|
|
125669
126004
|
logger.debug(`[KvProvider] Found ${keys.length} keys with prefix: ${kvPrefix}`, context);
|
|
125670
|
-
return
|
|
126005
|
+
return {
|
|
126006
|
+
keys,
|
|
126007
|
+
nextCursor
|
|
126008
|
+
};
|
|
125671
126009
|
}, {
|
|
125672
126010
|
operation: "KvProvider.list",
|
|
125673
126011
|
context,
|
|
125674
|
-
input: { tenantId, prefix }
|
|
126012
|
+
input: { tenantId, prefix, options }
|
|
126013
|
+
});
|
|
126014
|
+
}
|
|
126015
|
+
async getMany(tenantId, keys, context) {
|
|
126016
|
+
return ErrorHandler.tryCatch(async () => {
|
|
126017
|
+
const results = new Map;
|
|
126018
|
+
for (const key of keys) {
|
|
126019
|
+
const value = await this.get(tenantId, key, context);
|
|
126020
|
+
if (value !== null) {
|
|
126021
|
+
results.set(key, value);
|
|
126022
|
+
}
|
|
126023
|
+
}
|
|
126024
|
+
return results;
|
|
126025
|
+
}, {
|
|
126026
|
+
operation: "KvProvider.getMany",
|
|
126027
|
+
context,
|
|
126028
|
+
input: { tenantId, keyCount: keys.length }
|
|
126029
|
+
});
|
|
126030
|
+
}
|
|
126031
|
+
async setMany(tenantId, entries, context, options) {
|
|
126032
|
+
return ErrorHandler.tryCatch(async () => {
|
|
126033
|
+
const promises = Array.from(entries.entries()).map(([key, value]) => this.set(tenantId, key, value, context, options));
|
|
126034
|
+
await Promise.all(promises);
|
|
126035
|
+
}, {
|
|
126036
|
+
operation: "KvProvider.setMany",
|
|
126037
|
+
context,
|
|
126038
|
+
input: { tenantId, entryCount: entries.size }
|
|
126039
|
+
});
|
|
126040
|
+
}
|
|
126041
|
+
async deleteMany(tenantId, keys, context) {
|
|
126042
|
+
return ErrorHandler.tryCatch(async () => {
|
|
126043
|
+
const promises = keys.map((key) => this.delete(tenantId, key, context));
|
|
126044
|
+
const results = await Promise.all(promises);
|
|
126045
|
+
return results.filter((deleted) => deleted).length;
|
|
126046
|
+
}, {
|
|
126047
|
+
operation: "KvProvider.deleteMany",
|
|
126048
|
+
context,
|
|
126049
|
+
input: { tenantId, keyCount: keys.length }
|
|
126050
|
+
});
|
|
126051
|
+
}
|
|
126052
|
+
async clear(tenantId, context) {
|
|
126053
|
+
return ErrorHandler.tryCatch(async () => {
|
|
126054
|
+
const kvPrefix = `${tenantId}:`;
|
|
126055
|
+
let deletedCount = 0;
|
|
126056
|
+
let cursor;
|
|
126057
|
+
let listComplete = false;
|
|
126058
|
+
while (!listComplete) {
|
|
126059
|
+
const listOpts = {
|
|
126060
|
+
prefix: kvPrefix,
|
|
126061
|
+
limit: 1000
|
|
126062
|
+
};
|
|
126063
|
+
if (cursor) {
|
|
126064
|
+
listOpts.cursor = cursor;
|
|
126065
|
+
}
|
|
126066
|
+
const listed = await this.kv.list(listOpts);
|
|
126067
|
+
const deletePromises = listed.keys.map((keyInfo) => this.kv.delete(keyInfo.name));
|
|
126068
|
+
await Promise.all(deletePromises);
|
|
126069
|
+
deletedCount += listed.keys.length;
|
|
126070
|
+
listComplete = listed.list_complete;
|
|
126071
|
+
cursor = "cursor" in listed ? listed.cursor : undefined;
|
|
126072
|
+
}
|
|
126073
|
+
logger.info(`[KvProvider] Cleared ${deletedCount} keys for tenant: ${tenantId}`, context);
|
|
126074
|
+
return deletedCount;
|
|
126075
|
+
}, {
|
|
126076
|
+
operation: "KvProvider.clear",
|
|
126077
|
+
context,
|
|
126078
|
+
input: { tenantId }
|
|
125675
126079
|
});
|
|
125676
126080
|
}
|
|
125677
126081
|
}
|
|
@@ -125751,7 +126155,7 @@ var registerCoreServices = () => {
|
|
|
125751
126155
|
};
|
|
125752
126156
|
|
|
125753
126157
|
// src/container/registrations/mcp.ts
|
|
125754
|
-
var
|
|
126158
|
+
var import_tsyringe16 = __toESM(require_cjs3(), 1);
|
|
125755
126159
|
|
|
125756
126160
|
// src/mcp-server/resources/resource-registration.ts
|
|
125757
126161
|
var import_tsyringe7 = __toESM(require_cjs3(), 1);
|
|
@@ -129162,10 +129566,133 @@ var registerResources = (container3) => {
|
|
|
129162
129566
|
};
|
|
129163
129567
|
|
|
129164
129568
|
// src/mcp-server/server.ts
|
|
129569
|
+
var import_tsyringe11 = __toESM(require_cjs3(), 1);
|
|
129570
|
+
|
|
129571
|
+
// src/mcp-server/prompts/prompt-registration.ts
|
|
129572
|
+
var import_tsyringe8 = __toESM(require_cjs3(), 1);
|
|
129573
|
+
|
|
129574
|
+
// src/mcp-server/prompts/definitions/code-review.prompt.ts
|
|
129575
|
+
var PROMPT_NAME = "code_review";
|
|
129576
|
+
var PROMPT_DESCRIPTION = "Generates a structured code review prompt for analyzing code quality, security, and performance.";
|
|
129577
|
+
var ArgumentsSchema = z.object({
|
|
129578
|
+
language: z.string().optional().describe("Programming language of the code to review."),
|
|
129579
|
+
focus: z.string().optional().describe("The primary focus area for the code review ('security' | 'performance' | 'style' | 'general'). Defaults to 'general'."),
|
|
129580
|
+
includeExamples: z.string().optional().describe("Whether to include example improvements in the review ('true' | 'false'). Defaults to 'false'.")
|
|
129581
|
+
});
|
|
129582
|
+
var codeReviewPrompt = {
|
|
129583
|
+
name: PROMPT_NAME,
|
|
129584
|
+
description: PROMPT_DESCRIPTION,
|
|
129585
|
+
argumentsSchema: ArgumentsSchema,
|
|
129586
|
+
generate: (args) => {
|
|
129587
|
+
const focus = args.focus || "general";
|
|
129588
|
+
const includeExamples = args.includeExamples === "true";
|
|
129589
|
+
const focusGuidance = {
|
|
129590
|
+
security: `- Security vulnerabilities and potential exploits
|
|
129591
|
+
- Input validation and sanitization
|
|
129592
|
+
- Authentication and authorization issues
|
|
129593
|
+
- Data exposure risks`,
|
|
129594
|
+
performance: `- Algorithmic complexity and bottlenecks
|
|
129595
|
+
- Memory usage and leaks
|
|
129596
|
+
- Database query optimization
|
|
129597
|
+
- Caching opportunities`,
|
|
129598
|
+
style: `- Code readability and clarity
|
|
129599
|
+
- Naming conventions
|
|
129600
|
+
- Code organization and structure
|
|
129601
|
+
- Documentation completeness`,
|
|
129602
|
+
general: `- Overall code quality
|
|
129603
|
+
- Security considerations
|
|
129604
|
+
- Performance implications
|
|
129605
|
+
- Maintainability and readability`
|
|
129606
|
+
};
|
|
129607
|
+
const examplesSection = includeExamples ? `
|
|
129608
|
+
|
|
129609
|
+
For each significant finding, provide a concrete example of how to improve the code.` : "";
|
|
129610
|
+
return [
|
|
129611
|
+
{
|
|
129612
|
+
role: "user",
|
|
129613
|
+
content: {
|
|
129614
|
+
type: "text",
|
|
129615
|
+
text: `You are an expert code reviewer${args.language ? ` specializing in ${args.language}` : ""}. Please conduct a thorough code review with a focus on ${focus}.
|
|
129616
|
+
|
|
129617
|
+
Review the code for:
|
|
129618
|
+
${focusGuidance[focus] || focusGuidance["general"]}
|
|
129619
|
+
|
|
129620
|
+
Structure your review as follows:
|
|
129621
|
+
1. **Summary**: 2-3 sentence overview of the code's quality
|
|
129622
|
+
2. **Key Findings**: Bullet-point list of important observations
|
|
129623
|
+
3. **Critical Issues**: Any must-fix problems (if found)
|
|
129624
|
+
4. **Recommendations**: Suggested improvements prioritized by impact${examplesSection}
|
|
129625
|
+
|
|
129626
|
+
Be constructive, specific, and actionable in your feedback.`
|
|
129627
|
+
}
|
|
129628
|
+
}
|
|
129629
|
+
];
|
|
129630
|
+
}
|
|
129631
|
+
};
|
|
129632
|
+
|
|
129633
|
+
// src/mcp-server/prompts/definitions/index.ts
|
|
129634
|
+
var allPromptDefinitions = [codeReviewPrompt];
|
|
129635
|
+
|
|
129636
|
+
// src/mcp-server/prompts/prompt-registration.ts
|
|
129637
|
+
class PromptRegistry {
|
|
129638
|
+
logger;
|
|
129639
|
+
constructor(logger2) {
|
|
129640
|
+
this.logger = logger2;
|
|
129641
|
+
}
|
|
129642
|
+
registerAll(server) {
|
|
129643
|
+
const context = requestContextService.createRequestContext({
|
|
129644
|
+
operation: "PromptRegistry.registerAll"
|
|
129645
|
+
});
|
|
129646
|
+
this.logger.debug(`Registering ${allPromptDefinitions.length} prompts...`, context);
|
|
129647
|
+
for (const promptDef of allPromptDefinitions) {
|
|
129648
|
+
this.logger.debug(`Registering prompt: ${promptDef.name}`, context);
|
|
129649
|
+
server.registerPrompt(promptDef.name, {
|
|
129650
|
+
description: promptDef.description,
|
|
129651
|
+
...promptDef.argumentsSchema && {
|
|
129652
|
+
argsSchema: promptDef.argumentsSchema.shape
|
|
129653
|
+
}
|
|
129654
|
+
}, async (args) => {
|
|
129655
|
+
const messages = await promptDef.generate(args);
|
|
129656
|
+
return { messages };
|
|
129657
|
+
});
|
|
129658
|
+
this.logger.info(`Registered prompt: ${promptDef.name}`, context);
|
|
129659
|
+
}
|
|
129660
|
+
this.logger.info(`Successfully registered ${allPromptDefinitions.length} prompts`, context);
|
|
129661
|
+
}
|
|
129662
|
+
}
|
|
129663
|
+
PromptRegistry = __legacyDecorateClassTS([
|
|
129664
|
+
import_tsyringe8.injectable(),
|
|
129665
|
+
__legacyDecorateParamTS(0, import_tsyringe8.inject(Logger2)),
|
|
129666
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
129667
|
+
Object
|
|
129668
|
+
])
|
|
129669
|
+
], PromptRegistry);
|
|
129670
|
+
|
|
129671
|
+
// src/mcp-server/roots/roots-registration.ts
|
|
129165
129672
|
var import_tsyringe9 = __toESM(require_cjs3(), 1);
|
|
129673
|
+
class RootsRegistry {
|
|
129674
|
+
logger;
|
|
129675
|
+
constructor(logger2) {
|
|
129676
|
+
this.logger = logger2;
|
|
129677
|
+
}
|
|
129678
|
+
registerAll(_server) {
|
|
129679
|
+
const context = requestContextService.createRequestContext({
|
|
129680
|
+
operation: "RootsRegistry.registerAll"
|
|
129681
|
+
});
|
|
129682
|
+
this.logger.debug("Roots capability enabled (client-provided roots)", context);
|
|
129683
|
+
this.logger.info("Roots capability registered successfully", context);
|
|
129684
|
+
}
|
|
129685
|
+
}
|
|
129686
|
+
RootsRegistry = __legacyDecorateClassTS([
|
|
129687
|
+
import_tsyringe9.injectable(),
|
|
129688
|
+
__legacyDecorateParamTS(0, import_tsyringe9.inject(Logger2)),
|
|
129689
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
129690
|
+
Object
|
|
129691
|
+
])
|
|
129692
|
+
], RootsRegistry);
|
|
129166
129693
|
|
|
129167
129694
|
// src/mcp-server/tools/tool-registration.ts
|
|
129168
|
-
var
|
|
129695
|
+
var import_tsyringe10 = __toESM(require_cjs3(), 1);
|
|
129169
129696
|
|
|
129170
129697
|
// src/mcp-server/tools/definitions/template-cat-fact.tool.ts
|
|
129171
129698
|
var TOOL_NAME = "template_cat_fact";
|
|
@@ -129254,11 +129781,136 @@ var catFactTool = {
|
|
|
129254
129781
|
responseFormatter
|
|
129255
129782
|
};
|
|
129256
129783
|
|
|
129257
|
-
// src/mcp-server/tools/definitions/template-
|
|
129258
|
-
var TOOL_NAME2 = "
|
|
129259
|
-
var TOOL_TITLE2 = "
|
|
129260
|
-
var TOOL_DESCRIPTION2 = "
|
|
129784
|
+
// src/mcp-server/tools/definitions/template-code-review-sampling.tool.ts
|
|
129785
|
+
var TOOL_NAME2 = "template_code_review_sampling";
|
|
129786
|
+
var TOOL_TITLE2 = "Code Review with Sampling";
|
|
129787
|
+
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
129788
|
var TOOL_ANNOTATIONS2 = {
|
|
129789
|
+
readOnlyHint: true,
|
|
129790
|
+
idempotentHint: false,
|
|
129791
|
+
openWorldHint: true
|
|
129792
|
+
};
|
|
129793
|
+
var InputSchema2 = z.object({
|
|
129794
|
+
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."),
|
|
129795
|
+
language: z.string().optional().describe('Programming language of the code (e.g., "typescript", "python").'),
|
|
129796
|
+
focus: z.enum(["security", "performance", "style", "general"]).default("general").describe("The focus area for the code review."),
|
|
129797
|
+
maxTokens: z.number().int().min(100).max(2000).default(500).describe("Maximum tokens for the LLM response.")
|
|
129798
|
+
}).describe("Request an LLM-powered code review via sampling.");
|
|
129799
|
+
var OutputSchema3 = z.object({
|
|
129800
|
+
code: z.string().describe("The original code snippet."),
|
|
129801
|
+
language: z.string().optional().describe("The programming language."),
|
|
129802
|
+
focus: z.string().describe("The review focus area."),
|
|
129803
|
+
review: z.string().describe("The LLM-generated code review summary."),
|
|
129804
|
+
tokenUsage: z.object({
|
|
129805
|
+
requested: z.number().describe("Requested max tokens."),
|
|
129806
|
+
actual: z.number().optional().describe("Actual tokens used (if available).")
|
|
129807
|
+
}).optional().describe("Token usage information.")
|
|
129808
|
+
}).describe("Code review tool response payload.");
|
|
129809
|
+
function hasSamplingCapability(ctx) {
|
|
129810
|
+
return typeof ctx?.createMessage === "function";
|
|
129811
|
+
}
|
|
129812
|
+
async function codeReviewToolLogic(input, appContext, sdkContext) {
|
|
129813
|
+
logger.debug("Processing code review with sampling.", {
|
|
129814
|
+
...appContext,
|
|
129815
|
+
toolInput: { ...input, code: `${input.code.substring(0, 100)}...` }
|
|
129816
|
+
});
|
|
129817
|
+
if (!hasSamplingCapability(sdkContext)) {
|
|
129818
|
+
throw new McpError(-32600 /* InvalidRequest */, "Sampling capability is not available. The client does not support MCP sampling.", { requestId: appContext.requestId, operation: "codeReview.sample" });
|
|
129819
|
+
}
|
|
129820
|
+
const focusInstructions = {
|
|
129821
|
+
security: "Focus on security vulnerabilities, input validation, and potential exploits.",
|
|
129822
|
+
performance: "Focus on performance bottlenecks, algorithmic complexity, and optimization opportunities.",
|
|
129823
|
+
style: "Focus on code style, readability, naming conventions, and best practices.",
|
|
129824
|
+
general: "Provide a comprehensive review covering security, performance, and code quality."
|
|
129825
|
+
};
|
|
129826
|
+
const prompt = `You are an expert code reviewer. Please review the following ${input.language || "code"} snippet.
|
|
129827
|
+
|
|
129828
|
+
${focusInstructions[input.focus]}
|
|
129829
|
+
|
|
129830
|
+
Provide a concise, structured review with:
|
|
129831
|
+
1. Summary (2-3 sentences)
|
|
129832
|
+
2. Key findings (bullet points)
|
|
129833
|
+
3. Recommendations (if applicable)
|
|
129834
|
+
|
|
129835
|
+
Code to review:
|
|
129836
|
+
\`\`\`${input.language || ""}
|
|
129837
|
+
${input.code}
|
|
129838
|
+
\`\`\`
|
|
129839
|
+
|
|
129840
|
+
Your review:`;
|
|
129841
|
+
logger.debug("Requesting LLM completion via sampling...", {
|
|
129842
|
+
...appContext,
|
|
129843
|
+
maxTokens: input.maxTokens,
|
|
129844
|
+
focus: input.focus
|
|
129845
|
+
});
|
|
129846
|
+
try {
|
|
129847
|
+
const samplingResult = await sdkContext.createMessage({
|
|
129848
|
+
messages: [
|
|
129849
|
+
{
|
|
129850
|
+
role: "user",
|
|
129851
|
+
content: {
|
|
129852
|
+
type: "text",
|
|
129853
|
+
text: prompt
|
|
129854
|
+
}
|
|
129855
|
+
}
|
|
129856
|
+
],
|
|
129857
|
+
maxTokens: input.maxTokens,
|
|
129858
|
+
temperature: 0.3,
|
|
129859
|
+
modelPreferences: {
|
|
129860
|
+
hints: [{ name: "claude-3-5-sonnet-20241022" }],
|
|
129861
|
+
intelligencePriority: 0.8,
|
|
129862
|
+
speedPriority: 0.2
|
|
129863
|
+
}
|
|
129864
|
+
});
|
|
129865
|
+
logger.info("Sampling completed successfully.", {
|
|
129866
|
+
...appContext,
|
|
129867
|
+
model: samplingResult.model,
|
|
129868
|
+
stopReason: samplingResult.stopReason
|
|
129869
|
+
});
|
|
129870
|
+
const response = {
|
|
129871
|
+
code: input.code,
|
|
129872
|
+
language: input.language,
|
|
129873
|
+
focus: input.focus,
|
|
129874
|
+
review: samplingResult.content.text,
|
|
129875
|
+
tokenUsage: {
|
|
129876
|
+
requested: input.maxTokens
|
|
129877
|
+
}
|
|
129878
|
+
};
|
|
129879
|
+
return response;
|
|
129880
|
+
} catch (error2) {
|
|
129881
|
+
logger.error("Sampling request failed.", {
|
|
129882
|
+
...appContext,
|
|
129883
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
129884
|
+
});
|
|
129885
|
+
throw new McpError(-32603 /* InternalError */, `Failed to complete sampling request: ${error2 instanceof Error ? error2.message : "Unknown error"}`, { requestId: appContext.requestId, operation: "codeReview.sample" });
|
|
129886
|
+
}
|
|
129887
|
+
}
|
|
129888
|
+
function responseFormatter2(result) {
|
|
129889
|
+
return [
|
|
129890
|
+
{
|
|
129891
|
+
type: "text",
|
|
129892
|
+
text: `# Code Review (${result.focus})
|
|
129893
|
+
|
|
129894
|
+
${result.review}`
|
|
129895
|
+
}
|
|
129896
|
+
];
|
|
129897
|
+
}
|
|
129898
|
+
var codeReviewSamplingTool = {
|
|
129899
|
+
name: TOOL_NAME2,
|
|
129900
|
+
title: TOOL_TITLE2,
|
|
129901
|
+
description: TOOL_DESCRIPTION2,
|
|
129902
|
+
inputSchema: InputSchema2,
|
|
129903
|
+
outputSchema: OutputSchema3,
|
|
129904
|
+
annotations: TOOL_ANNOTATIONS2,
|
|
129905
|
+
logic: withToolAuth(["tool:code-review:use"], codeReviewToolLogic),
|
|
129906
|
+
responseFormatter: responseFormatter2
|
|
129907
|
+
};
|
|
129908
|
+
|
|
129909
|
+
// src/mcp-server/tools/definitions/template-echo-message.tool.ts
|
|
129910
|
+
var TOOL_NAME3 = "template_echo_message";
|
|
129911
|
+
var TOOL_TITLE3 = "Template Echo Message";
|
|
129912
|
+
var TOOL_DESCRIPTION3 = "Echoes a message back with optional formatting and repetition.";
|
|
129913
|
+
var TOOL_ANNOTATIONS3 = {
|
|
129262
129914
|
readOnlyHint: true,
|
|
129263
129915
|
idempotentHint: true,
|
|
129264
129916
|
openWorldHint: false
|
|
@@ -129268,13 +129920,13 @@ var DEFAULT_MODE = "standard";
|
|
|
129268
129920
|
var DEFAULT_REPEAT = 1;
|
|
129269
129921
|
var DEFAULT_INCLUDE_TIMESTAMP = false;
|
|
129270
129922
|
var TEST_ERROR_TRIGGER_MESSAGE = "TRIGGER_ERROR";
|
|
129271
|
-
var
|
|
129923
|
+
var InputSchema3 = z.object({
|
|
129272
129924
|
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
129925
|
mode: z.enum(ECHO_MODES).default(DEFAULT_MODE).describe("How to format the message ('standard' | 'uppercase' | 'lowercase')."),
|
|
129274
129926
|
repeat: z.number().int().min(1).max(5).default(DEFAULT_REPEAT).describe("Number of times to repeat the formatted message."),
|
|
129275
129927
|
includeTimestamp: z.boolean().default(DEFAULT_INCLUDE_TIMESTAMP).describe("Whether to include an ISO 8601 timestamp in the response.")
|
|
129276
129928
|
}).describe("Echo a message with optional formatting and repetition.");
|
|
129277
|
-
var
|
|
129929
|
+
var OutputSchema4 = z.object({
|
|
129278
129930
|
originalMessage: z.string().describe("The original message provided in the input."),
|
|
129279
129931
|
formattedMessage: z.string().describe("The message after applying the specified formatting."),
|
|
129280
129932
|
repeatedMessage: z.string().describe("The final message repeated the requested number of times."),
|
|
@@ -129308,7 +129960,7 @@ async function echoToolLogic(input, appContext, _sdkContext) {
|
|
|
129308
129960
|
};
|
|
129309
129961
|
return Promise.resolve(response);
|
|
129310
129962
|
}
|
|
129311
|
-
function
|
|
129963
|
+
function responseFormatter3(result) {
|
|
129312
129964
|
const preview = result.repeatedMessage.length > 200 ? `${result.repeatedMessage.slice(0, 197)}…` : result.repeatedMessage;
|
|
129313
129965
|
const lines = [
|
|
129314
129966
|
`Echo (mode=${result.mode}, repeat=${result.repeatCount})`,
|
|
@@ -129324,14 +129976,14 @@ function responseFormatter2(result) {
|
|
|
129324
129976
|
];
|
|
129325
129977
|
}
|
|
129326
129978
|
var echoTool = {
|
|
129327
|
-
name:
|
|
129328
|
-
title:
|
|
129329
|
-
description:
|
|
129330
|
-
inputSchema:
|
|
129331
|
-
outputSchema:
|
|
129332
|
-
annotations:
|
|
129979
|
+
name: TOOL_NAME3,
|
|
129980
|
+
title: TOOL_TITLE3,
|
|
129981
|
+
description: TOOL_DESCRIPTION3,
|
|
129982
|
+
inputSchema: InputSchema3,
|
|
129983
|
+
outputSchema: OutputSchema4,
|
|
129984
|
+
annotations: TOOL_ANNOTATIONS3,
|
|
129333
129985
|
logic: withToolAuth(["tool:echo:read"], echoToolLogic),
|
|
129334
|
-
responseFormatter:
|
|
129986
|
+
responseFormatter: responseFormatter3
|
|
129335
129987
|
};
|
|
129336
129988
|
|
|
129337
129989
|
// src/utils/internal/encoding.ts
|
|
@@ -129350,19 +130002,19 @@ function arrayBufferToBase64(buffer) {
|
|
|
129350
130002
|
}
|
|
129351
130003
|
|
|
129352
130004
|
// src/mcp-server/tools/definitions/template-image-test.tool.ts
|
|
129353
|
-
var
|
|
129354
|
-
var
|
|
129355
|
-
var
|
|
129356
|
-
var
|
|
130005
|
+
var TOOL_NAME4 = "template_image_test";
|
|
130006
|
+
var TOOL_TITLE4 = "Template Image Test";
|
|
130007
|
+
var TOOL_DESCRIPTION4 = "Fetches a random cat image and returns it base64-encoded with the MIME type. Useful for testing image handling.";
|
|
130008
|
+
var TOOL_ANNOTATIONS4 = {
|
|
129357
130009
|
readOnlyHint: true,
|
|
129358
130010
|
openWorldHint: true
|
|
129359
130011
|
};
|
|
129360
130012
|
var CAT_API_URL = "https://cataas.com/cat";
|
|
129361
130013
|
var API_TIMEOUT_MS = 5000;
|
|
129362
|
-
var
|
|
130014
|
+
var InputSchema4 = z.object({
|
|
129363
130015
|
trigger: z.boolean().optional().default(true).describe("A trigger to invoke the tool and fetch a new cat image.")
|
|
129364
130016
|
}).describe("Parameters for fetching a random image.");
|
|
129365
|
-
var
|
|
130017
|
+
var OutputSchema5 = z.object({
|
|
129366
130018
|
data: z.string().describe("Base64 encoded image data."),
|
|
129367
130019
|
mimeType: z.string().describe("The MIME type of the image (e.g., 'image/jpeg').")
|
|
129368
130020
|
}).describe("Image tool response payload.");
|
|
@@ -129398,7 +130050,7 @@ async function imageTestToolLogic(input, appContext, _sdkContext) {
|
|
|
129398
130050
|
});
|
|
129399
130051
|
return result;
|
|
129400
130052
|
}
|
|
129401
|
-
function
|
|
130053
|
+
function responseFormatter4(result) {
|
|
129402
130054
|
return [
|
|
129403
130055
|
{
|
|
129404
130056
|
type: "image",
|
|
@@ -129408,31 +130060,31 @@ function responseFormatter3(result) {
|
|
|
129408
130060
|
];
|
|
129409
130061
|
}
|
|
129410
130062
|
var imageTestTool = {
|
|
129411
|
-
name:
|
|
129412
|
-
title:
|
|
129413
|
-
description:
|
|
129414
|
-
inputSchema:
|
|
129415
|
-
outputSchema:
|
|
129416
|
-
annotations:
|
|
130063
|
+
name: TOOL_NAME4,
|
|
130064
|
+
title: TOOL_TITLE4,
|
|
130065
|
+
description: TOOL_DESCRIPTION4,
|
|
130066
|
+
inputSchema: InputSchema4,
|
|
130067
|
+
outputSchema: OutputSchema5,
|
|
130068
|
+
annotations: TOOL_ANNOTATIONS4,
|
|
129417
130069
|
logic: withToolAuth(["tool:image_test:read"], imageTestToolLogic),
|
|
129418
|
-
responseFormatter:
|
|
130070
|
+
responseFormatter: responseFormatter4
|
|
129419
130071
|
};
|
|
129420
130072
|
|
|
129421
130073
|
// src/mcp-server/tools/definitions/template-madlibs-elicitation.tool.ts
|
|
129422
|
-
var
|
|
129423
|
-
var
|
|
129424
|
-
var
|
|
129425
|
-
var
|
|
130074
|
+
var TOOL_NAME5 = "template_madlibs_elicitation";
|
|
130075
|
+
var TOOL_TITLE5 = "Mad Libs Elicitation Game";
|
|
130076
|
+
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.";
|
|
130077
|
+
var TOOL_ANNOTATIONS5 = {
|
|
129426
130078
|
readOnlyHint: true,
|
|
129427
130079
|
idempotentHint: false,
|
|
129428
130080
|
openWorldHint: false
|
|
129429
130081
|
};
|
|
129430
|
-
var
|
|
130082
|
+
var InputSchema5 = z.object({
|
|
129431
130083
|
noun: z.string().optional().describe("A noun for the story."),
|
|
129432
130084
|
verb: z.string().optional().describe("A verb (past tense) for the story."),
|
|
129433
130085
|
adjective: z.string().optional().describe("An adjective for the story.")
|
|
129434
130086
|
}).describe("Inputs for the Mad Libs game. Any missing fields will be elicited.");
|
|
129435
|
-
var
|
|
130087
|
+
var OutputSchema6 = z.object({
|
|
129436
130088
|
story: z.string().describe("The final, generated Mad Libs story."),
|
|
129437
130089
|
noun: z.string().describe("The noun used in the story."),
|
|
129438
130090
|
verb: z.string().describe("The verb used in the story."),
|
|
@@ -129472,7 +130124,7 @@ async function madlibsToolLogic(input, appContext, sdkContext) {
|
|
|
129472
130124
|
};
|
|
129473
130125
|
return Promise.resolve(response);
|
|
129474
130126
|
}
|
|
129475
|
-
function
|
|
130127
|
+
function responseFormatter5(result) {
|
|
129476
130128
|
return [
|
|
129477
130129
|
{
|
|
129478
130130
|
type: "text",
|
|
@@ -129489,19 +130141,20 @@ function responseFormatter4(result) {
|
|
|
129489
130141
|
];
|
|
129490
130142
|
}
|
|
129491
130143
|
var madlibsElicitationTool = {
|
|
129492
|
-
name:
|
|
129493
|
-
title:
|
|
129494
|
-
description:
|
|
129495
|
-
inputSchema:
|
|
129496
|
-
outputSchema:
|
|
129497
|
-
annotations:
|
|
130144
|
+
name: TOOL_NAME5,
|
|
130145
|
+
title: TOOL_TITLE5,
|
|
130146
|
+
description: TOOL_DESCRIPTION5,
|
|
130147
|
+
inputSchema: InputSchema5,
|
|
130148
|
+
outputSchema: OutputSchema6,
|
|
130149
|
+
annotations: TOOL_ANNOTATIONS5,
|
|
129498
130150
|
logic: withToolAuth(["tool:madlibs:play"], madlibsToolLogic),
|
|
129499
|
-
responseFormatter:
|
|
130151
|
+
responseFormatter: responseFormatter5
|
|
129500
130152
|
};
|
|
129501
130153
|
|
|
129502
130154
|
// src/mcp-server/tools/definitions/index.ts
|
|
129503
130155
|
var allToolDefinitions = [
|
|
129504
130156
|
catFactTool,
|
|
130157
|
+
codeReviewSamplingTool,
|
|
129505
130158
|
echoTool,
|
|
129506
130159
|
imageTestTool,
|
|
129507
130160
|
madlibsElicitationTool
|
|
@@ -129514,7 +130167,7 @@ var defaultResponseFormatter2 = (result) => [
|
|
|
129514
130167
|
function createMcpToolHandler({
|
|
129515
130168
|
toolName,
|
|
129516
130169
|
logic,
|
|
129517
|
-
responseFormatter:
|
|
130170
|
+
responseFormatter: responseFormatter6 = defaultResponseFormatter2
|
|
129518
130171
|
}) {
|
|
129519
130172
|
return async (input, callContext) => {
|
|
129520
130173
|
const sdkContext = callContext;
|
|
@@ -129531,7 +130184,7 @@ function createMcpToolHandler({
|
|
|
129531
130184
|
const result = await measureToolExecution(() => logic(input, appContext, sdkContext), { ...appContext, toolName }, input);
|
|
129532
130185
|
return {
|
|
129533
130186
|
structuredContent: result,
|
|
129534
|
-
content:
|
|
130187
|
+
content: responseFormatter6(result)
|
|
129535
130188
|
};
|
|
129536
130189
|
} catch (error2) {
|
|
129537
130190
|
const mcpError = ErrorHandler.handleError(error2, {
|
|
@@ -129602,8 +130255,8 @@ class ToolRegistry {
|
|
|
129602
130255
|
}
|
|
129603
130256
|
}
|
|
129604
130257
|
ToolRegistry = __legacyDecorateClassTS([
|
|
129605
|
-
|
|
129606
|
-
__legacyDecorateParamTS(0,
|
|
130258
|
+
import_tsyringe10.injectable(),
|
|
130259
|
+
__legacyDecorateParamTS(0, import_tsyringe10.injectAll(ToolDefinitions)),
|
|
129607
130260
|
__legacyMetadataTS("design:paramtypes", [
|
|
129608
130261
|
Array
|
|
129609
130262
|
])
|
|
@@ -129634,18 +130287,25 @@ async function createMcpServerInstance() {
|
|
|
129634
130287
|
logging: {},
|
|
129635
130288
|
resources: { listChanged: true },
|
|
129636
130289
|
tools: { listChanged: true },
|
|
129637
|
-
elicitation: {}
|
|
130290
|
+
elicitation: {},
|
|
130291
|
+
sampling: {},
|
|
130292
|
+
prompts: { listChanged: true },
|
|
130293
|
+
roots: { listChanged: true }
|
|
129638
130294
|
}
|
|
129639
130295
|
});
|
|
129640
130296
|
try {
|
|
129641
|
-
logger.debug("Registering
|
|
129642
|
-
const toolRegistry =
|
|
130297
|
+
logger.debug("Registering all MCP capabilities via registries...", context);
|
|
130298
|
+
const toolRegistry = import_tsyringe11.container.resolve(ToolRegistry);
|
|
129643
130299
|
await toolRegistry.registerAll(server);
|
|
129644
|
-
const resourceRegistry =
|
|
130300
|
+
const resourceRegistry = import_tsyringe11.container.resolve(ResourceRegistry);
|
|
129645
130301
|
await resourceRegistry.registerAll(server);
|
|
129646
|
-
|
|
130302
|
+
const promptRegistry = import_tsyringe11.container.resolve(PromptRegistry);
|
|
130303
|
+
promptRegistry.registerAll(server);
|
|
130304
|
+
const rootsRegistry = import_tsyringe11.container.resolve(RootsRegistry);
|
|
130305
|
+
rootsRegistry.registerAll(server);
|
|
130306
|
+
logger.info("All MCP capabilities registered successfully", context);
|
|
129647
130307
|
} catch (err) {
|
|
129648
|
-
logger.error("Failed to register
|
|
130308
|
+
logger.error("Failed to register MCP capabilities", {
|
|
129649
130309
|
...context,
|
|
129650
130310
|
error: err instanceof Error ? err.message : String(err),
|
|
129651
130311
|
stack: err instanceof Error ? err.stack : undefined
|
|
@@ -129656,7 +130316,7 @@ async function createMcpServerInstance() {
|
|
|
129656
130316
|
}
|
|
129657
130317
|
|
|
129658
130318
|
// src/mcp-server/transports/manager.ts
|
|
129659
|
-
var
|
|
130319
|
+
var import_tsyringe15 = __toESM(require_cjs3(), 1);
|
|
129660
130320
|
|
|
129661
130321
|
// node_modules/hono/dist/http-exception.js
|
|
129662
130322
|
var HTTPException = class extends Error {
|
|
@@ -132324,7 +132984,7 @@ var cors = (options) => {
|
|
|
132324
132984
|
import http from "http";
|
|
132325
132985
|
import { randomUUID } from "node:crypto";
|
|
132326
132986
|
// src/mcp-server/transports/auth/authFactory.ts
|
|
132327
|
-
var
|
|
132987
|
+
var import_tsyringe14 = __toESM(require_cjs3(), 1);
|
|
132328
132988
|
|
|
132329
132989
|
// node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
132330
132990
|
var encoder = new TextEncoder;
|
|
@@ -133842,7 +134502,7 @@ function createRemoteJWKSet(url, options) {
|
|
|
133842
134502
|
return remoteJWKSet;
|
|
133843
134503
|
}
|
|
133844
134504
|
// src/mcp-server/transports/auth/strategies/jwtStrategy.ts
|
|
133845
|
-
var
|
|
134505
|
+
var import_tsyringe12 = __toESM(require_cjs3(), 1);
|
|
133846
134506
|
class JwtStrategy {
|
|
133847
134507
|
config;
|
|
133848
134508
|
logger;
|
|
@@ -133945,9 +134605,9 @@ class JwtStrategy {
|
|
|
133945
134605
|
}
|
|
133946
134606
|
}
|
|
133947
134607
|
JwtStrategy = __legacyDecorateClassTS([
|
|
133948
|
-
|
|
133949
|
-
__legacyDecorateParamTS(0,
|
|
133950
|
-
__legacyDecorateParamTS(1,
|
|
134608
|
+
import_tsyringe12.injectable(),
|
|
134609
|
+
__legacyDecorateParamTS(0, import_tsyringe12.inject(AppConfig)),
|
|
134610
|
+
__legacyDecorateParamTS(1, import_tsyringe12.inject(Logger2)),
|
|
133951
134611
|
__legacyMetadataTS("design:paramtypes", [
|
|
133952
134612
|
Object,
|
|
133953
134613
|
Object
|
|
@@ -133955,7 +134615,7 @@ JwtStrategy = __legacyDecorateClassTS([
|
|
|
133955
134615
|
], JwtStrategy);
|
|
133956
134616
|
|
|
133957
134617
|
// src/mcp-server/transports/auth/strategies/oauthStrategy.ts
|
|
133958
|
-
var
|
|
134618
|
+
var import_tsyringe13 = __toESM(require_cjs3(), 1);
|
|
133959
134619
|
class OauthStrategy {
|
|
133960
134620
|
config;
|
|
133961
134621
|
logger;
|
|
@@ -134006,6 +134666,26 @@ class OauthStrategy {
|
|
|
134006
134666
|
...context,
|
|
134007
134667
|
claims: payload
|
|
134008
134668
|
});
|
|
134669
|
+
if (this.config.mcpServerResourceIdentifier) {
|
|
134670
|
+
const resourceClaim = payload.resource || payload.aud;
|
|
134671
|
+
const expectedResource = this.config.mcpServerResourceIdentifier;
|
|
134672
|
+
const isResourceValid = Array.isArray(resourceClaim) && resourceClaim.includes(expectedResource) || resourceClaim === expectedResource;
|
|
134673
|
+
if (!isResourceValid) {
|
|
134674
|
+
this.logger.warning("Token resource indicator mismatch. Token was not issued for this MCP server.", {
|
|
134675
|
+
...context,
|
|
134676
|
+
expected: expectedResource,
|
|
134677
|
+
received: resourceClaim
|
|
134678
|
+
});
|
|
134679
|
+
throw new McpError(-32005 /* Forbidden */, "Token was not issued for this MCP server. Resource indicator mismatch.", {
|
|
134680
|
+
expected: expectedResource,
|
|
134681
|
+
received: resourceClaim
|
|
134682
|
+
});
|
|
134683
|
+
}
|
|
134684
|
+
this.logger.debug("RFC 8707 resource indicator validated successfully.", {
|
|
134685
|
+
...context,
|
|
134686
|
+
resource: expectedResource
|
|
134687
|
+
});
|
|
134688
|
+
}
|
|
134009
134689
|
const scopes = typeof payload.scope === "string" ? payload.scope.split(" ") : [];
|
|
134010
134690
|
if (scopes.length === 0) {
|
|
134011
134691
|
this.logger.warning("Invalid token: missing or empty 'scope' claim.", context);
|
|
@@ -134052,9 +134732,9 @@ class OauthStrategy {
|
|
|
134052
134732
|
}
|
|
134053
134733
|
}
|
|
134054
134734
|
OauthStrategy = __legacyDecorateClassTS([
|
|
134055
|
-
|
|
134056
|
-
__legacyDecorateParamTS(0,
|
|
134057
|
-
__legacyDecorateParamTS(1,
|
|
134735
|
+
import_tsyringe13.injectable(),
|
|
134736
|
+
__legacyDecorateParamTS(0, import_tsyringe13.inject(AppConfig)),
|
|
134737
|
+
__legacyDecorateParamTS(1, import_tsyringe13.inject(Logger2)),
|
|
134058
134738
|
__legacyMetadataTS("design:paramtypes", [
|
|
134059
134739
|
Object,
|
|
134060
134740
|
Object
|
|
@@ -134062,8 +134742,8 @@ OauthStrategy = __legacyDecorateClassTS([
|
|
|
134062
134742
|
], OauthStrategy);
|
|
134063
134743
|
|
|
134064
134744
|
// src/mcp-server/transports/auth/authFactory.ts
|
|
134065
|
-
|
|
134066
|
-
|
|
134745
|
+
import_tsyringe14.container.register(JwtStrategy, { useClass: JwtStrategy });
|
|
134746
|
+
import_tsyringe14.container.register(OauthStrategy, { useClass: OauthStrategy });
|
|
134067
134747
|
function createAuthStrategy() {
|
|
134068
134748
|
const context = requestContextService.createRequestContext({
|
|
134069
134749
|
operation: "createAuthStrategy",
|
|
@@ -134073,10 +134753,10 @@ function createAuthStrategy() {
|
|
|
134073
134753
|
switch (config.mcpAuthMode) {
|
|
134074
134754
|
case "jwt":
|
|
134075
134755
|
logger.debug("Resolving JWT strategy from container.", context);
|
|
134076
|
-
return
|
|
134756
|
+
return import_tsyringe14.container.resolve(JwtStrategy);
|
|
134077
134757
|
case "oauth":
|
|
134078
134758
|
logger.debug("Resolving OAuth strategy from container.", context);
|
|
134079
|
-
return
|
|
134759
|
+
return import_tsyringe14.container.resolve(OauthStrategy);
|
|
134080
134760
|
case "none":
|
|
134081
134761
|
logger.info("Authentication is disabled ('none' mode).", context);
|
|
134082
134762
|
return null;
|
|
@@ -134245,6 +134925,18 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
134245
134925
|
}));
|
|
134246
134926
|
app.onError(httpErrorHandler);
|
|
134247
134927
|
app.get("/healthz", (c) => c.json({ status: "ok" }));
|
|
134928
|
+
app.get("/.well-known/oauth-protected-resource", (c) => {
|
|
134929
|
+
if (!config.oauthIssuerUrl) {
|
|
134930
|
+
return c.json({ error: "OAuth not configured on this server" }, { status: 404 });
|
|
134931
|
+
}
|
|
134932
|
+
return c.json({
|
|
134933
|
+
resource: config.mcpServerResourceIdentifier || config.oauthAudience,
|
|
134934
|
+
authorization_servers: [config.oauthIssuerUrl],
|
|
134935
|
+
bearer_methods_supported: ["header"],
|
|
134936
|
+
resource_signing_alg_values_supported: ["RS256", "ES256", "PS256"],
|
|
134937
|
+
...config.oauthJwksUri && { jwks_uri: config.oauthJwksUri }
|
|
134938
|
+
});
|
|
134939
|
+
});
|
|
134248
134940
|
app.get(config.mcpHttpEndpointPath, (c) => {
|
|
134249
134941
|
return c.json({
|
|
134250
134942
|
status: "ok",
|
|
@@ -134267,11 +134959,21 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
134267
134959
|
logger.info("Authentication is disabled; MCP endpoint is unprotected.", transportContext);
|
|
134268
134960
|
}
|
|
134269
134961
|
app.all(config.mcpHttpEndpointPath, async (c) => {
|
|
134962
|
+
const protocolVersion = c.req.header("mcp-protocol-version") ?? "2025-03-26";
|
|
134270
134963
|
logger.debug("Handling MCP request.", {
|
|
134271
134964
|
...transportContext,
|
|
134272
134965
|
path: c.req.path,
|
|
134273
|
-
method: c.req.method
|
|
134966
|
+
method: c.req.method,
|
|
134967
|
+
protocolVersion
|
|
134274
134968
|
});
|
|
134969
|
+
const supportedVersions = ["2025-03-26", "2025-06-18"];
|
|
134970
|
+
if (!supportedVersions.includes(protocolVersion)) {
|
|
134971
|
+
logger.warning("Unsupported MCP protocol version requested.", {
|
|
134972
|
+
...transportContext,
|
|
134973
|
+
protocolVersion,
|
|
134974
|
+
supportedVersions
|
|
134975
|
+
});
|
|
134976
|
+
}
|
|
134275
134977
|
const sessionId = c.req.header("mcp-session-id") ?? randomUUID();
|
|
134276
134978
|
const transport = new McpSessionTransport(sessionId);
|
|
134277
134979
|
const handleRpc = async () => {
|
|
@@ -134289,7 +134991,13 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
134289
134991
|
}
|
|
134290
134992
|
return await handleRpc();
|
|
134291
134993
|
} catch (err) {
|
|
134292
|
-
await transport.close?.()
|
|
134994
|
+
await transport.close?.().catch((closeErr) => {
|
|
134995
|
+
logger.warning("Failed to close transport after error", {
|
|
134996
|
+
...transportContext,
|
|
134997
|
+
sessionId,
|
|
134998
|
+
error: closeErr instanceof Error ? closeErr.message : String(closeErr)
|
|
134999
|
+
});
|
|
135000
|
+
});
|
|
134293
135001
|
throw err instanceof Error ? err : new Error(String(err));
|
|
134294
135002
|
}
|
|
134295
135003
|
});
|
|
@@ -134488,7 +135196,7 @@ async function startStdioTransport(server, parentContext) {
|
|
|
134488
135196
|
logger.info("MCP Server connected and listening via stdio transport.", operationContext);
|
|
134489
135197
|
logStartupBanner(`
|
|
134490
135198
|
\uD83D\uDE80 MCP Server running in STDIO mode.
|
|
134491
|
-
(MCP Spec: 2025-
|
|
135199
|
+
(MCP Spec: 2025-06-18 Stdio Transport)
|
|
134492
135200
|
`);
|
|
134493
135201
|
return server;
|
|
134494
135202
|
} catch (err) {
|
|
@@ -134562,10 +135270,10 @@ class TransportManager {
|
|
|
134562
135270
|
}
|
|
134563
135271
|
}
|
|
134564
135272
|
TransportManager = __legacyDecorateClassTS([
|
|
134565
|
-
|
|
134566
|
-
__legacyDecorateParamTS(0,
|
|
134567
|
-
__legacyDecorateParamTS(1,
|
|
134568
|
-
__legacyDecorateParamTS(2,
|
|
135273
|
+
import_tsyringe15.injectable(),
|
|
135274
|
+
__legacyDecorateParamTS(0, import_tsyringe15.inject(AppConfig)),
|
|
135275
|
+
__legacyDecorateParamTS(1, import_tsyringe15.inject(Logger2)),
|
|
135276
|
+
__legacyDecorateParamTS(2, import_tsyringe15.inject(CreateMcpServerInstance)),
|
|
134569
135277
|
__legacyMetadataTS("design:paramtypes", [
|
|
134570
135278
|
typeof AppConfigType === "undefined" ? Object : AppConfigType,
|
|
134571
135279
|
Object,
|
|
@@ -134575,14 +135283,14 @@ TransportManager = __legacyDecorateClassTS([
|
|
|
134575
135283
|
|
|
134576
135284
|
// src/container/registrations/mcp.ts
|
|
134577
135285
|
var registerMcpServices = () => {
|
|
134578
|
-
|
|
134579
|
-
|
|
134580
|
-
registerTools(
|
|
134581
|
-
registerResources(
|
|
134582
|
-
|
|
135286
|
+
import_tsyringe16.container.registerSingleton(ToolRegistry);
|
|
135287
|
+
import_tsyringe16.container.registerSingleton(ResourceRegistry);
|
|
135288
|
+
registerTools(import_tsyringe16.container);
|
|
135289
|
+
registerResources(import_tsyringe16.container);
|
|
135290
|
+
import_tsyringe16.container.register(CreateMcpServerInstance, {
|
|
134583
135291
|
useValue: createMcpServerInstance
|
|
134584
135292
|
});
|
|
134585
|
-
|
|
135293
|
+
import_tsyringe16.container.registerSingleton(TransportManagerToken, TransportManager);
|
|
134586
135294
|
logger.info("MCP services and factories registered with the DI container.");
|
|
134587
135295
|
};
|
|
134588
135296
|
|
|
@@ -134596,7 +135304,7 @@ function composeContainer() {
|
|
|
134596
135304
|
registerMcpServices();
|
|
134597
135305
|
isContainerComposed = true;
|
|
134598
135306
|
}
|
|
134599
|
-
var container_default =
|
|
135307
|
+
var container_default = import_tsyringe17.container;
|
|
134600
135308
|
|
|
134601
135309
|
// src/index.ts
|
|
134602
135310
|
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.5",
|
|
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",
|