@lanonasis/oauth-client 1.2.2 → 1.2.4

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