@sonoma-security/mcp-gateway 0.1.12 → 0.1.14

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 (53) hide show
  1. package/dist/__tests__/config.test.js +140 -2
  2. package/dist/__tests__/config.test.js.map +1 -1
  3. package/dist/__tests__/plugin-discovery.test.d.ts +12 -0
  4. package/dist/__tests__/plugin-discovery.test.d.ts.map +1 -0
  5. package/dist/__tests__/plugin-discovery.test.js +367 -0
  6. package/dist/__tests__/plugin-discovery.test.js.map +1 -0
  7. package/dist/__tests__/tool-blocking.test.d.ts +2 -0
  8. package/dist/__tests__/tool-blocking.test.d.ts.map +1 -0
  9. package/dist/__tests__/tool-blocking.test.js +256 -0
  10. package/dist/__tests__/tool-blocking.test.js.map +1 -0
  11. package/dist/auth/keychain.d.ts +34 -0
  12. package/dist/auth/keychain.d.ts.map +1 -0
  13. package/dist/auth/keychain.js +305 -0
  14. package/dist/auth/keychain.js.map +1 -0
  15. package/dist/auth/storage.d.ts +5 -6
  16. package/dist/auth/storage.d.ts.map +1 -1
  17. package/dist/auth/storage.js +72 -21
  18. package/dist/auth/storage.js.map +1 -1
  19. package/dist/auth/upstream-oauth.d.ts.map +1 -1
  20. package/dist/auth/upstream-oauth.js +8 -5
  21. package/dist/auth/upstream-oauth.js.map +1 -1
  22. package/dist/auth/upstream-token-store.d.ts +18 -6
  23. package/dist/auth/upstream-token-store.d.ts.map +1 -1
  24. package/dist/auth/upstream-token-store.js +127 -35
  25. package/dist/auth/upstream-token-store.js.map +1 -1
  26. package/dist/cli.js +48 -2
  27. package/dist/cli.js.map +1 -1
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js +122 -27
  30. package/dist/config.js.map +1 -1
  31. package/dist/gateway.d.ts +15 -0
  32. package/dist/gateway.d.ts.map +1 -1
  33. package/dist/gateway.js +302 -68
  34. package/dist/gateway.js.map +1 -1
  35. package/dist/http-proxy.d.ts +126 -0
  36. package/dist/http-proxy.d.ts.map +1 -0
  37. package/dist/http-proxy.js +875 -0
  38. package/dist/http-proxy.js.map +1 -0
  39. package/dist/index.d.ts +3 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +2 -0
  42. package/dist/index.js.map +1 -1
  43. package/dist/pattern-matcher.d.ts +25 -0
  44. package/dist/pattern-matcher.d.ts.map +1 -1
  45. package/dist/pattern-matcher.js +65 -0
  46. package/dist/pattern-matcher.js.map +1 -1
  47. package/dist/sonoma-client.d.ts +17 -1
  48. package/dist/sonoma-client.d.ts.map +1 -1
  49. package/dist/sonoma-client.js +67 -43
  50. package/dist/sonoma-client.js.map +1 -1
  51. package/dist/types.d.ts +14 -0
  52. package/dist/types.d.ts.map +1 -1
  53. package/package.json +1 -1
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * Secure token storage for MCP Gateway OAuth credentials
3
3
  *
4
- * Stores tokens in ~/.sonoma/gateway-credentials.json with AES-256-GCM encryption.
5
- * The encryption key is derived from a machine-specific identifier to prevent
6
- * tokens from being copied between machines.
4
+ * Stores tokens in the OS keychain (macOS Keychain, Windows Credential Manager).
5
+ * Falls back to encrypted file storage on unsupported platforms.
7
6
  */
8
7
  import type { OAuthTokens, OAuthClientInformationMixed } from "@modelcontextprotocol/sdk/shared/auth.js";
9
8
  export interface StoredCredentials {
@@ -20,15 +19,15 @@ export interface StoredCredentials {
20
19
  lastRefreshed?: number;
21
20
  }
22
21
  /**
23
- * Load stored credentials from disk
22
+ * Load stored credentials from OS keychain (or legacy file).
24
23
  */
25
24
  export declare function loadCredentials(): StoredCredentials | null;
26
25
  /**
27
- * Save credentials to disk (encrypted)
26
+ * Save credentials to OS keychain (or fallback file).
28
27
  */
29
28
  export declare function saveCredentials(credentials: StoredCredentials): void;
30
29
  /**
31
- * Clear all stored credentials
30
+ * Clear all stored credentials.
32
31
  */
33
32
  export declare function clearCredentials(): void;
34
33
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AAKzG,MAAM,WAAW,iBAAiB;IAEhC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAG/B,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,iBAAiB,GAAG,IAAI,CAc1D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAOpE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAIvC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,iBAAiB,GAAG,WAAW,GAAG,SAAS,CAY/E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,CAYpG;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,2BAA2B,GAAG,SAAS,CAUrG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,SAAQ,GAAG,OAAO,CAMlF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAEjE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AAQzG,MAAM,WAAW,iBAAiB;IAEhC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAG/B,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,iBAAiB,GAAG,IAAI,CA4B1D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAgBpE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAQvC;AAkBD;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,iBAAiB,GAAG,WAAW,GAAG,SAAS,CAY/E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,CAYpG;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,2BAA2B,GAAG,SAAS,CAUrG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,SAAQ,GAAG,OAAO,CAMlF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAEjE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
@@ -1,47 +1,98 @@
1
1
  /**
2
2
  * Secure token storage for MCP Gateway OAuth credentials
3
3
  *
4
- * Stores tokens in ~/.sonoma/gateway-credentials.json with AES-256-GCM encryption.
5
- * The encryption key is derived from a machine-specific identifier to prevent
6
- * tokens from being copied between machines.
4
+ * Stores tokens in the OS keychain (macOS Keychain, Windows Credential Manager).
5
+ * Falls back to encrypted file storage on unsupported platforms.
7
6
  */
8
7
  import { existsSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
9
8
  import { join } from "node:path";
10
9
  import { SONOMA_DIR, ensureSonomaDir, getDeviceId, encrypt, decrypt } from "./crypto.js";
11
- const CREDENTIALS_PATH = join(SONOMA_DIR, "gateway-credentials.json");
10
+ import { keychainAvailable, keychainGet, keychainSet, keychainDelete } from "./keychain.js";
11
+ const KEYCHAIN_ACCOUNT = "sonoma-auth";
12
+ // Legacy file path (for migration)
13
+ const LEGACY_CREDENTIALS_PATH = join(SONOMA_DIR, "gateway-credentials.json");
12
14
  /**
13
- * Load stored credentials from disk
15
+ * Load stored credentials from OS keychain (or legacy file).
14
16
  */
15
17
  export function loadCredentials() {
16
- if (!existsSync(CREDENTIALS_PATH)) {
17
- return null;
18
- }
19
- try {
20
- const encryptedData = readFileSync(CREDENTIALS_PATH, "utf-8");
21
- const decrypted = decrypt(encryptedData);
22
- return JSON.parse(decrypted);
23
- }
24
- catch (error) {
25
- // If decryption fails (e.g., machine changed), return null
26
- console.error("[auth] Failed to load credentials:", error);
18
+ // Try OS keychain first
19
+ if (keychainAvailable()) {
20
+ try {
21
+ const creds = keychainGet(KEYCHAIN_ACCOUNT);
22
+ if (creds)
23
+ return creds;
24
+ }
25
+ catch {
26
+ // Keychain access failed, try legacy
27
+ }
28
+ // Migrate from legacy encrypted file if it exists
29
+ const legacy = loadLegacyCredentials();
30
+ if (legacy) {
31
+ try {
32
+ keychainSet(KEYCHAIN_ACCOUNT, legacy);
33
+ // Clean up legacy file after successful migration
34
+ unlinkSync(LEGACY_CREDENTIALS_PATH);
35
+ }
36
+ catch {
37
+ // Migration failed, return legacy credentials anyway
38
+ }
39
+ return legacy;
40
+ }
27
41
  return null;
28
42
  }
43
+ // Fallback: encrypted file (Linux, etc.)
44
+ return loadLegacyCredentials();
29
45
  }
30
46
  /**
31
- * Save credentials to disk (encrypted)
47
+ * Save credentials to OS keychain (or fallback file).
32
48
  */
33
49
  export function saveCredentials(credentials) {
50
+ if (keychainAvailable()) {
51
+ keychainSet(KEYCHAIN_ACCOUNT, credentials);
52
+ // Clean up legacy file if it exists
53
+ if (existsSync(LEGACY_CREDENTIALS_PATH)) {
54
+ try {
55
+ unlinkSync(LEGACY_CREDENTIALS_PATH);
56
+ }
57
+ catch { /* ignore */ }
58
+ }
59
+ return;
60
+ }
61
+ // Fallback: encrypted file
34
62
  ensureSonomaDir();
35
63
  const data = JSON.stringify(credentials, null, 2);
36
64
  const encrypted = encrypt(data);
37
- writeFileSync(CREDENTIALS_PATH, encrypted, { mode: 0o600 });
65
+ writeFileSync(LEGACY_CREDENTIALS_PATH, encrypted, { mode: 0o600 });
38
66
  }
39
67
  /**
40
- * Clear all stored credentials
68
+ * Clear all stored credentials.
41
69
  */
42
70
  export function clearCredentials() {
43
- if (existsSync(CREDENTIALS_PATH)) {
44
- unlinkSync(CREDENTIALS_PATH);
71
+ if (keychainAvailable()) {
72
+ try {
73
+ keychainDelete(KEYCHAIN_ACCOUNT);
74
+ }
75
+ catch { /* ignore */ }
76
+ }
77
+ // Always clean up legacy file too
78
+ if (existsSync(LEGACY_CREDENTIALS_PATH)) {
79
+ unlinkSync(LEGACY_CREDENTIALS_PATH);
80
+ }
81
+ }
82
+ /**
83
+ * Load from legacy encrypted file (pre-keychain migration).
84
+ */
85
+ function loadLegacyCredentials() {
86
+ if (!existsSync(LEGACY_CREDENTIALS_PATH)) {
87
+ return null;
88
+ }
89
+ try {
90
+ const encryptedData = readFileSync(LEGACY_CREDENTIALS_PATH, "utf-8");
91
+ const decrypted = decrypt(encryptedData);
92
+ return JSON.parse(decrypted);
93
+ }
94
+ catch {
95
+ return null;
45
96
  }
46
97
  }
47
98
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"upstream-oauth.d.ts","sourceRoot":"","sources":["../../src/auth/upstream-oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAMpE,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8GAA8G;IAC9G,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2FAA2F;IAC3F,KAAK,CAAC,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,4GAA4G;IAC5G,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC,CAqGhC"}
1
+ {"version":3,"file":"upstream-oauth.d.ts","sourceRoot":"","sources":["../../src/auth/upstream-oauth.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAMpE,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,kBAAkB,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8GAA8G;IAC9G,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2FAA2F;IAC3F,KAAK,CAAC,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,4GAA4G;IAC5G,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC,CAwGhC"}
@@ -68,18 +68,21 @@ export async function authenticateUpstream(options) {
68
68
  });
69
69
  }
70
70
  catch (err) {
71
- // Port taken: another gateway is already authenticating this server
71
+ // Port taken: another gateway may be authenticating this server, or a
72
+ // stale process is holding the port. Wait briefly (15s) for tokens to
73
+ // appear; if not, try to take the port anyway (the stale process may
74
+ // have died by then).
72
75
  if (err instanceof Error && err.message.includes("already in use")) {
73
- log(`Another gateway is already authenticating with ${serverName} on port ${callbackPort}, waiting...`);
74
- console.error(`\nAnother authentication is in progress for ${serverName}. Waiting...`);
75
- const completed = await waitForUpstreamAuth(store, serverUrl, callbackPort, debug);
76
+ log(`Port ${callbackPort} in use for ${serverName}, waiting briefly for external auth...`);
77
+ console.error(`\nPort ${callbackPort} in use. Waiting briefly for ${serverName} auth to complete...`);
78
+ const completed = await waitForUpstreamAuth(store, serverUrl, callbackPort, debug, 15_000);
76
79
  if (completed) {
77
80
  log(`Upstream auth for ${serverName} completed by another process`);
78
81
  const retryResult = await auth(provider, { serverUrl });
79
82
  if (retryResult === "AUTHORIZED")
80
83
  return provider;
81
84
  }
82
- log(`External upstream auth did not complete for ${serverName}, retrying...`);
85
+ log(`External auth did not complete for ${serverName}, retrying port...`);
83
86
  handle = await startCallbackServer({
84
87
  port: callbackPort,
85
88
  debug,
@@ -1 +1 @@
1
- {"version":3,"file":"upstream-oauth.js","sourceRoot":"","sources":["../../src/auth/upstream-oauth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"upstream-oauth.js","sourceRoot":"","sources":["../../src/auth/upstream-oauth.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,28 @@
1
1
  /**
2
2
  * Per-server token storage for upstream MCP servers that require OAuth.
3
3
  *
4
- * Stores credentials in ~/.sonoma/upstream-credentials.json, encrypted with
5
- * the same AES-256-GCM scheme used for Sonoma gateway credentials.
6
- * Each server is keyed by its URL origin (e.g., "https://mcp.sentry.dev").
4
+ * Stores credentials in the OS keychain (macOS Keychain, Windows Credential Manager),
5
+ * keyed by server URL origin (e.g., "https://mcp.slack.com").
6
+ *
7
+ * Falls back to encrypted file storage on unsupported platforms.
7
8
  */
8
9
  import type { OAuthTokens, OAuthClientInformationMixed } from "@modelcontextprotocol/sdk/shared/auth.js";
9
10
  export declare class UpstreamTokenStore {
10
- private store;
11
- private load;
12
- private save;
11
+ private useKeychain;
12
+ private fileStore;
13
+ private migrated;
14
+ constructor();
15
+ /**
16
+ * Migrate credentials from legacy encrypted file to OS keychain.
17
+ */
18
+ private migrateLegacy;
19
+ private getServerFromKeychain;
20
+ private saveServerToKeychain;
21
+ private loadFile;
22
+ private saveFile;
23
+ private getServerFromFile;
13
24
  private getServer;
25
+ private saveServer;
14
26
  getTokens(serverUrl: string): OAuthTokens | undefined;
15
27
  saveTokens(serverUrl: string, tokens: OAuthTokens): void;
16
28
  clearTokens(serverUrl: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"upstream-token-store.d.ts","sourceRoot":"","sources":["../../src/auth/upstream-token-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AAsBzG,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAwC;IAErD,OAAO,CAAC,IAAI;IAoBZ,OAAO,CAAC,IAAI;IAOZ,OAAO,CAAC,SAAS;IASjB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIrD,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IAOxD,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAMpC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,2BAA2B,GAAG,SAAS;IAIzE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,GAAG,IAAI;IAM1E,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAMxC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAItD,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAM3D,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAMpD,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAOjC,mDAAmD;IACnD,eAAe,IAAI,IAAI;CAIxB"}
1
+ {"version":3,"file":"upstream-token-store.d.ts","sourceRoot":"","sources":["../../src/auth/upstream-token-store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AA4BzG,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAU;IAE7B,OAAO,CAAC,SAAS,CAAwC;IAEzD,OAAO,CAAC,QAAQ,CAAS;;IAYzB;;OAEG;IACH,OAAO,CAAC,aAAa;IA6BrB,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,UAAU;IAWlB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIrD,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IAOxD,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAMpC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,2BAA2B,GAAG,SAAS;IAIzE,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,GAAG,IAAI;IAM1E,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAMxC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAItD,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAM3D,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAMpD,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAYjC,mDAAmD;IACnD,eAAe,IAAI,IAAI;CAQxB"}
@@ -1,53 +1,131 @@
1
1
  /**
2
2
  * Per-server token storage for upstream MCP servers that require OAuth.
3
3
  *
4
- * Stores credentials in ~/.sonoma/upstream-credentials.json, encrypted with
5
- * the same AES-256-GCM scheme used for Sonoma gateway credentials.
6
- * Each server is keyed by its URL origin (e.g., "https://mcp.sentry.dev").
4
+ * Stores credentials in the OS keychain (macOS Keychain, Windows Credential Manager),
5
+ * keyed by server URL origin (e.g., "https://mcp.slack.com").
6
+ *
7
+ * Falls back to encrypted file storage on unsupported platforms.
7
8
  */
8
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
9
+ import { existsSync, readFileSync, writeFileSync, unlinkSync } from "node:fs";
9
10
  import { join } from "node:path";
10
11
  import { SONOMA_DIR, ensureSonomaDir, encrypt, decrypt } from "./crypto.js";
11
- const UPSTREAM_CREDENTIALS_PATH = join(SONOMA_DIR, "upstream-credentials.json");
12
+ import { keychainAvailable, keychainGet, keychainSet, keychainDelete, keychainDeleteAll } from "./keychain.js";
13
+ // Legacy file path (for migration from encrypted file)
14
+ const LEGACY_CREDENTIALS_PATH = join(SONOMA_DIR, "upstream-credentials.json");
12
15
  function getServerKey(serverUrl) {
13
16
  const url = new URL(serverUrl);
14
17
  return url.origin;
15
18
  }
19
+ function keychainAccount(serverKey) {
20
+ return `upstream:${serverKey}`;
21
+ }
16
22
  export class UpstreamTokenStore {
17
- store = null;
18
- load() {
19
- if (this.store)
20
- return this.store;
21
- if (!existsSync(UPSTREAM_CREDENTIALS_PATH)) {
22
- this.store = { servers: {} };
23
- return this.store;
23
+ useKeychain;
24
+ // In-memory cache for file-based fallback only
25
+ fileStore = null;
26
+ // Track whether legacy migration has been attempted
27
+ migrated = false;
28
+ constructor() {
29
+ this.useKeychain = keychainAvailable();
30
+ // Migrate legacy file to keychain on first use
31
+ if (this.useKeychain && !this.migrated) {
32
+ this.migrateLegacy();
33
+ this.migrated = true;
34
+ }
35
+ }
36
+ /**
37
+ * Migrate credentials from legacy encrypted file to OS keychain.
38
+ */
39
+ migrateLegacy() {
40
+ if (!existsSync(LEGACY_CREDENTIALS_PATH))
41
+ return;
42
+ try {
43
+ const encryptedData = readFileSync(LEGACY_CREDENTIALS_PATH, "utf-8");
44
+ const decrypted = decrypt(encryptedData);
45
+ const store = JSON.parse(decrypted);
46
+ if (store.servers) {
47
+ for (const [key, creds] of Object.entries(store.servers)) {
48
+ try {
49
+ keychainSet(keychainAccount(key), creds);
50
+ }
51
+ catch {
52
+ // Skip entries that fail to migrate
53
+ }
54
+ }
55
+ }
56
+ // Clean up legacy file after successful migration
57
+ unlinkSync(LEGACY_CREDENTIALS_PATH);
58
+ }
59
+ catch {
60
+ // Migration failed, legacy file may be corrupt
61
+ }
62
+ }
63
+ // ---------------------------------------------------------------------------
64
+ // Keychain-backed operations
65
+ // ---------------------------------------------------------------------------
66
+ getServerFromKeychain(serverUrl) {
67
+ const key = getServerKey(serverUrl);
68
+ return keychainGet(keychainAccount(key)) ?? {};
69
+ }
70
+ saveServerToKeychain(serverUrl, creds) {
71
+ const key = getServerKey(serverUrl);
72
+ keychainSet(keychainAccount(key), creds);
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // File-backed fallback (Linux, etc.)
76
+ // ---------------------------------------------------------------------------
77
+ loadFile() {
78
+ if (this.fileStore)
79
+ return this.fileStore;
80
+ if (!existsSync(LEGACY_CREDENTIALS_PATH)) {
81
+ this.fileStore = { servers: {} };
82
+ return this.fileStore;
24
83
  }
25
84
  try {
26
- const encryptedData = readFileSync(UPSTREAM_CREDENTIALS_PATH, "utf-8");
85
+ const encryptedData = readFileSync(LEGACY_CREDENTIALS_PATH, "utf-8");
27
86
  const decrypted = decrypt(encryptedData);
28
- this.store = JSON.parse(decrypted);
29
- return this.store;
87
+ this.fileStore = JSON.parse(decrypted);
88
+ return this.fileStore;
30
89
  }
31
90
  catch {
32
- // If decryption fails (e.g., machine changed), start fresh
33
- this.store = { servers: {} };
34
- return this.store;
91
+ this.fileStore = { servers: {} };
92
+ return this.fileStore;
35
93
  }
36
94
  }
37
- save() {
95
+ saveFile() {
38
96
  ensureSonomaDir();
39
- const data = JSON.stringify(this.load(), null, 2);
97
+ const data = JSON.stringify(this.loadFile(), null, 2);
40
98
  const encrypted = encrypt(data);
41
- writeFileSync(UPSTREAM_CREDENTIALS_PATH, encrypted, { mode: 0o600 });
99
+ writeFileSync(LEGACY_CREDENTIALS_PATH, encrypted, { mode: 0o600 });
42
100
  }
43
- getServer(serverUrl) {
44
- const store = this.load();
101
+ getServerFromFile(serverUrl) {
102
+ const store = this.loadFile();
45
103
  const key = getServerKey(serverUrl);
46
104
  if (!store.servers[key]) {
47
105
  store.servers[key] = {};
48
106
  }
49
107
  return store.servers[key];
50
108
  }
109
+ // ---------------------------------------------------------------------------
110
+ // Public API (delegates to keychain or file based on platform)
111
+ // ---------------------------------------------------------------------------
112
+ getServer(serverUrl) {
113
+ if (this.useKeychain) {
114
+ return this.getServerFromKeychain(serverUrl);
115
+ }
116
+ return this.getServerFromFile(serverUrl);
117
+ }
118
+ saveServer(serverUrl, creds) {
119
+ if (this.useKeychain) {
120
+ this.saveServerToKeychain(serverUrl, creds);
121
+ }
122
+ else {
123
+ const store = this.loadFile();
124
+ const key = getServerKey(serverUrl);
125
+ store.servers[key] = creds;
126
+ this.saveFile();
127
+ }
128
+ }
51
129
  getTokens(serverUrl) {
52
130
  return this.getServer(serverUrl).tokens;
53
131
  }
@@ -55,12 +133,12 @@ export class UpstreamTokenStore {
55
133
  const server = this.getServer(serverUrl);
56
134
  server.tokens = tokens;
57
135
  server.lastAuthenticated = Date.now();
58
- this.save();
136
+ this.saveServer(serverUrl, server);
59
137
  }
60
138
  clearTokens(serverUrl) {
61
139
  const server = this.getServer(serverUrl);
62
140
  delete server.tokens;
63
- this.save();
141
+ this.saveServer(serverUrl, server);
64
142
  }
65
143
  getClientInfo(serverUrl) {
66
144
  return this.getServer(serverUrl).clientInfo;
@@ -68,12 +146,12 @@ export class UpstreamTokenStore {
68
146
  saveClientInfo(serverUrl, info) {
69
147
  const server = this.getServer(serverUrl);
70
148
  server.clientInfo = info;
71
- this.save();
149
+ this.saveServer(serverUrl, server);
72
150
  }
73
151
  clearClientInfo(serverUrl) {
74
152
  const server = this.getServer(serverUrl);
75
153
  delete server.clientInfo;
76
- this.save();
154
+ this.saveServer(serverUrl, server);
77
155
  }
78
156
  getCodeVerifier(serverUrl) {
79
157
  return this.getServer(serverUrl).codeVerifier;
@@ -81,26 +159,40 @@ export class UpstreamTokenStore {
81
159
  saveCodeVerifier(serverUrl, verifier) {
82
160
  const server = this.getServer(serverUrl);
83
161
  server.codeVerifier = verifier;
84
- this.save();
162
+ this.saveServer(serverUrl, server);
85
163
  }
86
164
  setServerName(serverUrl, name) {
87
165
  const server = this.getServer(serverUrl);
88
166
  server.serverName = name;
89
- this.save();
167
+ this.saveServer(serverUrl, server);
90
168
  }
91
169
  getLastAuthenticated(serverUrl) {
92
170
  return this.getServer(serverUrl).lastAuthenticated;
93
171
  }
94
172
  clearAll(serverUrl) {
95
- const store = this.load();
96
- const key = getServerKey(serverUrl);
97
- delete store.servers[key];
98
- this.save();
173
+ if (this.useKeychain) {
174
+ const key = getServerKey(serverUrl);
175
+ try {
176
+ keychainDelete(keychainAccount(key));
177
+ }
178
+ catch { /* ignore */ }
179
+ }
180
+ else {
181
+ const store = this.loadFile();
182
+ const key = getServerKey(serverUrl);
183
+ delete store.servers[key];
184
+ this.saveFile();
185
+ }
99
186
  }
100
187
  /** Clear credentials for every upstream server. */
101
188
  clearAllServers() {
102
- this.store = { servers: {} };
103
- this.save();
189
+ if (this.useKeychain) {
190
+ keychainDeleteAll();
191
+ }
192
+ else {
193
+ this.fileStore = { servers: {} };
194
+ this.saveFile();
195
+ }
104
196
  }
105
197
  }
106
198
  //# sourceMappingURL=upstream-token-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"upstream-token-store.js","sourceRoot":"","sources":["../../src/auth/upstream-token-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"upstream-token-store.js","sourceRoot":"","sources":["../../src/auth/upstream-token-store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAE/G,uDAAuD;AACvD,MAAM,uBAAuB,GAAG,IAAI,CAAC,UAAU,EAAE,2BAA2B,CAAC,CAAC;AAc9E,SAAS,YAAY,CAAC,SAAiB;IACrC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAC/B,OAAO,GAAG,CAAC,MAAM,CAAC;AACpB,CAAC;AAED,SAAS,eAAe,CAAC,SAAiB;IACxC,OAAO,YAAY,SAAS,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,OAAO,kBAAkB;IACrB,WAAW,CAAU;IAC7B,+CAA+C;IACvC,SAAS,GAAmC,IAAI,CAAC;IACzD,oDAAoD;IAC5C,QAAQ,GAAG,KAAK,CAAC;IAEzB;QACE,IAAI,CAAC,WAAW,GAAG,iBAAiB,EAAE,CAAC;QAEvC,+CAA+C;QAC/C,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACvC,IAAI,CAAC,aAAa,EAAE,CAAC;YACrB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,CAAC;IACH,CAAC;IAED;;OAEG;IACK,aAAa;QACnB,IAAI,CAAC,UAAU,CAAC,uBAAuB,CAAC;YAAE,OAAO;QAEjD,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,YAAY,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;YACrE,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;YACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAA4B,CAAC;YAE/D,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBAClB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;oBACzD,IAAI,CAAC;wBACH,WAAW,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;oBAC3C,CAAC;oBAAC,MAAM,CAAC;wBACP,oCAAoC;oBACtC,CAAC;gBACH,CAAC;YACH,CAAC;YAED,kDAAkD;YAClD,UAAU,CAAC,uBAAuB,CAAC,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,+CAA+C;QACjD,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,6BAA6B;IAC7B,8EAA8E;IAEtE,qBAAqB,CAAC,SAAiB;QAC7C,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;QACpC,OAAO,WAAW,CAAoB,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACpE,CAAC;IAEO,oBAAoB,CAAC,SAAiB,EAAE,KAAwB;QACtE,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;QACpC,WAAW,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,8EAA8E;IAC9E,qCAAqC;IACrC,8EAA8E;IAEtE,QAAQ;QACd,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC;QAE1C,IAAI,CAAC,UAAU,CAAC,uBAAuB,CAAC,EAAE,CAAC;YACzC,IAAI,CAAC,SAAS,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,SAAS,CAAC;QACxB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,aAAa,GAAG,YAAY,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;YACrE,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;YACzC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAA4B,CAAC;YAClE,OAAO,IAAI,CAAC,SAAS,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,SAAS,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,SAAS,CAAC;QACxB,CAAC;IACH,CAAC;IAEO,QAAQ;QACd,eAAe,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACtD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAChC,aAAa,CAAC,uBAAuB,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrE,CAAC;IAEO,iBAAiB,CAAC,SAAiB;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAC1B,CAAC;QACD,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,8EAA8E;IAC9E,+DAA+D;IAC/D,8EAA8E;IAEtE,SAAS,CAAC,SAAiB;QACjC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;QAC/C,CAAC;QACD,OAAO,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;IAEO,UAAU,CAAC,SAAiB,EAAE,KAAwB;QAC5D,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,oBAAoB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;YACpC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YAC3B,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IAED,SAAS,CAAC,SAAiB;QACzB,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC;IAC1C,CAAC;IAED,UAAU,CAAC,SAAiB,EAAE,MAAmB;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,MAAM,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,WAAW,CAAC,SAAiB;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC,MAAM,CAAC;QACrB,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,aAAa,CAAC,SAAiB;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC;IAC9C,CAAC;IAED,cAAc,CAAC,SAAiB,EAAE,IAAiC;QACjE,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,eAAe,CAAC,SAAiB;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC,UAAU,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,eAAe,CAAC,SAAiB;QAC/B,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC;IAChD,CAAC;IAED,gBAAgB,CAAC,SAAiB,EAAE,QAAgB;QAClD,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,CAAC,YAAY,GAAG,QAAQ,CAAC;QAC/B,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,aAAa,CAAC,SAAiB,EAAE,IAAY;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,oBAAoB,CAAC,SAAiB;QACpC,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,iBAAiB,CAAC;IACrD,CAAC;IAED,QAAQ,CAAC,SAAiB;QACxB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;YACpC,IAAI,CAAC;gBAAC,cAAc,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QACtE,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;YACpC,OAAO,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IAED,mDAAmD;IACnD,eAAe;QACb,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,iBAAiB,EAAE,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,SAAS,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YACjC,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;CACF"}
package/dist/cli.js CHANGED
@@ -10,6 +10,7 @@
10
10
  import { parseArgs } from "node:util";
11
11
  import { readFileSync, existsSync } from "node:fs";
12
12
  import { McpGateway } from "./gateway.js";
13
+ import { preListenHttpServer } from "./http-proxy.js";
13
14
  import { loadConfig, findClaudeDesktopConfig, loadFromParentConfig, autoDetectConfig, discoverClaudeCodePlugins } from "./config.js";
14
15
  import { login, logout, getAuthStatus, ensureValidToken, getAccessToken, UpstreamTokenStore } from "./auth/index.js";
15
16
  import { SonomaClient } from "./sonoma-client.js";
@@ -123,6 +124,7 @@ async function main() {
123
124
  status: { type: "boolean" },
124
125
  reauth: { type: "boolean" },
125
126
  endpoint: { type: "string", short: "e" },
127
+ "http-proxy-port": { type: "string" },
126
128
  },
127
129
  strict: true,
128
130
  });
@@ -134,6 +136,29 @@ async function main() {
134
136
  console.error("@sonoma/mcp-gateway v0.1.0");
135
137
  process.exit(0);
136
138
  }
139
+ // Claim the HTTP proxy port IMMEDIATELY, before any async startup work (auth,
140
+ // policy fetch, upstream connects). Claude Code probes proxy URLs in
141
+ // parallel with spawning the gateway stdio process, and a probe that hits
142
+ // ECONNREFUSED is treated as a permanent failure with no retry. A prebound
143
+ // socket returns 503 until the gateway takes over, which keeps the probe
144
+ // happy long enough for the real handler to attach.
145
+ let preboundProxy;
146
+ const proxyPortStr = values["http-proxy-port"];
147
+ if (proxyPortStr) {
148
+ const port = parseInt(proxyPortStr, 10);
149
+ if (!Number.isNaN(port) && port >= 1 && port <= 65535) {
150
+ try {
151
+ preboundProxy = preListenHttpServer(port);
152
+ await preboundProxy.listening;
153
+ console.error(`[cli] HTTP proxy port ${port} claimed (awaiting gateway handler)`);
154
+ }
155
+ catch (error) {
156
+ const message = error instanceof Error ? error.message : String(error);
157
+ console.error(`[cli] Failed to claim HTTP proxy port ${port}: ${message}`);
158
+ preboundProxy = undefined;
159
+ }
160
+ }
161
+ }
137
162
  // Auth commands
138
163
  const sonomaEndpoint = values.endpoint || DEFAULT_SONOMA_ENDPOINT;
139
164
  if (values.login) {
@@ -323,8 +348,11 @@ async function main() {
323
348
  }
324
349
  }
325
350
  }
326
- // Inject implicit Sonoma MCP server so users don't need a separate config entry
327
- if (config.sonomaEndpoint) {
351
+ // Inject implicit Sonoma MCP server so users don't need a separate config entry.
352
+ // Skip in --http-proxy-port mode: that mode runs as a headless daemon (e.g.
353
+ // LaunchAgent) where OAuth browser flows are impossible and org API keys are
354
+ // rejected by /api/mcp — the implicit server would crash-loop on auth.
355
+ if (config.sonomaEndpoint && !values["http-proxy-port"]) {
328
356
  const hasAuth = authStatus.loggedIn || !!config.sonomaApiKey;
329
357
  const hasSonomaServer = config.servers.some((s) => s.name === "sonoma");
330
358
  if (hasAuth && !hasSonomaServer) {
@@ -362,6 +390,19 @@ async function main() {
362
390
  }
363
391
  }
364
392
  }
393
+ // HTTP proxy mode: expose per-server HTTP endpoints for plugin URL rewriting
394
+ if (values["http-proxy-port"]) {
395
+ const port = parseInt(values["http-proxy-port"], 10);
396
+ if (Number.isNaN(port) || port < 1 || port > 65535) {
397
+ console.error(`Invalid HTTP proxy port: ${values["http-proxy-port"]}`);
398
+ process.exit(2);
399
+ }
400
+ config.httpProxyPort = port;
401
+ if (preboundProxy) {
402
+ config.httpProxyServer = preboundProxy.server;
403
+ }
404
+ console.error(`[cli] HTTP proxy mode enabled on port ${port}`);
405
+ }
365
406
  const gateway = new McpGateway(config);
366
407
  // Handle shutdown gracefully
367
408
  const shutdown = async () => {
@@ -408,6 +449,11 @@ AUTH OPTIONS:
408
449
  --reauth Clear upstream OAuth tokens and re-authenticate
409
450
  -e, --endpoint <url> Sonoma API endpoint (default: https://app.sonoma.dev)
410
451
 
452
+ PROXY OPTIONS:
453
+ --http-proxy-port <port> Expose per-server HTTP endpoints for plugin proxying.
454
+ Each server is available at http://localhost:{port}/proxy/{name}/mcp.
455
+ Plugins can rewrite URLs to these endpoints to keep skills active.
456
+
411
457
  QUICKSTART (zero-config):
412
458
  Add to your ~/.cursor/mcp.json or Claude Desktop config:
413
459
  {