1
0

@modelcontextprotocol%2Fclient@2.0.0-beta.5.patch 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. diff --git a/dist/index.cjs b/dist/index.cjs
  2. index 1c43bac25a1037416fdf2ddfb4534ba0897a2e69..7e2108326f368ccbc48897195d57e370a4553855 100644
  3. --- a/dist/index.cjs
  4. +++ b/dist/index.cjs
  5. @@ -3154,6 +3154,7 @@ var Client = class extends require_src.Protocol {
  6. */
  7. async _connectPlainLegacy(transport, options) {
  8. await super.connect(transport);
  9. + transport.onsessionexpired = () => this._legacyHandshake(transport, options);
  10. if (transport.sessionId !== void 0) {
  11. const negotiatedProtocolVersion = this._negotiatedProtocolVersion;
  12. if (negotiatedProtocolVersion !== void 0) transport.setProtocolVersion?.(negotiatedProtocolVersion);
  13. @@ -3170,6 +3171,7 @@ var Client = class extends require_src.Protocol {
  14. * the handshake; its completion sets the negotiated (legacy) version.
  15. */
  16. async _legacyHandshake(transport, options) {
  17. + transport.onsessionexpired = () => this._legacyHandshake(transport, options);
  18. const legacyVersions = require_src.legacyProtocolVersions(this._supportedProtocolVersions);
  19. try {
  20. const offeredVersion = legacyVersions[0];
  21. @@ -3208,6 +3210,7 @@ var Client = class extends require_src.Protocol {
  22. await super.connect(transport);
  23. const negotiatedProtocolVersion = this._negotiatedProtocolVersion;
  24. if (negotiatedProtocolVersion !== void 0 && transport.setProtocolVersion) transport.setProtocolVersion(negotiatedProtocolVersion);
  25. + if (negotiatedProtocolVersion !== void 0 && !require_src.isModernProtocolVersion(negotiatedProtocolVersion)) transport.onsessionexpired = () => this._legacyHandshake(transport, options);
  26. return;
  27. }
  28. this._resetConnectionState();
  29. @@ -5211,10 +5214,32 @@ var StreamableHTTPClientTransport = class {
  30. }
  31. }
  32. async send(message, options) {
  33. - return this._send(message, options, false);
  34. + return this._send(message, options, false, 0, false);
  35. + }
  36. + async _recoverSession(expiredSessionId) {
  37. + if (this._sessionRecovery) return this._sessionRecovery;
  38. + if (!this.onsessionexpired) return false;
  39. + if (this._sessionId !== expiredSessionId) return true;
  40. + this._sessionId = void 0;
  41. + this._sessionRecovery = Promise.resolve().then(() => this.onsessionexpired()).then(() => true);
  42. + try {
  43. + return await this._sessionRecovery;
  44. + } catch (error) {
  45. + this._sessionId = void 0;
  46. + await this.close();
  47. + throw error;
  48. + } finally {
  49. + this._sessionRecovery = void 0;
  50. + }
  51. }
  52. - async _send(message, options, isAuthRetry, stepUpRetries = 0) {
  53. + async _send(message, options, isAuthRetry, stepUpRetries = 0, isSessionRetry = false) {
  54. try {
  55. + const isHandshake = Array.isArray(message) ? message.some((m) => require_src.isInitializeRequest(m)) : require_src.isInitializeRequest(message);
  56. + const isInitialized = Array.isArray(message) ? message.some((m) => require_src.isInitializedNotification(m)) : require_src.isInitializedNotification(message);
  57. + if (this._sessionRecovery && !isHandshake && !isInitialized) {
  58. + await this._sessionRecovery;
  59. + options?.requestSignal?.throwIfAborted();
  60. + }
  61. const { resumptionToken, onresumptiontoken } = options || {};
  62. if (resumptionToken) {
  63. this._startOrAuthSse({
  64. @@ -5226,8 +5251,8 @@ var StreamableHTTPClientTransport = class {
  65. }
  66. const headers = await this._commonHeaders();
  67. this._applyBodyDerivedHeaders(headers, message);
  68. - const isHandshake = Array.isArray(message) ? message.some((m) => require_src.isInitializeRequest(m)) : require_src.isInitializeRequest(message);
  69. if (isHandshake) headers.delete("mcp-session-id");
  70. + const requestSessionId = headers.get("mcp-session-id") || void 0;
  71. if (options?.headers !== void 0) for (const [name, value] of Object.entries(options.headers)) {
  72. if (RESERVED_REQUEST_HEADER_NAMES.has(name.toLowerCase())) continue;
  73. headers.set(name, value);
  74. @@ -5249,8 +5274,14 @@ var StreamableHTTPClientTransport = class {
  75. signal
  76. };
  77. const response = await (this._fetch ?? fetch)(this._url, init);
  78. - if (isHandshake && response.ok) this._sessionId = response.headers.get("mcp-session-id") || void 0;
  79. + if (isHandshake && response.ok && (requestSessionId === void 0 || this._sessionId === requestSessionId)) this._sessionId = response.headers.get("mcp-session-id") || void 0;
  80. if (!response.ok) {
  81. + if (response.status === 404 && requestSessionId && !isSessionRetry && !isInitialized) {
  82. + if (await this._recoverSession(requestSessionId)) {
  83. + options?.requestSignal?.throwIfAborted();
  84. + return this._send(message, options, isAuthRetry, stepUpRetries, true);
  85. + }
  86. + }
  87. if (response.status === 401 && this._authProvider) {
  88. if (response.headers.has("www-authenticate")) {
  89. const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
  90. @@ -5264,7 +5295,7 @@ var StreamableHTTPClientTransport = class {
  91. fetchFn: this._fetchWithInit
  92. });
  93. await response.text?.().catch(() => {});
  94. - return this._send(message, options, true, stepUpRetries);
  95. + return this._send(message, options, true, stepUpRetries, isSessionRetry);
  96. }
  97. await response.text?.().catch(() => {});
  98. if (isAuthRetry) throw new require_src.SdkHttpError(require_src.SdkErrorCode.ClientHttpAuthentication, "Server returned 401 after re-authentication", {
  99. @@ -5284,7 +5315,7 @@ var StreamableHTTPClientTransport = class {
  100. statusText: response.statusText,
  101. text
  102. }, stepUpRetries) !== "AUTHORIZED") throw new UnauthorizedError();
  103. - return this._send(message, options, isAuthRetry, stepUpRetries + 1);
  104. + return this._send(message, options, isAuthRetry, stepUpRetries + 1, isSessionRetry);
  105. }
  106. }
  107. if (response.status === 400 && typeof text === "string" && this._isModernEnvelopedRequest(message)) try {
  108. diff --git a/dist/index.mjs b/dist/index.mjs
  109. index 77e2389913cb5c5c2b047f95d990ab2892bef923..4b5e4ff2869189d600ca644488a7749668c39747 100644
  110. --- a/dist/index.mjs
  111. +++ b/dist/index.mjs
  112. @@ -3151,6 +3151,7 @@ var Client = class extends Protocol {
  113. */
  114. async _connectPlainLegacy(transport, options) {
  115. await super.connect(transport);
  116. + transport.onsessionexpired = () => this._legacyHandshake(transport, options);
  117. if (transport.sessionId !== void 0) {
  118. const negotiatedProtocolVersion = this._negotiatedProtocolVersion;
  119. if (negotiatedProtocolVersion !== void 0) transport.setProtocolVersion?.(negotiatedProtocolVersion);
  120. @@ -3167,6 +3168,7 @@ var Client = class extends Protocol {
  121. * the handshake; its completion sets the negotiated (legacy) version.
  122. */
  123. async _legacyHandshake(transport, options) {
  124. + transport.onsessionexpired = () => this._legacyHandshake(transport, options);
  125. const legacyVersions = legacyProtocolVersions(this._supportedProtocolVersions);
  126. try {
  127. const offeredVersion = legacyVersions[0];
  128. @@ -3205,6 +3207,7 @@ var Client = class extends Protocol {
  129. await super.connect(transport);
  130. const negotiatedProtocolVersion = this._negotiatedProtocolVersion;
  131. if (negotiatedProtocolVersion !== void 0 && transport.setProtocolVersion) transport.setProtocolVersion(negotiatedProtocolVersion);
  132. + if (negotiatedProtocolVersion !== void 0 && !isModernProtocolVersion(negotiatedProtocolVersion)) transport.onsessionexpired = () => this._legacyHandshake(transport, options);
  133. return;
  134. }
  135. this._resetConnectionState();
  136. @@ -5208,10 +5211,32 @@ var StreamableHTTPClientTransport = class {
  137. }
  138. }
  139. async send(message, options) {
  140. - return this._send(message, options, false);
  141. + return this._send(message, options, false, 0, false);
  142. + }
  143. + async _recoverSession(expiredSessionId) {
  144. + if (this._sessionRecovery) return this._sessionRecovery;
  145. + if (!this.onsessionexpired) return false;
  146. + if (this._sessionId !== expiredSessionId) return true;
  147. + this._sessionId = void 0;
  148. + this._sessionRecovery = Promise.resolve().then(() => this.onsessionexpired()).then(() => true);
  149. + try {
  150. + return await this._sessionRecovery;
  151. + } catch (error) {
  152. + this._sessionId = void 0;
  153. + await this.close();
  154. + throw error;
  155. + } finally {
  156. + this._sessionRecovery = void 0;
  157. + }
  158. }
  159. - async _send(message, options, isAuthRetry, stepUpRetries = 0) {
  160. + async _send(message, options, isAuthRetry, stepUpRetries = 0, isSessionRetry = false) {
  161. try {
  162. + const isHandshake = Array.isArray(message) ? message.some((m) => isInitializeRequest(m)) : isInitializeRequest(message);
  163. + const isInitialized = Array.isArray(message) ? message.some((m) => isInitializedNotification(m)) : isInitializedNotification(message);
  164. + if (this._sessionRecovery && !isHandshake && !isInitialized) {
  165. + await this._sessionRecovery;
  166. + options?.requestSignal?.throwIfAborted();
  167. + }
  168. const { resumptionToken, onresumptiontoken } = options || {};
  169. if (resumptionToken) {
  170. this._startOrAuthSse({
  171. @@ -5223,8 +5248,8 @@ var StreamableHTTPClientTransport = class {
  172. }
  173. const headers = await this._commonHeaders();
  174. this._applyBodyDerivedHeaders(headers, message);
  175. - const isHandshake = Array.isArray(message) ? message.some((m) => isInitializeRequest(m)) : isInitializeRequest(message);
  176. if (isHandshake) headers.delete("mcp-session-id");
  177. + const requestSessionId = headers.get("mcp-session-id") || void 0;
  178. if (options?.headers !== void 0) for (const [name, value] of Object.entries(options.headers)) {
  179. if (RESERVED_REQUEST_HEADER_NAMES.has(name.toLowerCase())) continue;
  180. headers.set(name, value);
  181. @@ -5246,8 +5271,14 @@ var StreamableHTTPClientTransport = class {
  182. signal
  183. };
  184. const response = await (this._fetch ?? fetch)(this._url, init);
  185. - if (isHandshake && response.ok) this._sessionId = response.headers.get("mcp-session-id") || void 0;
  186. + if (isHandshake && response.ok && (requestSessionId === void 0 || this._sessionId === requestSessionId)) this._sessionId = response.headers.get("mcp-session-id") || void 0;
  187. if (!response.ok) {
  188. + if (response.status === 404 && requestSessionId && !isSessionRetry && !isInitialized) {
  189. + if (await this._recoverSession(requestSessionId)) {
  190. + options?.requestSignal?.throwIfAborted();
  191. + return this._send(message, options, isAuthRetry, stepUpRetries, true);
  192. + }
  193. + }
  194. if (response.status === 401 && this._authProvider) {
  195. if (response.headers.has("www-authenticate")) {
  196. const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
  197. @@ -5261,7 +5292,7 @@ var StreamableHTTPClientTransport = class {
  198. fetchFn: this._fetchWithInit
  199. });
  200. await response.text?.().catch(() => {});
  201. - return this._send(message, options, true, stepUpRetries);
  202. + return this._send(message, options, true, stepUpRetries, isSessionRetry);
  203. }
  204. await response.text?.().catch(() => {});
  205. if (isAuthRetry) throw new SdkHttpError(SdkErrorCode.ClientHttpAuthentication, "Server returned 401 after re-authentication", {
  206. @@ -5281,7 +5312,7 @@ var StreamableHTTPClientTransport = class {
  207. statusText: response.statusText,
  208. text
  209. }, stepUpRetries) !== "AUTHORIZED") throw new UnauthorizedError();
  210. - return this._send(message, options, isAuthRetry, stepUpRetries + 1);
  211. + return this._send(message, options, isAuthRetry, stepUpRetries + 1, isSessionRetry);
  212. }
  213. }
  214. if (response.status === 400 && typeof text === "string" && this._isModernEnvelopedRequest(message)) try {