mcp-use 1.9.1-canary.0 → 1.10.0-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +9 -6
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/{chunk-MUZ5WYE3.js → chunk-BFFS67JY.js} +1 -1
  4. package/dist/{chunk-D22NUQTL.js → chunk-HRWL2M2I.js} +184 -0
  5. package/dist/{chunk-5URNFWCQ.js → chunk-LWVK6RXA.js} +8 -3
  6. package/dist/{chunk-KHTTBIRP.js → chunk-Q3PFK7Y4.js} +138 -1
  7. package/dist/{context-storage-TXQ4DVSS.js → context-storage-NA4MHWOZ.js} +3 -1
  8. package/dist/index.cjs +184 -0
  9. package/dist/index.d.ts +3 -2
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +2 -2
  12. package/dist/src/browser.cjs +184 -0
  13. package/dist/src/browser.js +1 -1
  14. package/dist/src/react/index.cjs +184 -0
  15. package/dist/src/react/index.js +2 -2
  16. package/dist/src/server/context-storage.d.ts +8 -1
  17. package/dist/src/server/context-storage.d.ts.map +1 -1
  18. package/dist/src/server/endpoints/mount-mcp.d.ts.map +1 -1
  19. package/dist/src/server/index.cjs +595 -63
  20. package/dist/src/server/index.d.ts +3 -3
  21. package/dist/src/server/index.d.ts.map +1 -1
  22. package/dist/src/server/index.js +459 -67
  23. package/dist/src/server/mcp-server.d.ts +49 -9
  24. package/dist/src/server/mcp-server.d.ts.map +1 -1
  25. package/dist/src/server/oauth/providers.d.ts +27 -9
  26. package/dist/src/server/oauth/providers.d.ts.map +1 -1
  27. package/dist/src/server/prompts/index.d.ts.map +1 -1
  28. package/dist/src/server/resources/index.d.ts +43 -23
  29. package/dist/src/server/resources/index.d.ts.map +1 -1
  30. package/dist/src/server/resources/subscriptions.d.ts +54 -0
  31. package/dist/src/server/resources/subscriptions.d.ts.map +1 -0
  32. package/dist/src/server/sessions/session-manager.d.ts +9 -1
  33. package/dist/src/server/sessions/session-manager.d.ts.map +1 -1
  34. package/dist/src/server/tools/tool-execution-helpers.d.ts +30 -17
  35. package/dist/src/server/tools/tool-execution-helpers.d.ts.map +1 -1
  36. package/dist/src/server/tools/tool-registration.d.ts.map +1 -1
  37. package/dist/src/server/types/common.d.ts +24 -8
  38. package/dist/src/server/types/common.d.ts.map +1 -1
  39. package/dist/src/server/types/index.d.ts +3 -3
  40. package/dist/src/server/types/index.d.ts.map +1 -1
  41. package/dist/src/server/types/prompt.d.ts +2 -1
  42. package/dist/src/server/types/prompt.d.ts.map +1 -1
  43. package/dist/src/server/types/resource.d.ts +53 -8
  44. package/dist/src/server/types/resource.d.ts.map +1 -1
  45. package/dist/src/server/types/tool-context.d.ts +131 -0
  46. package/dist/src/server/types/tool-context.d.ts.map +1 -1
  47. package/dist/src/server/types/tool.d.ts +1 -1
  48. package/dist/src/server/types/tool.d.ts.map +1 -1
  49. package/dist/src/server/utils/response-helpers.d.ts +48 -4
  50. package/dist/src/server/utils/response-helpers.d.ts.map +1 -1
  51. package/dist/src/server/widgets/index.d.ts +2 -2
  52. package/dist/src/server/widgets/ui-resource-registration.d.ts +2 -2
  53. package/dist/src/session.d.ts +337 -2
  54. package/dist/src/session.d.ts.map +1 -1
  55. package/dist/{tool-execution-helpers-IVUDHXMK.js → tool-execution-helpers-RRMGLAHR.js} +7 -1
  56. package/package.json +3 -3
@@ -126,14 +126,18 @@ var init_runtime = __esm({
126
126
  var context_storage_exports = {};
127
127
  __export(context_storage_exports, {
128
128
  getRequestContext: () => getRequestContext,
129
+ getSessionId: () => getSessionId,
129
130
  hasRequestContext: () => hasRequestContext,
130
131
  runWithContext: () => runWithContext
131
132
  });
132
- async function runWithContext(context, fn) {
133
- return requestContextStorage.run(context, fn);
133
+ async function runWithContext(context, fn, sessionId) {
134
+ return requestContextStorage.run({ honoContext: context, sessionId }, fn);
134
135
  }
135
136
  function getRequestContext() {
136
- return requestContextStorage.getStore();
137
+ return requestContextStorage.getStore()?.honoContext;
138
+ }
139
+ function getSessionId() {
140
+ return requestContextStorage.getStore()?.sessionId;
137
141
  }
138
142
  function hasRequestContext() {
139
143
  return requestContextStorage.getStore() !== void 0;
@@ -146,6 +150,7 @@ var init_context_storage = __esm({
146
150
  requestContextStorage = new import_node_async_hooks.AsyncLocalStorage();
147
151
  __name(runWithContext, "runWithContext");
148
152
  __name(getRequestContext, "getRequestContext");
153
+ __name(getSessionId, "getSessionId");
149
154
  __name(hasRequestContext, "hasRequestContext");
150
155
  }
151
156
  });
@@ -174,13 +179,16 @@ var init_errors = __esm({
174
179
  // src/server/tools/tool-execution-helpers.ts
175
180
  var tool_execution_helpers_exports = {};
176
181
  __export(tool_execution_helpers_exports, {
182
+ VALID_LOG_LEVELS: () => VALID_LOG_LEVELS,
177
183
  createElicitMethod: () => createElicitMethod,
178
184
  createEnhancedContext: () => createEnhancedContext,
179
185
  createReportProgressMethod: () => createReportProgressMethod,
180
186
  createSampleMethod: () => createSampleMethod,
181
187
  findSessionContext: () => findSessionContext,
188
+ isValidLogLevel: () => isValidLogLevel,
182
189
  parseElicitParams: () => parseElicitParams,
183
190
  sendProgressNotification: () => sendProgressNotification,
191
+ shouldLogMessage: () => shouldLogMessage,
184
192
  withTimeout: () => withTimeout
185
193
  });
186
194
  function findSessionContext(sessions, initialRequestContext, extraProgressToken, extraSendNotification) {
@@ -418,7 +426,97 @@ function createReportProgressMethod(progressToken, sendNotification2) {
418
426
  }
419
427
  return void 0;
420
428
  }
421
- function createEnhancedContext(baseContext, createMessage, elicitInput, progressToken, sendNotification2) {
429
+ function isValidLogLevel(level) {
430
+ return VALID_LOG_LEVELS.includes(level);
431
+ }
432
+ function shouldLogMessage(messageLevel, minLevel) {
433
+ if (!minLevel) {
434
+ return true;
435
+ }
436
+ if (!isValidLogLevel(messageLevel) || !isValidLogLevel(minLevel)) {
437
+ return true;
438
+ }
439
+ return LOG_LEVELS[messageLevel] >= LOG_LEVELS[minLevel];
440
+ }
441
+ function createLogMethod(sendNotification2, minLogLevel) {
442
+ if (!sendNotification2) {
443
+ return void 0;
444
+ }
445
+ return async (level, message, logger) => {
446
+ if (!shouldLogMessage(level, minLogLevel)) {
447
+ return;
448
+ }
449
+ await sendNotification2({
450
+ method: "notifications/message",
451
+ params: {
452
+ level,
453
+ data: message,
454
+ logger: logger || "tool"
455
+ }
456
+ });
457
+ };
458
+ }
459
+ function createClientCapabilityChecker(clientCapabilities) {
460
+ const caps = clientCapabilities || {};
461
+ return {
462
+ can(capability) {
463
+ return capability in caps;
464
+ },
465
+ capabilities() {
466
+ return { ...caps };
467
+ }
468
+ };
469
+ }
470
+ function createSendNotificationMethod(sessionId, sessions) {
471
+ if (!sessionId || !sessions) {
472
+ return void 0;
473
+ }
474
+ return async (method, params) => {
475
+ const session = sessions.get(sessionId);
476
+ if (!session?.sendNotification) {
477
+ console.warn(
478
+ `[MCP] Cannot send notification to session ${sessionId} - no sendNotification function`
479
+ );
480
+ return;
481
+ }
482
+ try {
483
+ await session.sendNotification({
484
+ method,
485
+ params: params || {}
486
+ });
487
+ } catch (error2) {
488
+ console.error(
489
+ `[MCP] Error sending notification to session ${sessionId}:`,
490
+ error2
491
+ );
492
+ }
493
+ };
494
+ }
495
+ function createSendNotificationToSessionMethod(sessions) {
496
+ if (!sessions) {
497
+ return void 0;
498
+ }
499
+ return async (sessionId, method, params) => {
500
+ const session = sessions.get(sessionId);
501
+ if (!session?.sendNotification) {
502
+ return false;
503
+ }
504
+ try {
505
+ await session.sendNotification({
506
+ method,
507
+ params: params || {}
508
+ });
509
+ return true;
510
+ } catch (error2) {
511
+ console.error(
512
+ `[MCP] Error sending notification to session ${sessionId}:`,
513
+ error2
514
+ );
515
+ return false;
516
+ }
517
+ };
518
+ }
519
+ function createEnhancedContext(baseContext, createMessage, elicitInput, progressToken, sendNotification2, minLogLevel, clientCapabilities, sessionId, sessions) {
422
520
  const enhancedContext = baseContext ? Object.create(baseContext) : {};
423
521
  enhancedContext.sample = createSampleMethod(
424
522
  createMessage,
@@ -430,9 +528,27 @@ function createEnhancedContext(baseContext, createMessage, elicitInput, progress
430
528
  progressToken,
431
529
  sendNotification2
432
530
  );
531
+ enhancedContext.log = createLogMethod(sendNotification2, minLogLevel);
532
+ enhancedContext.client = createClientCapabilityChecker(clientCapabilities);
533
+ if (sessionId) {
534
+ enhancedContext.session = {
535
+ sessionId
536
+ };
537
+ }
538
+ const sendNotificationMethod = createSendNotificationMethod(
539
+ sessionId,
540
+ sessions
541
+ );
542
+ if (sendNotificationMethod) {
543
+ enhancedContext.sendNotification = sendNotificationMethod;
544
+ }
545
+ const sendNotificationToSessionMethod = createSendNotificationToSessionMethod(sessions);
546
+ if (sendNotificationToSessionMethod) {
547
+ enhancedContext.sendNotificationToSession = sendNotificationToSessionMethod;
548
+ }
433
549
  return enhancedContext;
434
550
  }
435
- var import_zod_json_schema_compat;
551
+ var import_zod_json_schema_compat, LOG_LEVELS, VALID_LOG_LEVELS;
436
552
  var init_tool_execution_helpers = __esm({
437
553
  "src/server/tools/tool-execution-helpers.ts"() {
438
554
  "use strict";
@@ -446,6 +562,32 @@ var init_tool_execution_helpers = __esm({
446
562
  __name(createSampleMethod, "createSampleMethod");
447
563
  __name(createElicitMethod, "createElicitMethod");
448
564
  __name(createReportProgressMethod, "createReportProgressMethod");
565
+ LOG_LEVELS = {
566
+ debug: 0,
567
+ info: 1,
568
+ notice: 2,
569
+ warning: 3,
570
+ error: 4,
571
+ critical: 5,
572
+ alert: 6,
573
+ emergency: 7
574
+ };
575
+ VALID_LOG_LEVELS = [
576
+ "debug",
577
+ "info",
578
+ "notice",
579
+ "warning",
580
+ "error",
581
+ "critical",
582
+ "alert",
583
+ "emergency"
584
+ ];
585
+ __name(isValidLogLevel, "isValidLogLevel");
586
+ __name(shouldLogMessage, "shouldLogMessage");
587
+ __name(createLogMethod, "createLogMethod");
588
+ __name(createClientCapabilityChecker, "createClientCapabilityChecker");
589
+ __name(createSendNotificationMethod, "createSendNotificationMethod");
590
+ __name(createSendNotificationToSessionMethod, "createSendNotificationToSessionMethod");
449
591
  __name(createEnhancedContext, "createEnhancedContext");
450
592
  }
451
593
  });
@@ -643,9 +785,11 @@ var init_conversion2 = __esm({
643
785
  // src/server/index.ts
644
786
  var server_exports = {};
645
787
  __export(server_exports, {
788
+ MCPServer: () => MCPServer,
646
789
  adaptConnectMiddleware: () => adaptConnectMiddleware,
647
790
  adaptMiddleware: () => adaptMiddleware,
648
791
  array: () => array,
792
+ audio: () => audio,
649
793
  binary: () => binary,
650
794
  buildWidgetUrl: () => buildWidgetUrl,
651
795
  createExternalUrlResource: () => createExternalUrlResource,
@@ -684,11 +828,14 @@ module.exports = __toCommonJS(server_exports);
684
828
 
685
829
  // src/server/mcp-server.ts
686
830
  var import_mcp2 = require("@modelcontextprotocol/sdk/server/mcp.js");
831
+ var import_types2 = require("@modelcontextprotocol/sdk/types.js");
832
+ var import_zod2 = require("zod");
687
833
 
688
834
  // src/server/widgets/index.ts
689
835
  init_runtime();
690
836
 
691
837
  // src/server/utils/response-helpers.ts
838
+ init_runtime();
692
839
  function text(content) {
693
840
  return {
694
841
  content: [
@@ -719,7 +866,109 @@ function image(data, mimeType = "image/png") {
719
866
  };
720
867
  }
721
868
  __name(image, "image");
722
- function resource(uri, mimeType, text2) {
869
+ function getAudioMimeType(filename) {
870
+ const ext = filename.split(".").pop()?.toLowerCase();
871
+ switch (ext) {
872
+ case "wav":
873
+ return "audio/wav";
874
+ case "mp3":
875
+ return "audio/mpeg";
876
+ case "ogg":
877
+ return "audio/ogg";
878
+ case "m4a":
879
+ return "audio/mp4";
880
+ case "webm":
881
+ return "audio/webm";
882
+ case "flac":
883
+ return "audio/flac";
884
+ case "aac":
885
+ return "audio/aac";
886
+ default:
887
+ return "audio/wav";
888
+ }
889
+ }
890
+ __name(getAudioMimeType, "getAudioMimeType");
891
+ function arrayBufferToBase64(buffer) {
892
+ if (isDeno) {
893
+ const bytes = new Uint8Array(buffer);
894
+ let binary2 = "";
895
+ for (let i = 0; i < bytes.length; i++) {
896
+ binary2 += String.fromCharCode(bytes[i]);
897
+ }
898
+ return btoa(binary2);
899
+ } else {
900
+ return Buffer.from(buffer).toString("base64");
901
+ }
902
+ }
903
+ __name(arrayBufferToBase64, "arrayBufferToBase64");
904
+ function audio(dataOrPath, mimeType) {
905
+ const isFilePath = dataOrPath.includes("/") || dataOrPath.includes("\\") || dataOrPath.includes(".");
906
+ if (isFilePath && dataOrPath.length < 1e3) {
907
+ return (async () => {
908
+ const buffer = await fsHelpers.readFile(dataOrPath);
909
+ const base64Data = arrayBufferToBase64(buffer);
910
+ const inferredMimeType = mimeType || getAudioMimeType(dataOrPath);
911
+ return {
912
+ content: [
913
+ {
914
+ type: "audio",
915
+ data: base64Data,
916
+ mimeType: inferredMimeType
917
+ }
918
+ ],
919
+ _meta: {
920
+ mimeType: inferredMimeType,
921
+ isAudio: true
922
+ }
923
+ };
924
+ })();
925
+ }
926
+ const finalMimeType = mimeType || "audio/wav";
927
+ return {
928
+ content: [
929
+ {
930
+ type: "audio",
931
+ data: dataOrPath,
932
+ mimeType: finalMimeType
933
+ }
934
+ ],
935
+ _meta: {
936
+ mimeType: finalMimeType,
937
+ isAudio: true
938
+ }
939
+ };
940
+ }
941
+ __name(audio, "audio");
942
+ function resource(uri, mimeTypeOrContent, text2) {
943
+ if (typeof mimeTypeOrContent === "object" && mimeTypeOrContent !== null && "content" in mimeTypeOrContent) {
944
+ const contentResult = mimeTypeOrContent;
945
+ let extractedText;
946
+ let extractedMimeType;
947
+ if (contentResult._meta && typeof contentResult._meta === "object") {
948
+ const meta = contentResult._meta;
949
+ if (meta.mimeType && typeof meta.mimeType === "string") {
950
+ extractedMimeType = meta.mimeType;
951
+ }
952
+ }
953
+ if (contentResult.content && contentResult.content.length > 0) {
954
+ const firstContent = contentResult.content[0];
955
+ if (firstContent.type === "text" && "text" in firstContent) {
956
+ extractedText = firstContent.text;
957
+ }
958
+ }
959
+ const resourceContent2 = {
960
+ type: "resource",
961
+ resource: {
962
+ uri,
963
+ ...extractedMimeType && { mimeType: extractedMimeType },
964
+ ...extractedText && { text: extractedText }
965
+ }
966
+ };
967
+ return {
968
+ content: [resourceContent2]
969
+ };
970
+ }
971
+ const mimeType = mimeTypeOrContent;
723
972
  const resourceContent = {
724
973
  type: "resource",
725
974
  resource: {
@@ -998,7 +1247,7 @@ function parseTemplateUri(template, uri) {
998
1247
  const params = {};
999
1248
  let regexPattern = template.replace(/[.*+?^$()[\]\\|]/g, "\\$&");
1000
1249
  const paramNames = [];
1001
- regexPattern = regexPattern.replace(/\\\{([^}]+)\\\}/g, (_, paramName) => {
1250
+ regexPattern = regexPattern.replace(/\{([^}]+)\}/g, (_, paramName) => {
1002
1251
  paramNames.push(paramName);
1003
1252
  return "([^/]+)";
1004
1253
  });
@@ -2431,7 +2680,7 @@ function toolRegistration(toolDefinition, callback) {
2431
2680
  const initialRequestContext = getRequestContext();
2432
2681
  const extraProgressToken = extra?._meta?.progressToken;
2433
2682
  const extraSendNotification = extra?.sendNotification;
2434
- const { requestContext, progressToken, sendNotification: sendNotification2 } = findSessionContext(
2683
+ const { requestContext, session, progressToken, sendNotification: sendNotification2 } = findSessionContext(
2435
2684
  this.sessions,
2436
2685
  initialRequestContext,
2437
2686
  extraProgressToken,
@@ -2442,7 +2691,9 @@ function toolRegistration(toolDefinition, callback) {
2442
2691
  this.createMessage.bind(this),
2443
2692
  this.server.server.elicitInput.bind(this.server.server),
2444
2693
  progressToken,
2445
- sendNotification2
2694
+ sendNotification2,
2695
+ session?.logLevel,
2696
+ session?.clientCapabilities
2446
2697
  );
2447
2698
  const executeCallback = /* @__PURE__ */ __name(async () => {
2448
2699
  if (actualCallback.length >= 2) {
@@ -2467,6 +2718,152 @@ init_tool_execution_helpers();
2467
2718
  // src/server/resources/index.ts
2468
2719
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
2469
2720
  init_conversion();
2721
+
2722
+ // src/server/resources/subscriptions.ts
2723
+ var import_types = require("@modelcontextprotocol/sdk/types.js");
2724
+ init_context_storage();
2725
+ var ResourceSubscriptionManager = class {
2726
+ static {
2727
+ __name(this, "ResourceSubscriptionManager");
2728
+ }
2729
+ /**
2730
+ * Tracks resource subscriptions per session
2731
+ * Map structure: uri -> Set<sessionId>
2732
+ */
2733
+ subscriptions = /* @__PURE__ */ new Map();
2734
+ /**
2735
+ * Register subscription handlers with an MCP server instance
2736
+ *
2737
+ * @param server - The native MCP server instance
2738
+ * @param sessions - Map of active sessions
2739
+ */
2740
+ registerHandlers(server, sessions) {
2741
+ server.server.setRequestHandler(
2742
+ import_types.SubscribeRequestSchema,
2743
+ async (request) => {
2744
+ const { uri } = request.params;
2745
+ const sessionId = this.getSessionIdFromContext(sessions, server);
2746
+ if (!sessionId) {
2747
+ console.warn(
2748
+ `[MCP] Could not determine session ID for resource subscription to ${uri}`
2749
+ );
2750
+ return {};
2751
+ }
2752
+ if (!this.subscriptions.has(uri)) {
2753
+ this.subscriptions.set(uri, /* @__PURE__ */ new Set());
2754
+ }
2755
+ this.subscriptions.get(uri).add(sessionId);
2756
+ console.log(
2757
+ `[MCP] Session ${sessionId} subscribed to resource: ${uri}`
2758
+ );
2759
+ return {};
2760
+ }
2761
+ );
2762
+ server.server.setRequestHandler(
2763
+ import_types.UnsubscribeRequestSchema,
2764
+ async (request) => {
2765
+ const { uri } = request.params;
2766
+ const sessionId = this.getSessionIdFromContext(sessions, server);
2767
+ if (!sessionId) {
2768
+ console.warn(
2769
+ `[MCP] Could not determine session ID for resource unsubscribe from ${uri}`
2770
+ );
2771
+ return {};
2772
+ }
2773
+ const subscribers = this.subscriptions.get(uri);
2774
+ if (subscribers) {
2775
+ subscribers.delete(sessionId);
2776
+ if (subscribers.size === 0) {
2777
+ this.subscriptions.delete(uri);
2778
+ }
2779
+ console.log(
2780
+ `[MCP] Session ${sessionId} unsubscribed from resource: ${uri}`
2781
+ );
2782
+ }
2783
+ return {};
2784
+ }
2785
+ );
2786
+ }
2787
+ /**
2788
+ * Get session ID from request context or sessions map
2789
+ *
2790
+ * @param sessions - Map of active sessions
2791
+ * @param server - The server instance to match against
2792
+ * @returns The session ID, or undefined if not found
2793
+ */
2794
+ getSessionIdFromContext(sessions, server) {
2795
+ const requestContext = getRequestContext();
2796
+ let sessionId;
2797
+ if (requestContext) {
2798
+ sessionId = requestContext.req.header("mcp-session-id");
2799
+ }
2800
+ if (!sessionId) {
2801
+ for (const [sid, session] of sessions.entries()) {
2802
+ if (session.server === server) {
2803
+ sessionId = sid;
2804
+ break;
2805
+ }
2806
+ }
2807
+ }
2808
+ return sessionId;
2809
+ }
2810
+ /**
2811
+ * Notify subscribed clients that a resource has been updated
2812
+ *
2813
+ * This method sends a `notifications/resources/updated` notification to all
2814
+ * sessions that have subscribed to the specified resource URI.
2815
+ *
2816
+ * @param uri - The URI of the resource that changed
2817
+ * @param sessions - Map of active sessions
2818
+ * @returns Promise that resolves when all notifications have been sent
2819
+ */
2820
+ async notifyResourceUpdated(uri, sessions) {
2821
+ const subscribers = this.subscriptions.get(uri);
2822
+ if (!subscribers || subscribers.size === 0) {
2823
+ return;
2824
+ }
2825
+ console.log(
2826
+ `[MCP] Notifying ${subscribers.size} subscriber(s) of resource update: ${uri}`
2827
+ );
2828
+ for (const sessionId of subscribers) {
2829
+ const session = sessions.get(sessionId);
2830
+ if (session?.server) {
2831
+ try {
2832
+ await session.server.server.sendResourceUpdated({ uri });
2833
+ console.log(
2834
+ `[MCP] Sent resource update notification to session ${sessionId}`
2835
+ );
2836
+ } catch (error2) {
2837
+ console.error(
2838
+ `[MCP] Failed to send resource update notification to session ${sessionId}:`,
2839
+ error2
2840
+ );
2841
+ }
2842
+ }
2843
+ }
2844
+ }
2845
+ /**
2846
+ * Clean up resource subscriptions for a closed session
2847
+ *
2848
+ * This method is called automatically when a session is closed to remove
2849
+ * all resource subscriptions associated with that session.
2850
+ *
2851
+ * @param sessionId - The session ID to clean up
2852
+ */
2853
+ cleanupSession(sessionId) {
2854
+ for (const [uri, subscribers] of this.subscriptions) {
2855
+ subscribers.delete(sessionId);
2856
+ if (subscribers.size === 0) {
2857
+ this.subscriptions.delete(uri);
2858
+ }
2859
+ }
2860
+ console.log(
2861
+ `[MCP] Cleaned up resource subscriptions for session ${sessionId}`
2862
+ );
2863
+ }
2864
+ };
2865
+
2866
+ // src/server/resources/index.ts
2470
2867
  function registerResource(resourceDefinition, callback) {
2471
2868
  const actualCallback = callback || resourceDefinition.readCallback;
2472
2869
  if (!actualCallback) {
@@ -2525,24 +2922,25 @@ function registerResourceTemplate(resourceTemplateDefinition, callback) {
2525
2922
  `Resource template '${resourceTemplateDefinition.name}' must have either a readCallback property or a callback parameter`
2526
2923
  );
2527
2924
  }
2528
- const template = new import_mcp.ResourceTemplate(
2529
- resourceTemplateDefinition.resourceTemplate.uriTemplate,
2530
- {
2531
- list: void 0,
2532
- // Optional: callback to list all matching resources
2533
- complete: void 0
2534
- // Optional: callback for auto-completion
2535
- }
2536
- );
2925
+ const isFlatStructure = "uriTemplate" in resourceTemplateDefinition;
2926
+ const uriTemplate = isFlatStructure ? resourceTemplateDefinition.uriTemplate : resourceTemplateDefinition.resourceTemplate.uriTemplate;
2927
+ const mimeType = isFlatStructure ? resourceTemplateDefinition.mimeType : resourceTemplateDefinition.resourceTemplate.mimeType;
2928
+ const templateDescription = isFlatStructure ? void 0 : resourceTemplateDefinition.resourceTemplate.description;
2929
+ const template = new import_mcp.ResourceTemplate(uriTemplate, {
2930
+ list: void 0,
2931
+ // Optional: callback to list all matching resources
2932
+ complete: void 0
2933
+ // Optional: callback for auto-completion
2934
+ });
2537
2935
  const metadata = {};
2538
2936
  if (resourceTemplateDefinition.title) {
2539
2937
  metadata.title = resourceTemplateDefinition.title;
2540
2938
  }
2541
- if (resourceTemplateDefinition.description || resourceTemplateDefinition.resourceTemplate.description) {
2542
- metadata.description = resourceTemplateDefinition.description || resourceTemplateDefinition.resourceTemplate.description;
2939
+ if (resourceTemplateDefinition.description || templateDescription) {
2940
+ metadata.description = resourceTemplateDefinition.description || templateDescription;
2543
2941
  }
2544
- if (resourceTemplateDefinition.resourceTemplate.mimeType) {
2545
- metadata.mimeType = resourceTemplateDefinition.resourceTemplate.mimeType;
2942
+ if (mimeType) {
2943
+ metadata.mimeType = mimeType;
2546
2944
  }
2547
2945
  if (resourceTemplateDefinition.annotations) {
2548
2946
  metadata.annotations = resourceTemplateDefinition.annotations;
@@ -2552,10 +2950,7 @@ function registerResourceTemplate(resourceTemplateDefinition, callback) {
2552
2950
  template,
2553
2951
  metadata,
2554
2952
  async (uri) => {
2555
- const params = this.parseTemplateUri(
2556
- resourceTemplateDefinition.resourceTemplate.uriTemplate,
2557
- uri.toString()
2558
- );
2953
+ const params = this.parseTemplateUri(uriTemplate, uri.toString());
2559
2954
  const { getRequestContext: getRequestContext2, runWithContext: runWithContext2 } = await Promise.resolve().then(() => (init_context_storage(), context_storage_exports));
2560
2955
  const { findSessionContext: findSessionContext2 } = await Promise.resolve().then(() => (init_tool_execution_helpers(), tool_execution_helpers_exports));
2561
2956
  const initialRequestContext = getRequestContext2();
@@ -2570,8 +2965,12 @@ function registerResourceTemplate(resourceTemplateDefinition, callback) {
2570
2965
  const executeCallback = /* @__PURE__ */ __name(async () => {
2571
2966
  if (actualCallback.length >= 3) {
2572
2967
  return await actualCallback(uri, params, enhancedContext);
2968
+ } else if (actualCallback.length === 2) {
2969
+ return await actualCallback(uri, params);
2970
+ } else if (actualCallback.length === 1) {
2971
+ return await actualCallback(uri);
2573
2972
  }
2574
- return await actualCallback(uri, params);
2973
+ return await actualCallback();
2575
2974
  }, "executeCallback");
2576
2975
  const result = requestContext ? await runWithContext2(requestContext, executeCallback) : await executeCallback();
2577
2976
  if ("contents" in result && Array.isArray(result.contents)) {
@@ -2602,8 +3001,10 @@ function registerPrompt(promptDefinition, callback) {
2602
3001
  argsSchema = this.convertZodSchemaToParams(
2603
3002
  promptDefinition.schema
2604
3003
  );
3004
+ } else if (promptDefinition.args && promptDefinition.args.length > 0) {
3005
+ argsSchema = this.createParamsSchema(promptDefinition.args);
2605
3006
  } else {
2606
- argsSchema = this.createParamsSchema(promptDefinition.args || []);
3007
+ argsSchema = void 0;
2607
3008
  }
2608
3009
  const wrappedCallback = /* @__PURE__ */ __name(async (params, extra) => {
2609
3010
  const { getRequestContext: getRequestContext2, runWithContext: runWithContext2 } = await Promise.resolve().then(() => (init_context_storage(), context_storage_exports));
@@ -2886,7 +3287,7 @@ init_tool_execution_helpers();
2886
3287
  init_context_storage();
2887
3288
 
2888
3289
  // src/server/sessions/session-manager.ts
2889
- function startIdleCleanup(sessions, idleTimeoutMs) {
3290
+ function startIdleCleanup(sessions, idleTimeoutMs, mcpServerInstance) {
2890
3291
  if (idleTimeoutMs <= 0) {
2891
3292
  return void 0;
2892
3293
  }
@@ -2904,6 +3305,7 @@ function startIdleCleanup(sessions, idleTimeoutMs) {
2904
3305
  );
2905
3306
  for (const sessionId of expiredSessions) {
2906
3307
  sessions.delete(sessionId);
3308
+ mcpServerInstance?.cleanupSessionSubscriptions?.(sessionId);
2907
3309
  }
2908
3310
  }
2909
3311
  }, 6e4);
@@ -2918,7 +3320,11 @@ async function mountMcp(app, mcpServerInstance, sessions, config, isProductionMo
2918
3320
  const transports = /* @__PURE__ */ new Map();
2919
3321
  let idleCleanupInterval;
2920
3322
  if (idleTimeoutMs > 0) {
2921
- idleCleanupInterval = startIdleCleanup(sessions, idleTimeoutMs);
3323
+ idleCleanupInterval = startIdleCleanup(
3324
+ sessions,
3325
+ idleTimeoutMs,
3326
+ mcpServerInstance
3327
+ );
2922
3328
  }
2923
3329
  const handleRequest = /* @__PURE__ */ __name(async (c) => {
2924
3330
  const sessionId = c.req.header("mcp-session-id");
@@ -2945,11 +3351,23 @@ async function mountMcp(app, mcpServerInstance, sessions, config, isProductionMo
2945
3351
  context: c,
2946
3352
  honoContext: c
2947
3353
  });
3354
+ server.server.oninitialized = () => {
3355
+ const clientCapabilities = server.server.getClientCapabilities();
3356
+ if (clientCapabilities && sessions.has(sid)) {
3357
+ const session = sessions.get(sid);
3358
+ session.clientCapabilities = clientCapabilities;
3359
+ console.log(
3360
+ `[MCP] Captured client capabilities for session ${sid}:`,
3361
+ Object.keys(clientCapabilities)
3362
+ );
3363
+ }
3364
+ };
2948
3365
  }, "onsessioninitialized"),
2949
3366
  onsessionclosed: /* @__PURE__ */ __name((sid) => {
2950
3367
  console.log(`[MCP] Session closed: ${sid}`);
2951
3368
  transports.delete(sid);
2952
3369
  sessions.delete(sid);
3370
+ mcpServerInstance.cleanupSessionSubscriptions?.(sid);
2953
3371
  }, "onsessionclosed")
2954
3372
  });
2955
3373
  await server.connect(transport);
@@ -3240,9 +3658,9 @@ async function setupOAuthForServer(app, oauthProvider, baseUrl, state) {
3240
3658
  __name(setupOAuthForServer, "setupOAuthForServer");
3241
3659
 
3242
3660
  // src/server/mcp-server.ts
3243
- var McpServer = class {
3661
+ var MCPServer = class {
3244
3662
  static {
3245
- __name(this, "McpServer");
3663
+ __name(this, "MCPServer");
3246
3664
  }
3247
3665
  /**
3248
3666
  * Native MCP server instance from @modelcontextprotocol/sdk
@@ -3285,6 +3703,22 @@ var McpServer = class {
3285
3703
  resources: /* @__PURE__ */ new Map(),
3286
3704
  resourceTemplates: /* @__PURE__ */ new Map()
3287
3705
  };
3706
+ /**
3707
+ * Resource subscription manager for tracking and notifying resource updates
3708
+ */
3709
+ subscriptionManager = new ResourceSubscriptionManager();
3710
+ /**
3711
+ * Clean up resource subscriptions for a closed session
3712
+ *
3713
+ * This method is called automatically when a session is closed to remove
3714
+ * all resource subscriptions associated with that session.
3715
+ *
3716
+ * @param sessionId - The session ID to clean up
3717
+ * @internal
3718
+ */
3719
+ cleanupSessionSubscriptions(sessionId) {
3720
+ this.subscriptionManager.cleanupSession(sessionId);
3721
+ }
3288
3722
  /**
3289
3723
  * Creates a new MCP server instance with Hono integration
3290
3724
  *
@@ -3293,16 +3727,27 @@ var McpServer = class {
3293
3727
  * access to Hono methods while preserving MCP server functionality.
3294
3728
  *
3295
3729
  * @param config - Server configuration including name, version, and description
3296
- * @returns A proxied McpServer instance that supports both MCP and Hono methods
3730
+ * @returns A proxied MCPServer instance that supports both MCP and Hono methods
3297
3731
  */
3298
3732
  constructor(config) {
3299
3733
  this.config = config;
3300
3734
  this.serverHost = config.host || "localhost";
3301
3735
  this.serverBaseUrl = config.baseUrl;
3302
- this.nativeServer = new import_mcp2.McpServer({
3303
- name: config.name,
3304
- version: config.version
3305
- });
3736
+ this.nativeServer = new import_mcp2.McpServer(
3737
+ {
3738
+ name: config.name,
3739
+ version: config.version
3740
+ },
3741
+ {
3742
+ capabilities: {
3743
+ logging: {},
3744
+ resources: {
3745
+ subscribe: true,
3746
+ listChanged: true
3747
+ }
3748
+ }
3749
+ }
3750
+ );
3306
3751
  this.app = createHonoApp(requestLogger);
3307
3752
  this.oauthConfig = config.oauth;
3308
3753
  this.wrapRegistrationMethods();
@@ -3357,10 +3802,17 @@ var McpServer = class {
3357
3802
  * This is called for each initialize request to create an isolated server.
3358
3803
  */
3359
3804
  getServerForSession() {
3360
- const newServer = new import_mcp2.McpServer({
3361
- name: this.config.name,
3362
- version: this.config.version
3363
- });
3805
+ const newServer = new import_mcp2.McpServer(
3806
+ {
3807
+ name: this.config.name,
3808
+ version: this.config.version
3809
+ },
3810
+ {
3811
+ capabilities: {
3812
+ logging: {}
3813
+ }
3814
+ }
3815
+ );
3364
3816
  for (const [name, recipe] of this.registrationRecipes.tools) {
3365
3817
  const { config, handler: actualCallback } = recipe;
3366
3818
  let inputSchema;
@@ -3375,12 +3827,21 @@ var McpServer = class {
3375
3827
  const initialRequestContext = getRequestContext();
3376
3828
  const extraProgressToken = extra?._meta?.progressToken;
3377
3829
  const extraSendNotification = extra?.sendNotification;
3378
- const { requestContext, progressToken, sendNotification: sendNotification2 } = findSessionContext(
3830
+ const { requestContext, session, progressToken, sendNotification: sendNotification2 } = findSessionContext(
3379
3831
  this.sessions,
3380
3832
  initialRequestContext,
3381
3833
  extraProgressToken,
3382
3834
  extraSendNotification
3383
3835
  );
3836
+ let sessionId;
3837
+ if (session) {
3838
+ for (const [id, s] of this.sessions.entries()) {
3839
+ if (s === session) {
3840
+ sessionId = id;
3841
+ break;
3842
+ }
3843
+ }
3844
+ }
3384
3845
  const createMessageWithLogging = /* @__PURE__ */ __name(async (params2, options) => {
3385
3846
  console.log("[createMessage] About to call server.createMessage");
3386
3847
  console.log("[createMessage] Has server:", !!newServer);
@@ -3406,7 +3867,11 @@ var McpServer = class {
3406
3867
  createMessageWithLogging,
3407
3868
  newServer.server.elicitInput.bind(newServer.server),
3408
3869
  progressToken,
3409
- sendNotification2
3870
+ sendNotification2,
3871
+ session?.logLevel,
3872
+ session?.clientCapabilities,
3873
+ sessionId,
3874
+ this.sessions
3410
3875
  );
3411
3876
  const executeCallback = /* @__PURE__ */ __name(async () => {
3412
3877
  if (actualCallback.length >= 2) {
@@ -3436,8 +3901,10 @@ var McpServer = class {
3436
3901
  let argsSchema;
3437
3902
  if (config.schema) {
3438
3903
  argsSchema = this.convertZodSchemaToParams(config.schema);
3904
+ } else if (config.args && config.args.length > 0) {
3905
+ argsSchema = this.createParamsSchema(config.args);
3439
3906
  } else {
3440
- argsSchema = this.createParamsSchema(config.args || []);
3907
+ argsSchema = void 0;
3441
3908
  }
3442
3909
  const wrappedHandler = /* @__PURE__ */ __name(async (params) => {
3443
3910
  const result = await handler(params);
@@ -3480,22 +3947,23 @@ var McpServer = class {
3480
3947
  }
3481
3948
  for (const [_name, recipe] of this.registrationRecipes.resourceTemplates) {
3482
3949
  const { config, handler } = recipe;
3483
- const template = new import_mcp2.ResourceTemplate(
3484
- config.resourceTemplate.uriTemplate,
3485
- {
3486
- list: void 0,
3487
- complete: void 0
3488
- }
3489
- );
3950
+ const isFlatStructure = "uriTemplate" in config;
3951
+ const uriTemplate = isFlatStructure ? config.uriTemplate : config.resourceTemplate.uriTemplate;
3952
+ const mimeType = isFlatStructure ? config.mimeType : config.resourceTemplate.mimeType;
3953
+ const templateDescription = isFlatStructure ? void 0 : config.resourceTemplate.description;
3954
+ const template = new import_mcp2.ResourceTemplate(uriTemplate, {
3955
+ list: void 0,
3956
+ complete: void 0
3957
+ });
3490
3958
  const metadata = {};
3491
3959
  if (config.title) {
3492
3960
  metadata.title = config.title;
3493
3961
  }
3494
- if (config.description || config.resourceTemplate.description) {
3495
- metadata.description = config.description || config.resourceTemplate.description;
3962
+ if (config.description || templateDescription) {
3963
+ metadata.description = config.description || templateDescription;
3496
3964
  }
3497
- if (config.resourceTemplate.mimeType) {
3498
- metadata.mimeType = config.resourceTemplate.mimeType;
3965
+ if (mimeType) {
3966
+ metadata.mimeType = mimeType;
3499
3967
  }
3500
3968
  if (config.annotations) {
3501
3969
  metadata.annotations = config.annotations;
@@ -3505,10 +3973,7 @@ var McpServer = class {
3505
3973
  template,
3506
3974
  metadata,
3507
3975
  async (uri) => {
3508
- const params = this.parseTemplateUri(
3509
- config.resourceTemplate.uriTemplate,
3510
- uri.toString()
3511
- );
3976
+ const params = this.parseTemplateUri(uriTemplate, uri.toString());
3512
3977
  const result = await handler(uri, params);
3513
3978
  if ("contents" in result && Array.isArray(result.contents)) {
3514
3979
  return result;
@@ -3518,6 +3983,50 @@ var McpServer = class {
3518
3983
  }
3519
3984
  );
3520
3985
  }
3986
+ newServer.server.setRequestHandler(
3987
+ import_zod2.z.object({ method: import_zod2.z.literal("logging/setLevel") }).passthrough(),
3988
+ async (request) => {
3989
+ const level = request.params?.level;
3990
+ if (!level) {
3991
+ throw new import_types2.McpError(
3992
+ import_types2.ErrorCode.InvalidParams,
3993
+ "Missing 'level' parameter"
3994
+ );
3995
+ }
3996
+ if (!isValidLogLevel(level)) {
3997
+ throw new import_types2.McpError(
3998
+ import_types2.ErrorCode.InvalidParams,
3999
+ `Invalid log level '${level}'. Must be one of: debug, info, notice, warning, error, critical, alert, emergency`
4000
+ );
4001
+ }
4002
+ const requestContext = getRequestContext();
4003
+ if (requestContext) {
4004
+ const sessionId = requestContext.req.header("mcp-session-id");
4005
+ if (sessionId && this.sessions.has(sessionId)) {
4006
+ const session = this.sessions.get(sessionId);
4007
+ session.logLevel = level;
4008
+ console.log(
4009
+ `[MCP] Set log level to '${level}' for session ${sessionId}`
4010
+ );
4011
+ return {};
4012
+ }
4013
+ }
4014
+ for (const [sessionId, session] of this.sessions.entries()) {
4015
+ if (session.server === newServer) {
4016
+ session.logLevel = level;
4017
+ console.log(
4018
+ `[MCP] Set log level to '${level}' for session ${sessionId}`
4019
+ );
4020
+ return {};
4021
+ }
4022
+ }
4023
+ console.warn(
4024
+ "[MCP] Could not find session for logging/setLevel request"
4025
+ );
4026
+ throw new import_types2.McpError(import_types2.ErrorCode.InternalError, "Could not find session");
4027
+ }
4028
+ );
4029
+ this.subscriptionManager.registerHandlers(newServer, this.sessions);
3521
4030
  return newServer;
3522
4031
  }
3523
4032
  /**
@@ -3547,6 +4056,24 @@ var McpServer = class {
3547
4056
  getActiveSessions = getActiveSessions;
3548
4057
  sendNotification = sendNotification;
3549
4058
  sendNotificationToSession = sendNotificationToSession2;
4059
+ /**
4060
+ * Notify subscribed clients that a resource has been updated
4061
+ *
4062
+ * This method sends a `notifications/resources/updated` notification to all
4063
+ * sessions that have subscribed to the specified resource URI.
4064
+ *
4065
+ * @param uri - The URI of the resource that changed
4066
+ * @returns Promise that resolves when all notifications have been sent
4067
+ *
4068
+ * @example
4069
+ * ```typescript
4070
+ * // After updating a resource, notify subscribers
4071
+ * await server.notifyResourceUpdated("file:///path/to/resource.txt");
4072
+ * ```
4073
+ */
4074
+ async notifyResourceUpdated(uri) {
4075
+ return this.subscriptionManager.notifyResourceUpdated(uri, this.sessions);
4076
+ }
3550
4077
  uiResource = uiResourceRegistration;
3551
4078
  /**
3552
4079
  * Mount MCP server endpoints at /mcp and /sse
@@ -3572,7 +4099,7 @@ var McpServer = class {
3572
4099
  const result = await mountMcp(
3573
4100
  this.app,
3574
4101
  this,
3575
- // Pass the McpServer instance so mountMcp can call getServerForSession()
4102
+ // Pass the MCPServer instance so mountMcp can call getServerForSession()
3576
4103
  this.sessions,
3577
4104
  this.config,
3578
4105
  isProductionMode()
@@ -3630,6 +4157,11 @@ var McpServer = class {
3630
4157
  if (hostEnv) {
3631
4158
  this.serverHost = hostEnv;
3632
4159
  }
4160
+ this.serverBaseUrl = getServerBaseUrl(
4161
+ this.serverBaseUrl,
4162
+ this.serverHost,
4163
+ this.serverPort
4164
+ );
3633
4165
  if (this.oauthConfig && !this.oauthSetupState.complete) {
3634
4166
  await setupOAuthForServer(
3635
4167
  this.app,
@@ -3667,7 +4199,7 @@ var McpServer = class {
3667
4199
  * @example
3668
4200
  * ```typescript
3669
4201
  * // For Supabase Edge Functions (handles path rewriting automatically)
3670
- * const server = createMCPServer('my-server');
4202
+ * const server = new MCPServer({ name: 'my-server', version: '1.0.0' });
3671
4203
  * server.tool({ ... });
3672
4204
  * const handler = await server.getHandler({ provider: 'supabase' });
3673
4205
  * Deno.serve(handler);
@@ -3676,7 +4208,7 @@ var McpServer = class {
3676
4208
  * @example
3677
4209
  * ```typescript
3678
4210
  * // For Cloudflare Workers
3679
- * const server = createMCPServer('my-server');
4211
+ * const server = new MCPServer({ name: 'my-server', version: '1.0.0' });
3680
4212
  * server.tool({ ... });
3681
4213
  * const handler = await server.getHandler();
3682
4214
  * export default { fetch: handler };
@@ -3754,7 +4286,7 @@ var McpServer = class {
3754
4286
  }
3755
4287
  };
3756
4288
  function createMCPServer(name, config = {}) {
3757
- const instance = new McpServer({
4289
+ const instance = new MCPServer({
3758
4290
  name,
3759
4291
  version: config.version || "1.0.0",
3760
4292
  description: config.description,