@lanonasis/oauth-client 1.2.2 → 1.2.3

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/browser.cjs CHANGED
@@ -247,300 +247,8 @@ var DesktopOAuthFlow = class extends BaseOAuthFlow {
247
247
  }
248
248
  };
249
249
 
250
- // src/client/mcp-client.ts
251
- var import_cross_fetch4 = __toESM(require("cross-fetch"), 1);
252
-
253
- // src/storage/token-storage.ts
254
- var TokenStorage = class {
255
- constructor() {
256
- this.storageKey = "lanonasis_mcp_tokens";
257
- this.webEncryptionKeyStorage = "lanonasis_web_token_enc_key";
258
- if (this.isNode()) {
259
- try {
260
- this.keytar = require("keytar");
261
- } catch (e) {
262
- console.warn("Keytar not available - falling back to file storage");
263
- }
264
- }
265
- }
266
- async store(tokens) {
267
- const tokensWithTimestamp = {
268
- ...tokens,
269
- issued_at: Date.now()
270
- };
271
- const tokenString = JSON.stringify(tokensWithTimestamp);
272
- if (this.isNode()) {
273
- if (this.keytar) {
274
- await this.keytar.setPassword("lanonasis-mcp", "tokens", tokenString);
275
- } else {
276
- await this.storeToFile(tokenString);
277
- }
278
- } else if (this.isElectron()) {
279
- await window.electronAPI.secureStore.set(this.storageKey, tokensWithTimestamp);
280
- } else if (this.isMobile()) {
281
- await window.SecureStorage.set(this.storageKey, tokenString);
282
- } else {
283
- const encrypted = await this.encrypt(tokenString);
284
- localStorage.setItem(this.storageKey, encrypted);
285
- }
286
- }
287
- async retrieve() {
288
- let tokenString = null;
289
- try {
290
- if (this.isNode()) {
291
- if (this.keytar) {
292
- tokenString = await this.keytar.getPassword("lanonasis-mcp", "tokens");
293
- }
294
- if (!tokenString) {
295
- tokenString = await this.retrieveFromFile();
296
- }
297
- } else if (this.isElectron()) {
298
- const tokens = await window.electronAPI.secureStore.get(this.storageKey);
299
- return tokens || null;
300
- } else if (this.isMobile()) {
301
- tokenString = await window.SecureStorage.get(this.storageKey);
302
- } else {
303
- const encrypted = localStorage.getItem(this.storageKey);
304
- if (encrypted) {
305
- tokenString = await this.decrypt(encrypted);
306
- }
307
- }
308
- return tokenString ? JSON.parse(tokenString) : null;
309
- } catch (error) {
310
- console.error("Error retrieving tokens:", error);
311
- return null;
312
- }
313
- }
314
- async clear() {
315
- if (this.isNode()) {
316
- if (this.keytar) {
317
- await this.keytar.deletePassword("lanonasis-mcp", "tokens");
318
- }
319
- await this.deleteFile();
320
- } else if (this.isElectron()) {
321
- await window.electronAPI.secureStore.delete(this.storageKey);
322
- } else if (this.isMobile()) {
323
- await window.SecureStorage.remove(this.storageKey);
324
- } else {
325
- localStorage.removeItem(this.storageKey);
326
- }
327
- }
328
- isTokenExpired(tokens) {
329
- if (tokens.token_type === "api-key" || tokens.expires_in === 0) {
330
- return false;
331
- }
332
- if (!tokens.expires_in) return false;
333
- if (!tokens.issued_at) {
334
- console.warn("Token missing issued_at timestamp, treating as expired");
335
- return true;
336
- }
337
- const expiresAt = tokens.issued_at + tokens.expires_in * 1e3;
338
- const now = Date.now();
339
- return expiresAt - now < 3e5;
340
- }
341
- async storeToFile(tokenString) {
342
- if (!this.isNode()) return;
343
- const fs = require("fs").promises;
344
- const path = require("path");
345
- const os = require("os");
346
- const crypto2 = require("crypto");
347
- const configDir = path.join(os.homedir(), ".lanonasis");
348
- const tokenFile = path.join(configDir, "mcp-tokens.enc");
349
- await fs.mkdir(configDir, { recursive: true });
350
- const key = this.getFileEncryptionKey();
351
- const iv = crypto2.randomBytes(16);
352
- const cipher = crypto2.createCipheriv("aes-256-gcm", key, iv);
353
- let encrypted = cipher.update(tokenString, "utf8", "hex");
354
- encrypted += cipher.final("hex");
355
- const authTag = cipher.getAuthTag().toString("hex");
356
- const data = [iv.toString("hex"), authTag, encrypted].join(":");
357
- await fs.writeFile(tokenFile, data, { mode: 384 });
358
- }
359
- async retrieveFromFile() {
360
- if (!this.isNode()) return null;
361
- const fs = require("fs").promises;
362
- const path = require("path");
363
- const os = require("os");
364
- const crypto2 = require("crypto");
365
- const tokenFile = path.join(os.homedir(), ".lanonasis", "mcp-tokens.enc");
366
- try {
367
- const data = await fs.readFile(tokenFile, "utf8");
368
- const parts = data.split(":");
369
- const key = this.getFileEncryptionKey();
370
- if (parts.length === 3) {
371
- const [ivHex, authTagHex, encrypted] = parts;
372
- const iv = Buffer.from(ivHex, "hex");
373
- const authTag = Buffer.from(authTagHex, "hex");
374
- const decipher = crypto2.createDecipheriv("aes-256-gcm", key, iv);
375
- decipher.setAuthTag(authTag);
376
- let decrypted = decipher.update(encrypted, "hex", "utf8");
377
- decrypted += decipher.final("utf8");
378
- return decrypted;
379
- }
380
- if (parts.length === 2) {
381
- const [ivHex, encrypted] = parts;
382
- const iv = Buffer.from(ivHex, "hex");
383
- const decipher = crypto2.createDecipheriv("aes-256-cbc", key, iv);
384
- let decrypted = decipher.update(encrypted, "hex", "utf8");
385
- decrypted += decipher.final("utf8");
386
- return decrypted;
387
- }
388
- throw new Error("Invalid encrypted token format");
389
- } catch (error) {
390
- return null;
391
- }
392
- }
393
- async deleteFile() {
394
- if (!this.isNode()) return;
395
- const fs = require("fs").promises;
396
- const path = require("path");
397
- const os = require("os");
398
- const tokenFile = path.join(os.homedir(), ".lanonasis", "mcp-tokens.enc");
399
- try {
400
- await fs.unlink(tokenFile);
401
- } catch (error) {
402
- }
403
- }
404
- getFileEncryptionKey() {
405
- const crypto2 = require("crypto");
406
- const os = require("os");
407
- const machineId = os.hostname() + os.userInfo().username;
408
- const salt = "lanonasis-mcp-oauth-2024";
409
- return crypto2.pbkdf2Sync(machineId, salt, 1e5, 32, "sha256");
410
- }
411
- async encrypt(text) {
412
- if (typeof window === "undefined" || !window.crypto?.subtle) {
413
- const encoder2 = new TextEncoder();
414
- const data2 = encoder2.encode(text);
415
- return this.base64Encode(data2);
416
- }
417
- const encoder = new TextEncoder();
418
- const data = encoder.encode(text);
419
- const passphrase = await this.getWebEncryptionKey();
420
- const keyMaterial = await window.crypto.subtle.importKey(
421
- "raw",
422
- encoder.encode(passphrase),
423
- "PBKDF2",
424
- false,
425
- ["deriveBits", "deriveKey"]
426
- );
427
- const key = await window.crypto.subtle.deriveKey(
428
- {
429
- name: "PBKDF2",
430
- salt: encoder.encode("lanonasis-token-salt"),
431
- iterations: 1e5,
432
- hash: "SHA-256"
433
- },
434
- keyMaterial,
435
- { name: "AES-GCM", length: 256 },
436
- true,
437
- ["encrypt", "decrypt"]
438
- );
439
- const iv = window.crypto.getRandomValues(new Uint8Array(12));
440
- const encrypted = await window.crypto.subtle.encrypt(
441
- { name: "AES-GCM", iv },
442
- key,
443
- data
444
- );
445
- const combined = new Uint8Array(iv.length + encrypted.byteLength);
446
- combined.set(iv, 0);
447
- combined.set(new Uint8Array(encrypted), iv.length);
448
- return this.base64Encode(combined);
449
- }
450
- async decrypt(encrypted) {
451
- if (typeof window === "undefined" || !window.crypto?.subtle) {
452
- const bytes2 = this.base64Decode(encrypted);
453
- const decoder2 = new TextDecoder();
454
- return decoder2.decode(bytes2);
455
- }
456
- const bytes = this.base64Decode(encrypted);
457
- const iv = bytes.slice(0, 12);
458
- const data = bytes.slice(12);
459
- const encoder = new TextEncoder();
460
- const decoder = new TextDecoder();
461
- const passphrase = await this.getWebEncryptionKey();
462
- const keyMaterial = await window.crypto.subtle.importKey(
463
- "raw",
464
- encoder.encode(passphrase),
465
- "PBKDF2",
466
- false,
467
- ["deriveBits", "deriveKey"]
468
- );
469
- const key = await window.crypto.subtle.deriveKey(
470
- {
471
- name: "PBKDF2",
472
- salt: encoder.encode("lanonasis-token-salt"),
473
- iterations: 1e5,
474
- hash: "SHA-256"
475
- },
476
- keyMaterial,
477
- { name: "AES-GCM", length: 256 },
478
- true,
479
- ["encrypt", "decrypt"]
480
- );
481
- const decrypted = await window.crypto.subtle.decrypt(
482
- { name: "AES-GCM", iv },
483
- key,
484
- data
485
- );
486
- return decoder.decode(decrypted);
487
- }
488
- isNode() {
489
- return !!(typeof process !== "undefined" && process.versions && process.versions.node && !this.isElectron());
490
- }
491
- isElectron() {
492
- return typeof window !== "undefined" && window.electronAPI !== void 0;
493
- }
494
- isMobile() {
495
- return typeof window !== "undefined" && window.SecureStorage !== void 0;
496
- }
497
- base64Encode(bytes) {
498
- if (typeof btoa !== "undefined") {
499
- let binary = "";
500
- bytes.forEach((b) => {
501
- binary += String.fromCharCode(b);
502
- });
503
- return btoa(binary);
504
- }
505
- if (typeof Buffer !== "undefined") {
506
- return Buffer.from(bytes).toString("base64");
507
- }
508
- throw new Error("No base64 encoder available");
509
- }
510
- base64Decode(value) {
511
- if (typeof atob !== "undefined") {
512
- const binary = atob(value);
513
- const bytes = new Uint8Array(binary.length);
514
- for (let i = 0; i < binary.length; i++) {
515
- bytes[i] = binary.charCodeAt(i);
516
- }
517
- return bytes;
518
- }
519
- if (typeof Buffer !== "undefined") {
520
- return new Uint8Array(Buffer.from(value, "base64"));
521
- }
522
- throw new Error("No base64 decoder available");
523
- }
524
- async getWebEncryptionKey() {
525
- const existing = typeof localStorage !== "undefined" ? localStorage.getItem(this.webEncryptionKeyStorage) : null;
526
- if (existing) {
527
- return existing;
528
- }
529
- let raw = "";
530
- if (typeof window !== "undefined" && window.crypto?.getRandomValues) {
531
- const buf = new Uint8Array(32);
532
- window.crypto.getRandomValues(buf);
533
- raw = Array.from(buf).map((b) => b.toString(16).padStart(2, "0")).join("");
534
- } else {
535
- const ua = typeof navigator !== "undefined" ? navigator.userAgent : "node";
536
- raw = `${ua}-${Math.random().toString(36).slice(2)}-${Date.now()}`;
537
- }
538
- if (typeof localStorage !== "undefined") {
539
- localStorage.setItem(this.webEncryptionKeyStorage, raw);
540
- }
541
- return raw;
542
- }
543
- };
250
+ // src/client/mcp-client-browser.ts
251
+ var import_cross_fetch3 = __toESM(require("cross-fetch"), 1);
544
252
 
545
253
  // src/storage/token-storage-web.ts
546
254
  var TokenStorageWeb = class {
@@ -680,123 +388,8 @@ var TokenStorageWeb = class {
680
388
  }
681
389
  };
682
390
 
683
- // src/flows/terminal-flow.ts
684
- var import_cross_fetch2 = __toESM(require("cross-fetch"), 1);
685
- var TerminalOAuthFlow = class extends BaseOAuthFlow {
686
- constructor(config) {
687
- super({
688
- ...config,
689
- clientId: config.clientId || "lanonasis-mcp-cli"
690
- });
691
- this.pollInterval = 5;
692
- }
693
- async authenticate() {
694
- try {
695
- const deviceResponse = await this.requestDeviceCode();
696
- this.displayInstructions(deviceResponse);
697
- if (deviceResponse.verification_uri_complete) {
698
- await this.openBrowser(deviceResponse.verification_uri_complete);
699
- }
700
- return await this.pollForToken(deviceResponse);
701
- } catch (error) {
702
- console.error("Authentication failed:", error);
703
- throw error;
704
- }
705
- }
706
- async requestDeviceCode() {
707
- const response = await (0, import_cross_fetch2.default)(`${this.authBaseUrl}/oauth/device`, {
708
- method: "POST",
709
- headers: { "Content-Type": "application/json" },
710
- body: JSON.stringify({
711
- client_id: this.clientId,
712
- scope: this.scope
713
- })
714
- });
715
- if (!response.ok) {
716
- const error = await response.json();
717
- throw new Error(error.error_description || "Failed to request device code");
718
- }
719
- const data = await response.json();
720
- this.pollInterval = data.interval || 5;
721
- return data;
722
- }
723
- displayInstructions(response) {
724
- console.log("\n\u{1F510} Lan Onasis Authentication Required\n");
725
- console.log(`Please visit: ${response.verification_uri}`);
726
- console.log(`Enter code: ${response.user_code}
727
- `);
728
- console.log("Or press Enter to open your browser automatically...");
729
- }
730
- async openBrowser(url) {
731
- try {
732
- const { default: open } = await import("open");
733
- await Promise.race([
734
- this.waitForEnter(),
735
- new Promise((resolve) => setTimeout(resolve, 2e3))
736
- ]);
737
- console.log("Opening browser...");
738
- await open(url);
739
- } catch (error) {
740
- console.log("Please open the URL manually in your browser.");
741
- }
742
- }
743
- waitForEnter() {
744
- return new Promise((resolve) => {
745
- if (process.stdin.isTTY) {
746
- process.stdin.setRawMode(true);
747
- process.stdin.resume();
748
- process.stdin.once("data", () => {
749
- process.stdin.setRawMode(false);
750
- process.stdin.pause();
751
- resolve();
752
- });
753
- } else {
754
- resolve();
755
- }
756
- });
757
- }
758
- async pollForToken(deviceResponse) {
759
- const startTime = Date.now();
760
- const expiresAt = startTime + deviceResponse.expires_in * 1e3;
761
- console.log("Waiting for authorization...");
762
- while (Date.now() < expiresAt) {
763
- await new Promise((resolve) => setTimeout(resolve, this.pollInterval * 1e3));
764
- try {
765
- const token = await this.checkDeviceCode(deviceResponse.device_code);
766
- console.log("\u2705 Authorization successful!\n");
767
- return token;
768
- } catch (error) {
769
- if (error.message === "authorization_pending") {
770
- process.stdout.write(".");
771
- } else if (error.message === "slow_down") {
772
- this.pollInterval += 5;
773
- } else {
774
- throw error;
775
- }
776
- }
777
- }
778
- throw new Error("Authorization timeout - please try again");
779
- }
780
- async checkDeviceCode(deviceCode) {
781
- const response = await (0, import_cross_fetch2.default)(`${this.authBaseUrl}/oauth/token`, {
782
- method: "POST",
783
- headers: { "Content-Type": "application/json" },
784
- body: JSON.stringify({
785
- grant_type: "urn:ietf:params:oauth:grant-type:device_code",
786
- device_code: deviceCode,
787
- client_id: this.clientId
788
- })
789
- });
790
- const data = await response.json();
791
- if (!response.ok) {
792
- throw new Error(data.error || "Token request failed");
793
- }
794
- return data;
795
- }
796
- };
797
-
798
391
  // src/flows/apikey-flow.ts
799
- var import_cross_fetch3 = __toESM(require("cross-fetch"), 1);
392
+ var import_cross_fetch2 = __toESM(require("cross-fetch"), 1);
800
393
  var APIKeyFlow = class extends BaseOAuthFlow {
801
394
  constructor(apiKey, authBaseUrl = "https://mcp.lanonasis.com") {
802
395
  super({
@@ -839,7 +432,7 @@ var APIKeyFlow = class extends BaseOAuthFlow {
839
432
  */
840
433
  async validateAPIKey() {
841
434
  try {
842
- const response = await (0, import_cross_fetch3.default)(`${this.config.authBaseUrl}/api/v1/health`, {
435
+ const response = await (0, import_cross_fetch2.default)(`${this.config.authBaseUrl}/api/v1/health`, {
843
436
  headers: {
844
437
  "x-api-key": this.apiKey
845
438
  }
@@ -852,10 +445,9 @@ var APIKeyFlow = class extends BaseOAuthFlow {
852
445
  }
853
446
  };
854
447
 
855
- // src/client/mcp-client.ts
448
+ // src/client/mcp-client-browser.ts
856
449
  var MCPClient = class {
857
450
  constructor(config = {}) {
858
- // ← NEW: Track auth mode
859
451
  this.ws = null;
860
452
  this.eventSource = null;
861
453
  this.accessToken = null;
@@ -865,8 +457,7 @@ var MCPClient = class {
865
457
  autoRefresh: true,
866
458
  ...config
867
459
  };
868
- const defaultStorage = typeof window !== "undefined" ? new TokenStorageWeb() : new TokenStorage();
869
- this.tokenStorage = config.tokenStorage || defaultStorage;
460
+ this.tokenStorage = config.tokenStorage || new TokenStorageWeb();
870
461
  this.authMode = config.apiKey ? "apikey" : "oauth";
871
462
  if (this.authMode === "apikey") {
872
463
  this.authFlow = new APIKeyFlow(
@@ -874,11 +465,7 @@ var MCPClient = class {
874
465
  config.authBaseUrl || "https://mcp.lanonasis.com"
875
466
  );
876
467
  } else {
877
- if (this.isTerminal()) {
878
- this.authFlow = new TerminalOAuthFlow(config);
879
- } else {
880
- this.authFlow = new DesktopOAuthFlow(config);
881
- }
468
+ this.authFlow = new DesktopOAuthFlow(config);
882
469
  }
883
470
  }
884
471
  async connect() {
@@ -904,186 +491,124 @@ var MCPClient = class {
904
491
  }
905
492
  this.accessToken = tokens.access_token;
906
493
  if (this.config.autoRefresh && tokens.expires_in) {
907
- this.scheduleTokenRefresh(tokens);
494
+ this.scheduleTokenRefresh(tokens.expires_in);
908
495
  }
909
496
  }
910
497
  await this.establishConnection();
911
498
  } catch (error) {
912
- console.error("Failed to connect:", error);
499
+ console.error("MCP connection failed:", error);
913
500
  throw error;
914
501
  }
915
502
  }
916
503
  async authenticate() {
917
- console.log("Authenticating with Lan Onasis...");
918
504
  const tokens = await this.authFlow.authenticate();
919
505
  await this.tokenStorage.store(tokens);
920
506
  return tokens;
921
507
  }
922
508
  async ensureAccessToken() {
923
- if (this.accessToken) return;
924
- const tokens = await this.tokenStorage.retrieve();
925
- if (!tokens) {
926
- throw new Error("Not authenticated");
927
- }
928
- if (this.authMode === "apikey") {
929
- this.accessToken = tokens.access_token;
930
- return;
931
- }
932
- if (this.tokenStorage.isTokenExpired(tokens)) {
933
- if (tokens.refresh_token) {
934
- try {
935
- const newTokens = await this.authFlow.refreshToken(tokens.refresh_token);
936
- await this.tokenStorage.store(newTokens);
937
- this.accessToken = newTokens.access_token;
938
- return;
939
- } catch (error) {
940
- console.error("Token refresh failed:", error);
941
- throw new Error("Token expired and refresh failed");
942
- }
943
- } else {
944
- throw new Error("Token expired and no refresh token available");
945
- }
509
+ if (!this.accessToken) {
510
+ await this.connect();
946
511
  }
947
- this.accessToken = tokens.access_token;
512
+ return this.accessToken;
948
513
  }
949
- scheduleTokenRefresh(tokens) {
514
+ scheduleTokenRefresh(expiresIn) {
515
+ const refreshTime = (expiresIn - 300) * 1e3;
950
516
  if (this.refreshTimer) {
951
517
  clearTimeout(this.refreshTimer);
952
518
  }
953
- const refreshIn = (tokens.expires_in - 300) * 1e3;
954
519
  this.refreshTimer = setTimeout(async () => {
955
520
  try {
956
- if (tokens.refresh_token) {
521
+ const tokens = await this.tokenStorage.retrieve();
522
+ if (tokens?.refresh_token) {
957
523
  const newTokens = await this.authFlow.refreshToken(tokens.refresh_token);
958
524
  await this.tokenStorage.store(newTokens);
959
525
  this.accessToken = newTokens.access_token;
960
- this.scheduleTokenRefresh(newTokens);
961
- await this.reconnect();
526
+ if (newTokens.expires_in) {
527
+ this.scheduleTokenRefresh(newTokens.expires_in);
528
+ }
962
529
  }
963
530
  } catch (error) {
964
531
  console.error("Token refresh failed:", error);
532
+ await this.connect();
965
533
  }
966
- }, refreshIn);
534
+ }, refreshTime);
967
535
  }
968
536
  async establishConnection() {
969
537
  const endpoint = this.config.mcpEndpoint;
970
- if (endpoint.startsWith("wss://")) {
538
+ if (endpoint.startsWith("ws://") || endpoint.startsWith("wss://")) {
971
539
  await this.connectWebSocket(endpoint);
972
- } else if (endpoint.startsWith("https://")) {
973
- await this.connectSSE(endpoint);
974
540
  } else {
975
- throw new Error("Invalid MCP endpoint - must be wss:// or https://");
541
+ await this.connectSSE(endpoint);
976
542
  }
977
543
  }
978
544
  async connectWebSocket(endpoint) {
979
- const wsUrl = new URL(endpoint);
980
- wsUrl.pathname = "/ws";
981
- if (this.accessToken) {
982
- wsUrl.searchParams.set("access_token", this.accessToken);
983
- }
984
545
  if (typeof WebSocket !== "undefined") {
985
- this.ws = new WebSocket(wsUrl.toString());
986
- } else {
987
- const { default: WS } = await import("ws");
988
- if (this.authMode === "apikey") {
989
- this.ws = new WS(wsUrl.toString(), {
990
- headers: {
991
- "x-api-key": this.accessToken
992
- }
993
- });
994
- } else {
995
- this.ws = new WS(wsUrl.toString(), {
996
- headers: {
997
- "Authorization": `Bearer ${this.accessToken}`
998
- }
999
- });
1000
- }
1001
- }
1002
- return new Promise((resolve, reject) => {
1003
- if (!this.ws) {
1004
- reject(new Error("WebSocket not initialized"));
1005
- return;
1006
- }
546
+ this.ws = new WebSocket(endpoint);
1007
547
  this.ws.onopen = () => {
1008
548
  console.log("MCP WebSocket connected");
1009
- resolve();
549
+ this.ws?.send(JSON.stringify({
550
+ type: "auth",
551
+ token: this.accessToken
552
+ }));
1010
553
  };
1011
- this.ws.onerror = (error) => {
1012
- console.error("WebSocket error:", error);
1013
- reject(error);
554
+ this.ws.onmessage = (event) => {
555
+ this.handleMessage(JSON.parse(event.data));
1014
556
  };
1015
- this.ws.onclose = (event) => {
1016
- console.log("WebSocket closed:", event.code, event.reason);
1017
- if (event.code !== 1008 && event.code !== 4001) {
1018
- setTimeout(() => this.reconnect(), 5e3);
1019
- }
557
+ this.ws.onerror = (error) => {
558
+ console.error("MCP WebSocket error:", error);
1020
559
  };
1021
- this.ws.onmessage = (event) => {
1022
- this.handleMessage(event.data);
560
+ this.ws.onclose = () => {
561
+ console.log("MCP WebSocket disconnected");
562
+ setTimeout(() => this.reconnect(), 5e3);
1023
563
  };
1024
- });
564
+ } else {
565
+ throw new Error("WebSocket is not available in this environment");
566
+ }
1025
567
  }
1026
568
  async connectSSE(endpoint) {
1027
569
  const sseUrl = new URL(endpoint);
1028
- sseUrl.pathname = "/sse";
1029
570
  if (typeof EventSource !== "undefined") {
1030
- this.eventSource = new EventSource(sseUrl.toString());
1031
- } else {
1032
- const EventSourceModule = await import("eventsource");
1033
- const ES = EventSourceModule.default || EventSourceModule;
1034
571
  if (this.authMode === "apikey") {
1035
- this.eventSource = new ES(sseUrl.toString(), {
1036
- headers: {
1037
- "x-api-key": this.accessToken
1038
- }
1039
- });
572
+ sseUrl.searchParams.set("api_key", this.accessToken);
1040
573
  } else {
1041
- this.eventSource = new ES(sseUrl.toString(), {
1042
- headers: {
1043
- "Authorization": `Bearer ${this.accessToken}`
1044
- }
1045
- });
574
+ sseUrl.searchParams.set("token", this.accessToken);
1046
575
  }
576
+ this.eventSource = new EventSource(sseUrl.toString());
577
+ this.eventSource.onopen = () => {
578
+ console.log("MCP SSE connected");
579
+ };
580
+ this.eventSource.onmessage = (event) => {
581
+ this.handleMessage(JSON.parse(event.data));
582
+ };
583
+ this.eventSource.onerror = () => {
584
+ console.error("MCP SSE error");
585
+ this.eventSource?.close();
586
+ setTimeout(() => this.reconnect(), 5e3);
587
+ };
588
+ } else {
589
+ throw new Error("EventSource is not available in this environment");
1047
590
  }
1048
- this.eventSource.onopen = () => {
1049
- console.log("MCP SSE connected");
1050
- };
1051
- this.eventSource.onerror = (error) => {
1052
- console.error("SSE error:", error);
1053
- setTimeout(() => this.reconnect(), 5e3);
1054
- };
1055
- this.eventSource.onmessage = (event) => {
1056
- this.handleMessage(event.data);
1057
- };
1058
591
  }
1059
- handleMessage(data) {
592
+ handleMessage(message) {
593
+ console.log("MCP message:", message);
594
+ }
595
+ async reconnect() {
1060
596
  try {
1061
- const message = JSON.parse(data);
1062
- console.log("MCP message:", message);
597
+ await this.connect();
1063
598
  } catch (error) {
1064
- console.error("Failed to parse message:", error);
599
+ console.error("Reconnection failed:", error);
600
+ setTimeout(() => this.reconnect(), 1e4);
1065
601
  }
1066
602
  }
1067
- async reconnect() {
1068
- this.disconnect();
1069
- await this.establishConnection();
1070
- }
1071
603
  async request(method, params) {
1072
604
  await this.ensureAccessToken();
1073
- if (!this.accessToken) {
1074
- throw new Error("Not authenticated");
1075
- }
1076
- const headers = {
1077
- "Content-Type": "application/json"
1078
- };
1079
- if (this.authMode === "apikey") {
1080
- headers["x-api-key"] = this.accessToken;
1081
- } else {
1082
- headers["Authorization"] = `Bearer ${this.accessToken}`;
1083
- }
1084
- const response = await (0, import_cross_fetch4.default)(`${this.config.mcpEndpoint}/api`, {
605
+ const endpoint = this.config.mcpEndpoint.replace(/^ws/, "http");
606
+ const response = await (0, import_cross_fetch3.default)(`${endpoint}/rpc`, {
1085
607
  method: "POST",
1086
- headers,
608
+ headers: {
609
+ "Content-Type": "application/json",
610
+ "Authorization": `Bearer ${this.accessToken}`
611
+ },
1087
612
  body: JSON.stringify({
1088
613
  jsonrpc: "2.0",
1089
614
  id: this.generateId(),
@@ -1091,26 +616,11 @@ var MCPClient = class {
1091
616
  params
1092
617
  })
1093
618
  });
1094
- if (response.status === 401) {
1095
- if (this.authMode === "apikey") {
1096
- throw new Error("Invalid API key - please check your credentials");
1097
- }
1098
- const tokens = await this.tokenStorage.retrieve();
1099
- if (tokens?.refresh_token) {
1100
- const newTokens = await this.authFlow.refreshToken(tokens.refresh_token);
1101
- await this.tokenStorage.store(newTokens);
1102
- this.accessToken = newTokens.access_token;
1103
- return this.request(method, params);
1104
- } else {
1105
- await this.connect();
1106
- return this.request(method, params);
1107
- }
1108
- }
1109
- const result = await response.json();
1110
- if (result.error) {
1111
- throw new Error(result.error.message || "Request failed");
619
+ const data = await response.json();
620
+ if (data.error) {
621
+ throw new Error(data.error.message || "MCP request failed");
1112
622
  }
1113
- return result.result;
623
+ return data.result;
1114
624
  }
1115
625
  disconnect() {
1116
626
  if (this.ws) {
@@ -1125,59 +635,30 @@ var MCPClient = class {
1125
635
  clearTimeout(this.refreshTimer);
1126
636
  this.refreshTimer = null;
1127
637
  }
638
+ this.accessToken = null;
1128
639
  }
1129
640
  async logout() {
1130
- const tokens = await this.tokenStorage.retrieve();
1131
- if (tokens) {
1132
- try {
1133
- if (tokens.access_token) {
1134
- await this.authFlow.revokeToken(tokens.access_token, "access_token");
1135
- }
1136
- if (tokens.refresh_token) {
1137
- await this.authFlow.revokeToken(tokens.refresh_token, "refresh_token");
1138
- }
1139
- } catch (error) {
1140
- console.error("Failed to revoke tokens:", error);
1141
- }
1142
- }
1143
- await this.tokenStorage.clear();
1144
641
  this.disconnect();
1145
- this.accessToken = null;
1146
- }
1147
- isTerminal() {
1148
- return !!(typeof process !== "undefined" && process.versions && process.versions.node && !this.isElectron());
1149
- }
1150
- isElectron() {
1151
- return typeof window !== "undefined" && window.electronAPI !== void 0;
642
+ await this.tokenStorage.clear();
1152
643
  }
1153
644
  generateId() {
1154
- return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
645
+ return Math.random().toString(36).substring(2, 15);
1155
646
  }
1156
- // MCP-specific methods
647
+ // Convenience methods for memory operations
1157
648
  async createMemory(title, content, options) {
1158
- return this.request("memory/create", {
1159
- title,
1160
- content,
1161
- ...options
1162
- });
649
+ return this.request("memories.create", { title, content, ...options || {} });
1163
650
  }
1164
651
  async searchMemories(query, options) {
1165
- return this.request("memory/search", {
1166
- query,
1167
- ...options
1168
- });
652
+ return this.request("memories.search", { query, ...options || {} });
1169
653
  }
1170
654
  async getMemory(id) {
1171
- return this.request("memory/get", { id });
655
+ return this.request("memories.get", { id });
1172
656
  }
1173
657
  async updateMemory(id, updates) {
1174
- return this.request("memory/update", {
1175
- id,
1176
- ...updates
1177
- });
658
+ return this.request("memories.update", { id, updates });
1178
659
  }
1179
660
  async deleteMemory(id) {
1180
- return this.request("memory/delete", { id });
661
+ return this.request("memories.delete", { id });
1181
662
  }
1182
663
  };
1183
664