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
@@ -2,11 +2,12 @@ import {
2
2
  getRequestContext,
3
3
  hasRequestContext,
4
4
  runWithContext
5
- } from "../../chunk-5URNFWCQ.js";
5
+ } from "../../chunk-LWVK6RXA.js";
6
6
  import {
7
7
  createEnhancedContext,
8
- findSessionContext
9
- } from "../../chunk-KHTTBIRP.js";
8
+ findSessionContext,
9
+ isValidLogLevel
10
+ } from "../../chunk-Q3PFK7Y4.js";
10
11
  import {
11
12
  convertToolResultToResourceResult
12
13
  } from "../../chunk-362PI25Z.js";
@@ -31,6 +32,8 @@ import {
31
32
  McpServer as OfficialMcpServer,
32
33
  ResourceTemplate as ResourceTemplate2
33
34
  } from "@modelcontextprotocol/sdk/server/mcp.js";
35
+ import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
36
+ import { z as z2 } from "zod";
34
37
 
35
38
  // src/server/utils/response-helpers.ts
36
39
  function text(content) {
@@ -63,7 +66,109 @@ function image(data, mimeType = "image/png") {
63
66
  };
64
67
  }
65
68
  __name(image, "image");
66
- function resource(uri, mimeType, text2) {
69
+ function getAudioMimeType(filename) {
70
+ const ext = filename.split(".").pop()?.toLowerCase();
71
+ switch (ext) {
72
+ case "wav":
73
+ return "audio/wav";
74
+ case "mp3":
75
+ return "audio/mpeg";
76
+ case "ogg":
77
+ return "audio/ogg";
78
+ case "m4a":
79
+ return "audio/mp4";
80
+ case "webm":
81
+ return "audio/webm";
82
+ case "flac":
83
+ return "audio/flac";
84
+ case "aac":
85
+ return "audio/aac";
86
+ default:
87
+ return "audio/wav";
88
+ }
89
+ }
90
+ __name(getAudioMimeType, "getAudioMimeType");
91
+ function arrayBufferToBase64(buffer) {
92
+ if (isDeno) {
93
+ const bytes = new Uint8Array(buffer);
94
+ let binary2 = "";
95
+ for (let i = 0; i < bytes.length; i++) {
96
+ binary2 += String.fromCharCode(bytes[i]);
97
+ }
98
+ return btoa(binary2);
99
+ } else {
100
+ return Buffer.from(buffer).toString("base64");
101
+ }
102
+ }
103
+ __name(arrayBufferToBase64, "arrayBufferToBase64");
104
+ function audio(dataOrPath, mimeType) {
105
+ const isFilePath = dataOrPath.includes("/") || dataOrPath.includes("\\") || dataOrPath.includes(".");
106
+ if (isFilePath && dataOrPath.length < 1e3) {
107
+ return (async () => {
108
+ const buffer = await fsHelpers.readFile(dataOrPath);
109
+ const base64Data = arrayBufferToBase64(buffer);
110
+ const inferredMimeType = mimeType || getAudioMimeType(dataOrPath);
111
+ return {
112
+ content: [
113
+ {
114
+ type: "audio",
115
+ data: base64Data,
116
+ mimeType: inferredMimeType
117
+ }
118
+ ],
119
+ _meta: {
120
+ mimeType: inferredMimeType,
121
+ isAudio: true
122
+ }
123
+ };
124
+ })();
125
+ }
126
+ const finalMimeType = mimeType || "audio/wav";
127
+ return {
128
+ content: [
129
+ {
130
+ type: "audio",
131
+ data: dataOrPath,
132
+ mimeType: finalMimeType
133
+ }
134
+ ],
135
+ _meta: {
136
+ mimeType: finalMimeType,
137
+ isAudio: true
138
+ }
139
+ };
140
+ }
141
+ __name(audio, "audio");
142
+ function resource(uri, mimeTypeOrContent, text2) {
143
+ if (typeof mimeTypeOrContent === "object" && mimeTypeOrContent !== null && "content" in mimeTypeOrContent) {
144
+ const contentResult = mimeTypeOrContent;
145
+ let extractedText;
146
+ let extractedMimeType;
147
+ if (contentResult._meta && typeof contentResult._meta === "object") {
148
+ const meta = contentResult._meta;
149
+ if (meta.mimeType && typeof meta.mimeType === "string") {
150
+ extractedMimeType = meta.mimeType;
151
+ }
152
+ }
153
+ if (contentResult.content && contentResult.content.length > 0) {
154
+ const firstContent = contentResult.content[0];
155
+ if (firstContent.type === "text" && "text" in firstContent) {
156
+ extractedText = firstContent.text;
157
+ }
158
+ }
159
+ const resourceContent2 = {
160
+ type: "resource",
161
+ resource: {
162
+ uri,
163
+ ...extractedMimeType && { mimeType: extractedMimeType },
164
+ ...extractedText && { text: extractedText }
165
+ }
166
+ };
167
+ return {
168
+ content: [resourceContent2]
169
+ };
170
+ }
171
+ const mimeType = mimeTypeOrContent;
67
172
  const resourceContent = {
68
173
  type: "resource",
69
174
  resource: {
@@ -338,7 +443,7 @@ function parseTemplateUri(template, uri) {
338
443
  const params = {};
339
444
  let regexPattern = template.replace(/[.*+?^$()[\]\\|]/g, "\\$&");
340
445
  const paramNames = [];
341
- regexPattern = regexPattern.replace(/\\\{([^}]+)\\\}/g, (_, paramName) => {
446
+ regexPattern = regexPattern.replace(/\{([^}]+)\}/g, (_, paramName) => {
342
447
  paramNames.push(paramName);
343
448
  return "([^/]+)";
344
449
  });
@@ -1762,7 +1867,7 @@ function toolRegistration(toolDefinition, callback) {
1762
1867
  const initialRequestContext = getRequestContext();
1763
1868
  const extraProgressToken = extra?._meta?.progressToken;
1764
1869
  const extraSendNotification = extra?.sendNotification;
1765
- const { requestContext, progressToken, sendNotification: sendNotification2 } = findSessionContext(
1870
+ const { requestContext, session, progressToken, sendNotification: sendNotification2 } = findSessionContext(
1766
1871
  this.sessions,
1767
1872
  initialRequestContext,
1768
1873
  extraProgressToken,
@@ -1773,7 +1878,9 @@ function toolRegistration(toolDefinition, callback) {
1773
1878
  this.createMessage.bind(this),
1774
1879
  this.server.server.elicitInput.bind(this.server.server),
1775
1880
  progressToken,
1776
- sendNotification2
1881
+ sendNotification2,
1882
+ session?.logLevel,
1883
+ session?.clientCapabilities
1777
1884
  );
1778
1885
  const executeCallback = /* @__PURE__ */ __name(async () => {
1779
1886
  if (actualCallback.length >= 2) {
@@ -1794,6 +1901,154 @@ __name(toolRegistration, "toolRegistration");
1794
1901
 
1795
1902
  // src/server/resources/index.ts
1796
1903
  import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
1904
+
1905
+ // src/server/resources/subscriptions.ts
1906
+ import {
1907
+ SubscribeRequestSchema,
1908
+ UnsubscribeRequestSchema
1909
+ } from "@modelcontextprotocol/sdk/types.js";
1910
+ var ResourceSubscriptionManager = class {
1911
+ static {
1912
+ __name(this, "ResourceSubscriptionManager");
1913
+ }
1914
+ /**
1915
+ * Tracks resource subscriptions per session
1916
+ * Map structure: uri -> Set<sessionId>
1917
+ */
1918
+ subscriptions = /* @__PURE__ */ new Map();
1919
+ /**
1920
+ * Register subscription handlers with an MCP server instance
1921
+ *
1922
+ * @param server - The native MCP server instance
1923
+ * @param sessions - Map of active sessions
1924
+ */
1925
+ registerHandlers(server, sessions) {
1926
+ server.server.setRequestHandler(
1927
+ SubscribeRequestSchema,
1928
+ async (request) => {
1929
+ const { uri } = request.params;
1930
+ const sessionId = this.getSessionIdFromContext(sessions, server);
1931
+ if (!sessionId) {
1932
+ console.warn(
1933
+ `[MCP] Could not determine session ID for resource subscription to ${uri}`
1934
+ );
1935
+ return {};
1936
+ }
1937
+ if (!this.subscriptions.has(uri)) {
1938
+ this.subscriptions.set(uri, /* @__PURE__ */ new Set());
1939
+ }
1940
+ this.subscriptions.get(uri).add(sessionId);
1941
+ console.log(
1942
+ `[MCP] Session ${sessionId} subscribed to resource: ${uri}`
1943
+ );
1944
+ return {};
1945
+ }
1946
+ );
1947
+ server.server.setRequestHandler(
1948
+ UnsubscribeRequestSchema,
1949
+ async (request) => {
1950
+ const { uri } = request.params;
1951
+ const sessionId = this.getSessionIdFromContext(sessions, server);
1952
+ if (!sessionId) {
1953
+ console.warn(
1954
+ `[MCP] Could not determine session ID for resource unsubscribe from ${uri}`
1955
+ );
1956
+ return {};
1957
+ }
1958
+ const subscribers = this.subscriptions.get(uri);
1959
+ if (subscribers) {
1960
+ subscribers.delete(sessionId);
1961
+ if (subscribers.size === 0) {
1962
+ this.subscriptions.delete(uri);
1963
+ }
1964
+ console.log(
1965
+ `[MCP] Session ${sessionId} unsubscribed from resource: ${uri}`
1966
+ );
1967
+ }
1968
+ return {};
1969
+ }
1970
+ );
1971
+ }
1972
+ /**
1973
+ * Get session ID from request context or sessions map
1974
+ *
1975
+ * @param sessions - Map of active sessions
1976
+ * @param server - The server instance to match against
1977
+ * @returns The session ID, or undefined if not found
1978
+ */
1979
+ getSessionIdFromContext(sessions, server) {
1980
+ const requestContext = getRequestContext();
1981
+ let sessionId;
1982
+ if (requestContext) {
1983
+ sessionId = requestContext.req.header("mcp-session-id");
1984
+ }
1985
+ if (!sessionId) {
1986
+ for (const [sid, session] of sessions.entries()) {
1987
+ if (session.server === server) {
1988
+ sessionId = sid;
1989
+ break;
1990
+ }
1991
+ }
1992
+ }
1993
+ return sessionId;
1994
+ }
1995
+ /**
1996
+ * Notify subscribed clients that a resource has been updated
1997
+ *
1998
+ * This method sends a `notifications/resources/updated` notification to all
1999
+ * sessions that have subscribed to the specified resource URI.
2000
+ *
2001
+ * @param uri - The URI of the resource that changed
2002
+ * @param sessions - Map of active sessions
2003
+ * @returns Promise that resolves when all notifications have been sent
2004
+ */
2005
+ async notifyResourceUpdated(uri, sessions) {
2006
+ const subscribers = this.subscriptions.get(uri);
2007
+ if (!subscribers || subscribers.size === 0) {
2008
+ return;
2009
+ }
2010
+ console.log(
2011
+ `[MCP] Notifying ${subscribers.size} subscriber(s) of resource update: ${uri}`
2012
+ );
2013
+ for (const sessionId of subscribers) {
2014
+ const session = sessions.get(sessionId);
2015
+ if (session?.server) {
2016
+ try {
2017
+ await session.server.server.sendResourceUpdated({ uri });
2018
+ console.log(
2019
+ `[MCP] Sent resource update notification to session ${sessionId}`
2020
+ );
2021
+ } catch (error2) {
2022
+ console.error(
2023
+ `[MCP] Failed to send resource update notification to session ${sessionId}:`,
2024
+ error2
2025
+ );
2026
+ }
2027
+ }
2028
+ }
2029
+ }
2030
+ /**
2031
+ * Clean up resource subscriptions for a closed session
2032
+ *
2033
+ * This method is called automatically when a session is closed to remove
2034
+ * all resource subscriptions associated with that session.
2035
+ *
2036
+ * @param sessionId - The session ID to clean up
2037
+ */
2038
+ cleanupSession(sessionId) {
2039
+ for (const [uri, subscribers] of this.subscriptions) {
2040
+ subscribers.delete(sessionId);
2041
+ if (subscribers.size === 0) {
2042
+ this.subscriptions.delete(uri);
2043
+ }
2044
+ }
2045
+ console.log(
2046
+ `[MCP] Cleaned up resource subscriptions for session ${sessionId}`
2047
+ );
2048
+ }
2049
+ };
2050
+
2051
+ // src/server/resources/index.ts
1797
2052
  function registerResource(resourceDefinition, callback) {
1798
2053
  const actualCallback = callback || resourceDefinition.readCallback;
1799
2054
  if (!actualCallback) {
@@ -1803,8 +2058,8 @@ function registerResource(resourceDefinition, callback) {
1803
2058
  }
1804
2059
  const explicitMimeType = resourceDefinition.mimeType;
1805
2060
  const wrappedCallback = /* @__PURE__ */ __name(async () => {
1806
- const { getRequestContext: getRequestContext2, runWithContext: runWithContext2 } = await import("../../context-storage-TXQ4DVSS.js");
1807
- const { findSessionContext: findSessionContext2 } = await import("../../tool-execution-helpers-IVUDHXMK.js");
2061
+ const { getRequestContext: getRequestContext2, runWithContext: runWithContext2 } = await import("../../context-storage-NA4MHWOZ.js");
2062
+ const { findSessionContext: findSessionContext2 } = await import("../../tool-execution-helpers-RRMGLAHR.js");
1808
2063
  const initialRequestContext = getRequestContext2();
1809
2064
  const sessions = this.sessions || /* @__PURE__ */ new Map();
1810
2065
  const { requestContext } = findSessionContext2(
@@ -1852,24 +2107,25 @@ function registerResourceTemplate(resourceTemplateDefinition, callback) {
1852
2107
  `Resource template '${resourceTemplateDefinition.name}' must have either a readCallback property or a callback parameter`
1853
2108
  );
1854
2109
  }
1855
- const template = new ResourceTemplate(
1856
- resourceTemplateDefinition.resourceTemplate.uriTemplate,
1857
- {
1858
- list: void 0,
1859
- // Optional: callback to list all matching resources
1860
- complete: void 0
1861
- // Optional: callback for auto-completion
1862
- }
1863
- );
2110
+ const isFlatStructure = "uriTemplate" in resourceTemplateDefinition;
2111
+ const uriTemplate = isFlatStructure ? resourceTemplateDefinition.uriTemplate : resourceTemplateDefinition.resourceTemplate.uriTemplate;
2112
+ const mimeType = isFlatStructure ? resourceTemplateDefinition.mimeType : resourceTemplateDefinition.resourceTemplate.mimeType;
2113
+ const templateDescription = isFlatStructure ? void 0 : resourceTemplateDefinition.resourceTemplate.description;
2114
+ const template = new ResourceTemplate(uriTemplate, {
2115
+ list: void 0,
2116
+ // Optional: callback to list all matching resources
2117
+ complete: void 0
2118
+ // Optional: callback for auto-completion
2119
+ });
1864
2120
  const metadata = {};
1865
2121
  if (resourceTemplateDefinition.title) {
1866
2122
  metadata.title = resourceTemplateDefinition.title;
1867
2123
  }
1868
- if (resourceTemplateDefinition.description || resourceTemplateDefinition.resourceTemplate.description) {
1869
- metadata.description = resourceTemplateDefinition.description || resourceTemplateDefinition.resourceTemplate.description;
2124
+ if (resourceTemplateDefinition.description || templateDescription) {
2125
+ metadata.description = resourceTemplateDefinition.description || templateDescription;
1870
2126
  }
1871
- if (resourceTemplateDefinition.resourceTemplate.mimeType) {
1872
- metadata.mimeType = resourceTemplateDefinition.resourceTemplate.mimeType;
2127
+ if (mimeType) {
2128
+ metadata.mimeType = mimeType;
1873
2129
  }
1874
2130
  if (resourceTemplateDefinition.annotations) {
1875
2131
  metadata.annotations = resourceTemplateDefinition.annotations;
@@ -1879,12 +2135,9 @@ function registerResourceTemplate(resourceTemplateDefinition, callback) {
1879
2135
  template,
1880
2136
  metadata,
1881
2137
  async (uri) => {
1882
- const params = this.parseTemplateUri(
1883
- resourceTemplateDefinition.resourceTemplate.uriTemplate,
1884
- uri.toString()
1885
- );
1886
- const { getRequestContext: getRequestContext2, runWithContext: runWithContext2 } = await import("../../context-storage-TXQ4DVSS.js");
1887
- const { findSessionContext: findSessionContext2 } = await import("../../tool-execution-helpers-IVUDHXMK.js");
2138
+ const params = this.parseTemplateUri(uriTemplate, uri.toString());
2139
+ const { getRequestContext: getRequestContext2, runWithContext: runWithContext2 } = await import("../../context-storage-NA4MHWOZ.js");
2140
+ const { findSessionContext: findSessionContext2 } = await import("../../tool-execution-helpers-RRMGLAHR.js");
1888
2141
  const initialRequestContext = getRequestContext2();
1889
2142
  const sessions = this.sessions || /* @__PURE__ */ new Map();
1890
2143
  const { requestContext } = findSessionContext2(
@@ -1897,8 +2150,12 @@ function registerResourceTemplate(resourceTemplateDefinition, callback) {
1897
2150
  const executeCallback = /* @__PURE__ */ __name(async () => {
1898
2151
  if (actualCallback.length >= 3) {
1899
2152
  return await actualCallback(uri, params, enhancedContext);
2153
+ } else if (actualCallback.length === 2) {
2154
+ return await actualCallback(uri, params);
2155
+ } else if (actualCallback.length === 1) {
2156
+ return await actualCallback(uri);
1900
2157
  }
1901
- return await actualCallback(uri, params);
2158
+ return await actualCallback();
1902
2159
  }, "executeCallback");
1903
2160
  const result = requestContext ? await runWithContext2(requestContext, executeCallback) : await executeCallback();
1904
2161
  if ("contents" in result && Array.isArray(result.contents)) {
@@ -1928,12 +2185,14 @@ function registerPrompt(promptDefinition, callback) {
1928
2185
  argsSchema = this.convertZodSchemaToParams(
1929
2186
  promptDefinition.schema
1930
2187
  );
2188
+ } else if (promptDefinition.args && promptDefinition.args.length > 0) {
2189
+ argsSchema = this.createParamsSchema(promptDefinition.args);
1931
2190
  } else {
1932
- argsSchema = this.createParamsSchema(promptDefinition.args || []);
2191
+ argsSchema = void 0;
1933
2192
  }
1934
2193
  const wrappedCallback = /* @__PURE__ */ __name(async (params, extra) => {
1935
- const { getRequestContext: getRequestContext2, runWithContext: runWithContext2 } = await import("../../context-storage-TXQ4DVSS.js");
1936
- const { findSessionContext: findSessionContext2 } = await import("../../tool-execution-helpers-IVUDHXMK.js");
2194
+ const { getRequestContext: getRequestContext2, runWithContext: runWithContext2 } = await import("../../context-storage-NA4MHWOZ.js");
2195
+ const { findSessionContext: findSessionContext2 } = await import("../../tool-execution-helpers-RRMGLAHR.js");
1937
2196
  const initialRequestContext = getRequestContext2();
1938
2197
  const sessions = this.sessions || /* @__PURE__ */ new Map();
1939
2198
  const { requestContext } = findSessionContext2(
@@ -2204,7 +2463,7 @@ async function sendNotificationToSession2(sessionId, method, params) {
2204
2463
  __name(sendNotificationToSession2, "sendNotificationToSession");
2205
2464
 
2206
2465
  // src/server/sessions/session-manager.ts
2207
- function startIdleCleanup(sessions, idleTimeoutMs) {
2466
+ function startIdleCleanup(sessions, idleTimeoutMs, mcpServerInstance) {
2208
2467
  if (idleTimeoutMs <= 0) {
2209
2468
  return void 0;
2210
2469
  }
@@ -2222,6 +2481,7 @@ function startIdleCleanup(sessions, idleTimeoutMs) {
2222
2481
  );
2223
2482
  for (const sessionId of expiredSessions) {
2224
2483
  sessions.delete(sessionId);
2484
+ mcpServerInstance?.cleanupSessionSubscriptions?.(sessionId);
2225
2485
  }
2226
2486
  }
2227
2487
  }, 6e4);
@@ -2235,7 +2495,11 @@ async function mountMcp(app, mcpServerInstance, sessions, config, isProductionMo
2235
2495
  const transports = /* @__PURE__ */ new Map();
2236
2496
  let idleCleanupInterval;
2237
2497
  if (idleTimeoutMs > 0) {
2238
- idleCleanupInterval = startIdleCleanup(sessions, idleTimeoutMs);
2498
+ idleCleanupInterval = startIdleCleanup(
2499
+ sessions,
2500
+ idleTimeoutMs,
2501
+ mcpServerInstance
2502
+ );
2239
2503
  }
2240
2504
  const handleRequest = /* @__PURE__ */ __name(async (c) => {
2241
2505
  const sessionId = c.req.header("mcp-session-id");
@@ -2262,11 +2526,23 @@ async function mountMcp(app, mcpServerInstance, sessions, config, isProductionMo
2262
2526
  context: c,
2263
2527
  honoContext: c
2264
2528
  });
2529
+ server.server.oninitialized = () => {
2530
+ const clientCapabilities = server.server.getClientCapabilities();
2531
+ if (clientCapabilities && sessions.has(sid)) {
2532
+ const session = sessions.get(sid);
2533
+ session.clientCapabilities = clientCapabilities;
2534
+ console.log(
2535
+ `[MCP] Captured client capabilities for session ${sid}:`,
2536
+ Object.keys(clientCapabilities)
2537
+ );
2538
+ }
2539
+ };
2265
2540
  }, "onsessioninitialized"),
2266
2541
  onsessionclosed: /* @__PURE__ */ __name((sid) => {
2267
2542
  console.log(`[MCP] Session closed: ${sid}`);
2268
2543
  transports.delete(sid);
2269
2544
  sessions.delete(sid);
2545
+ mcpServerInstance.cleanupSessionSubscriptions?.(sid);
2270
2546
  }, "onsessionclosed")
2271
2547
  });
2272
2548
  await server.connect(transport);
@@ -2557,9 +2833,9 @@ async function setupOAuthForServer(app, oauthProvider, baseUrl, state) {
2557
2833
  __name(setupOAuthForServer, "setupOAuthForServer");
2558
2834
 
2559
2835
  // src/server/mcp-server.ts
2560
- var McpServer = class {
2836
+ var MCPServer = class {
2561
2837
  static {
2562
- __name(this, "McpServer");
2838
+ __name(this, "MCPServer");
2563
2839
  }
2564
2840
  /**
2565
2841
  * Native MCP server instance from @modelcontextprotocol/sdk
@@ -2602,6 +2878,22 @@ var McpServer = class {
2602
2878
  resources: /* @__PURE__ */ new Map(),
2603
2879
  resourceTemplates: /* @__PURE__ */ new Map()
2604
2880
  };
2881
+ /**
2882
+ * Resource subscription manager for tracking and notifying resource updates
2883
+ */
2884
+ subscriptionManager = new ResourceSubscriptionManager();
2885
+ /**
2886
+ * Clean up resource subscriptions for a closed session
2887
+ *
2888
+ * This method is called automatically when a session is closed to remove
2889
+ * all resource subscriptions associated with that session.
2890
+ *
2891
+ * @param sessionId - The session ID to clean up
2892
+ * @internal
2893
+ */
2894
+ cleanupSessionSubscriptions(sessionId) {
2895
+ this.subscriptionManager.cleanupSession(sessionId);
2896
+ }
2605
2897
  /**
2606
2898
  * Creates a new MCP server instance with Hono integration
2607
2899
  *
@@ -2610,16 +2902,27 @@ var McpServer = class {
2610
2902
  * access to Hono methods while preserving MCP server functionality.
2611
2903
  *
2612
2904
  * @param config - Server configuration including name, version, and description
2613
- * @returns A proxied McpServer instance that supports both MCP and Hono methods
2905
+ * @returns A proxied MCPServer instance that supports both MCP and Hono methods
2614
2906
  */
2615
2907
  constructor(config) {
2616
2908
  this.config = config;
2617
2909
  this.serverHost = config.host || "localhost";
2618
2910
  this.serverBaseUrl = config.baseUrl;
2619
- this.nativeServer = new OfficialMcpServer({
2620
- name: config.name,
2621
- version: config.version
2622
- });
2911
+ this.nativeServer = new OfficialMcpServer(
2912
+ {
2913
+ name: config.name,
2914
+ version: config.version
2915
+ },
2916
+ {
2917
+ capabilities: {
2918
+ logging: {},
2919
+ resources: {
2920
+ subscribe: true,
2921
+ listChanged: true
2922
+ }
2923
+ }
2924
+ }
2925
+ );
2623
2926
  this.app = createHonoApp(requestLogger);
2624
2927
  this.oauthConfig = config.oauth;
2625
2928
  this.wrapRegistrationMethods();
@@ -2674,10 +2977,17 @@ var McpServer = class {
2674
2977
  * This is called for each initialize request to create an isolated server.
2675
2978
  */
2676
2979
  getServerForSession() {
2677
- const newServer = new OfficialMcpServer({
2678
- name: this.config.name,
2679
- version: this.config.version
2680
- });
2980
+ const newServer = new OfficialMcpServer(
2981
+ {
2982
+ name: this.config.name,
2983
+ version: this.config.version
2984
+ },
2985
+ {
2986
+ capabilities: {
2987
+ logging: {}
2988
+ }
2989
+ }
2990
+ );
2681
2991
  for (const [name, recipe] of this.registrationRecipes.tools) {
2682
2992
  const { config, handler: actualCallback } = recipe;
2683
2993
  let inputSchema;
@@ -2692,12 +3002,21 @@ var McpServer = class {
2692
3002
  const initialRequestContext = getRequestContext();
2693
3003
  const extraProgressToken = extra?._meta?.progressToken;
2694
3004
  const extraSendNotification = extra?.sendNotification;
2695
- const { requestContext, progressToken, sendNotification: sendNotification2 } = findSessionContext(
3005
+ const { requestContext, session, progressToken, sendNotification: sendNotification2 } = findSessionContext(
2696
3006
  this.sessions,
2697
3007
  initialRequestContext,
2698
3008
  extraProgressToken,
2699
3009
  extraSendNotification
2700
3010
  );
3011
+ let sessionId;
3012
+ if (session) {
3013
+ for (const [id, s] of this.sessions.entries()) {
3014
+ if (s === session) {
3015
+ sessionId = id;
3016
+ break;
3017
+ }
3018
+ }
3019
+ }
2701
3020
  const createMessageWithLogging = /* @__PURE__ */ __name(async (params2, options) => {
2702
3021
  console.log("[createMessage] About to call server.createMessage");
2703
3022
  console.log("[createMessage] Has server:", !!newServer);
@@ -2723,7 +3042,11 @@ var McpServer = class {
2723
3042
  createMessageWithLogging,
2724
3043
  newServer.server.elicitInput.bind(newServer.server),
2725
3044
  progressToken,
2726
- sendNotification2
3045
+ sendNotification2,
3046
+ session?.logLevel,
3047
+ session?.clientCapabilities,
3048
+ sessionId,
3049
+ this.sessions
2727
3050
  );
2728
3051
  const executeCallback = /* @__PURE__ */ __name(async () => {
2729
3052
  if (actualCallback.length >= 2) {
@@ -2753,8 +3076,10 @@ var McpServer = class {
2753
3076
  let argsSchema;
2754
3077
  if (config.schema) {
2755
3078
  argsSchema = this.convertZodSchemaToParams(config.schema);
3079
+ } else if (config.args && config.args.length > 0) {
3080
+ argsSchema = this.createParamsSchema(config.args);
2756
3081
  } else {
2757
- argsSchema = this.createParamsSchema(config.args || []);
3082
+ argsSchema = void 0;
2758
3083
  }
2759
3084
  const wrappedHandler = /* @__PURE__ */ __name(async (params) => {
2760
3085
  const result = await handler(params);
@@ -2797,22 +3122,23 @@ var McpServer = class {
2797
3122
  }
2798
3123
  for (const [_name, recipe] of this.registrationRecipes.resourceTemplates) {
2799
3124
  const { config, handler } = recipe;
2800
- const template = new ResourceTemplate2(
2801
- config.resourceTemplate.uriTemplate,
2802
- {
2803
- list: void 0,
2804
- complete: void 0
2805
- }
2806
- );
3125
+ const isFlatStructure = "uriTemplate" in config;
3126
+ const uriTemplate = isFlatStructure ? config.uriTemplate : config.resourceTemplate.uriTemplate;
3127
+ const mimeType = isFlatStructure ? config.mimeType : config.resourceTemplate.mimeType;
3128
+ const templateDescription = isFlatStructure ? void 0 : config.resourceTemplate.description;
3129
+ const template = new ResourceTemplate2(uriTemplate, {
3130
+ list: void 0,
3131
+ complete: void 0
3132
+ });
2807
3133
  const metadata = {};
2808
3134
  if (config.title) {
2809
3135
  metadata.title = config.title;
2810
3136
  }
2811
- if (config.description || config.resourceTemplate.description) {
2812
- metadata.description = config.description || config.resourceTemplate.description;
3137
+ if (config.description || templateDescription) {
3138
+ metadata.description = config.description || templateDescription;
2813
3139
  }
2814
- if (config.resourceTemplate.mimeType) {
2815
- metadata.mimeType = config.resourceTemplate.mimeType;
3140
+ if (mimeType) {
3141
+ metadata.mimeType = mimeType;
2816
3142
  }
2817
3143
  if (config.annotations) {
2818
3144
  metadata.annotations = config.annotations;
@@ -2822,10 +3148,7 @@ var McpServer = class {
2822
3148
  template,
2823
3149
  metadata,
2824
3150
  async (uri) => {
2825
- const params = this.parseTemplateUri(
2826
- config.resourceTemplate.uriTemplate,
2827
- uri.toString()
2828
- );
3151
+ const params = this.parseTemplateUri(uriTemplate, uri.toString());
2829
3152
  const result = await handler(uri, params);
2830
3153
  if ("contents" in result && Array.isArray(result.contents)) {
2831
3154
  return result;
@@ -2835,6 +3158,50 @@ var McpServer = class {
2835
3158
  }
2836
3159
  );
2837
3160
  }
3161
+ newServer.server.setRequestHandler(
3162
+ z2.object({ method: z2.literal("logging/setLevel") }).passthrough(),
3163
+ async (request) => {
3164
+ const level = request.params?.level;
3165
+ if (!level) {
3166
+ throw new McpError(
3167
+ ErrorCode.InvalidParams,
3168
+ "Missing 'level' parameter"
3169
+ );
3170
+ }
3171
+ if (!isValidLogLevel(level)) {
3172
+ throw new McpError(
3173
+ ErrorCode.InvalidParams,
3174
+ `Invalid log level '${level}'. Must be one of: debug, info, notice, warning, error, critical, alert, emergency`
3175
+ );
3176
+ }
3177
+ const requestContext = getRequestContext();
3178
+ if (requestContext) {
3179
+ const sessionId = requestContext.req.header("mcp-session-id");
3180
+ if (sessionId && this.sessions.has(sessionId)) {
3181
+ const session = this.sessions.get(sessionId);
3182
+ session.logLevel = level;
3183
+ console.log(
3184
+ `[MCP] Set log level to '${level}' for session ${sessionId}`
3185
+ );
3186
+ return {};
3187
+ }
3188
+ }
3189
+ for (const [sessionId, session] of this.sessions.entries()) {
3190
+ if (session.server === newServer) {
3191
+ session.logLevel = level;
3192
+ console.log(
3193
+ `[MCP] Set log level to '${level}' for session ${sessionId}`
3194
+ );
3195
+ return {};
3196
+ }
3197
+ }
3198
+ console.warn(
3199
+ "[MCP] Could not find session for logging/setLevel request"
3200
+ );
3201
+ throw new McpError(ErrorCode.InternalError, "Could not find session");
3202
+ }
3203
+ );
3204
+ this.subscriptionManager.registerHandlers(newServer, this.sessions);
2838
3205
  return newServer;
2839
3206
  }
2840
3207
  /**
@@ -2864,6 +3231,24 @@ var McpServer = class {
2864
3231
  getActiveSessions = getActiveSessions;
2865
3232
  sendNotification = sendNotification;
2866
3233
  sendNotificationToSession = sendNotificationToSession2;
3234
+ /**
3235
+ * Notify subscribed clients that a resource has been updated
3236
+ *
3237
+ * This method sends a `notifications/resources/updated` notification to all
3238
+ * sessions that have subscribed to the specified resource URI.
3239
+ *
3240
+ * @param uri - The URI of the resource that changed
3241
+ * @returns Promise that resolves when all notifications have been sent
3242
+ *
3243
+ * @example
3244
+ * ```typescript
3245
+ * // After updating a resource, notify subscribers
3246
+ * await server.notifyResourceUpdated("file:///path/to/resource.txt");
3247
+ * ```
3248
+ */
3249
+ async notifyResourceUpdated(uri) {
3250
+ return this.subscriptionManager.notifyResourceUpdated(uri, this.sessions);
3251
+ }
2867
3252
  uiResource = uiResourceRegistration;
2868
3253
  /**
2869
3254
  * Mount MCP server endpoints at /mcp and /sse
@@ -2889,7 +3274,7 @@ var McpServer = class {
2889
3274
  const result = await mountMcp(
2890
3275
  this.app,
2891
3276
  this,
2892
- // Pass the McpServer instance so mountMcp can call getServerForSession()
3277
+ // Pass the MCPServer instance so mountMcp can call getServerForSession()
2893
3278
  this.sessions,
2894
3279
  this.config,
2895
3280
  isProductionMode()
@@ -2947,6 +3332,11 @@ var McpServer = class {
2947
3332
  if (hostEnv) {
2948
3333
  this.serverHost = hostEnv;
2949
3334
  }
3335
+ this.serverBaseUrl = getServerBaseUrl(
3336
+ this.serverBaseUrl,
3337
+ this.serverHost,
3338
+ this.serverPort
3339
+ );
2950
3340
  if (this.oauthConfig && !this.oauthSetupState.complete) {
2951
3341
  await setupOAuthForServer(
2952
3342
  this.app,
@@ -2984,7 +3374,7 @@ var McpServer = class {
2984
3374
  * @example
2985
3375
  * ```typescript
2986
3376
  * // For Supabase Edge Functions (handles path rewriting automatically)
2987
- * const server = createMCPServer('my-server');
3377
+ * const server = new MCPServer({ name: 'my-server', version: '1.0.0' });
2988
3378
  * server.tool({ ... });
2989
3379
  * const handler = await server.getHandler({ provider: 'supabase' });
2990
3380
  * Deno.serve(handler);
@@ -2993,7 +3383,7 @@ var McpServer = class {
2993
3383
  * @example
2994
3384
  * ```typescript
2995
3385
  * // For Cloudflare Workers
2996
- * const server = createMCPServer('my-server');
3386
+ * const server = new MCPServer({ name: 'my-server', version: '1.0.0' });
2997
3387
  * server.tool({ ... });
2998
3388
  * const handler = await server.getHandler();
2999
3389
  * export default { fetch: handler };
@@ -3071,7 +3461,7 @@ var McpServer = class {
3071
3461
  }
3072
3462
  };
3073
3463
  function createMCPServer(name, config = {}) {
3074
- const instance = new McpServer({
3464
+ const instance = new MCPServer({
3075
3465
  name,
3076
3466
  version: config.version || "1.0.0",
3077
3467
  description: config.description,
@@ -3674,9 +4064,11 @@ function requireAnyScope(needed) {
3674
4064
  }
3675
4065
  __name(requireAnyScope, "requireAnyScope");
3676
4066
  export {
4067
+ MCPServer,
3677
4068
  adaptConnectMiddleware,
3678
4069
  adaptMiddleware,
3679
4070
  array,
4071
+ audio,
3680
4072
  binary,
3681
4073
  buildWidgetUrl,
3682
4074
  createExternalUrlResource,