@n24q02m/mcp-core 0.1.0

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 (93) hide show
  1. package/build/crypto/aes.d.ts +8 -0
  2. package/build/crypto/aes.d.ts.map +1 -0
  3. package/build/crypto/aes.js +25 -0
  4. package/build/crypto/aes.js.map +1 -0
  5. package/build/crypto/ecdh.d.ts +5 -0
  6. package/build/crypto/ecdh.d.ts.map +1 -0
  7. package/build/crypto/ecdh.js +16 -0
  8. package/build/crypto/ecdh.js.map +1 -0
  9. package/build/crypto/index.d.ts +4 -0
  10. package/build/crypto/index.d.ts.map +1 -0
  11. package/build/crypto/index.js +4 -0
  12. package/build/crypto/index.js.map +1 -0
  13. package/build/crypto/kdf.d.ts +2 -0
  14. package/build/crypto/kdf.d.ts.map +1 -0
  15. package/build/crypto/kdf.js +7 -0
  16. package/build/crypto/kdf.js.map +1 -0
  17. package/build/index.d.ts +12 -0
  18. package/build/index.d.ts.map +1 -0
  19. package/build/index.js +12 -0
  20. package/build/index.js.map +1 -0
  21. package/build/oauth/index.d.ts +4 -0
  22. package/build/oauth/index.d.ts.map +1 -0
  23. package/build/oauth/index.js +4 -0
  24. package/build/oauth/index.js.map +1 -0
  25. package/build/oauth/jwt-issuer.d.ts +25 -0
  26. package/build/oauth/jwt-issuer.d.ts.map +1 -0
  27. package/build/oauth/jwt-issuer.js +79 -0
  28. package/build/oauth/jwt-issuer.js.map +1 -0
  29. package/build/oauth/provider.d.ts +67 -0
  30. package/build/oauth/provider.d.ts.map +1 -0
  31. package/build/oauth/provider.js +129 -0
  32. package/build/oauth/provider.js.map +1 -0
  33. package/build/oauth/user-store.d.ts +25 -0
  34. package/build/oauth/user-store.d.ts.map +1 -0
  35. package/build/oauth/user-store.js +78 -0
  36. package/build/oauth/user-store.js.map +1 -0
  37. package/build/relay/browser.d.ts +15 -0
  38. package/build/relay/browser.d.ts.map +1 -0
  39. package/build/relay/browser.js +76 -0
  40. package/build/relay/browser.js.map +1 -0
  41. package/build/relay/client.d.ts +17 -0
  42. package/build/relay/client.d.ts.map +1 -0
  43. package/build/relay/client.js +87 -0
  44. package/build/relay/client.js.map +1 -0
  45. package/build/relay/wordlist.d.ts +2 -0
  46. package/build/relay/wordlist.d.ts.map +1 -0
  47. package/build/relay/wordlist.js +7782 -0
  48. package/build/relay/wordlist.js.map +1 -0
  49. package/build/schema/types.d.ts +42 -0
  50. package/build/schema/types.d.ts.map +1 -0
  51. package/build/schema/types.js +2 -0
  52. package/build/schema/types.js.map +1 -0
  53. package/build/storage/config-file.d.ts +8 -0
  54. package/build/storage/config-file.d.ts.map +1 -0
  55. package/build/storage/config-file.js +136 -0
  56. package/build/storage/config-file.js.map +1 -0
  57. package/build/storage/encryption.d.ts +7 -0
  58. package/build/storage/encryption.d.ts.map +1 -0
  59. package/build/storage/encryption.js +26 -0
  60. package/build/storage/encryption.js.map +1 -0
  61. package/build/storage/index.d.ts +7 -0
  62. package/build/storage/index.d.ts.map +1 -0
  63. package/build/storage/index.js +7 -0
  64. package/build/storage/index.js.map +1 -0
  65. package/build/storage/machine-id.d.ts +3 -0
  66. package/build/storage/machine-id.d.ts.map +1 -0
  67. package/build/storage/machine-id.js +47 -0
  68. package/build/storage/machine-id.js.map +1 -0
  69. package/build/storage/mode.d.ts +23 -0
  70. package/build/storage/mode.d.ts.map +1 -0
  71. package/build/storage/mode.js +43 -0
  72. package/build/storage/mode.js.map +1 -0
  73. package/build/storage/resolver.d.ts +7 -0
  74. package/build/storage/resolver.d.ts.map +1 -0
  75. package/build/storage/resolver.js +37 -0
  76. package/build/storage/resolver.js.map +1 -0
  77. package/build/storage/session-lock.d.ts +19 -0
  78. package/build/storage/session-lock.d.ts.map +1 -0
  79. package/build/storage/session-lock.js +94 -0
  80. package/build/storage/session-lock.js.map +1 -0
  81. package/build/transport/index.d.ts +3 -0
  82. package/build/transport/index.d.ts.map +1 -0
  83. package/build/transport/index.js +3 -0
  84. package/build/transport/index.js.map +1 -0
  85. package/build/transport/oauth-middleware.d.ts +32 -0
  86. package/build/transport/oauth-middleware.d.ts.map +1 -0
  87. package/build/transport/oauth-middleware.js +62 -0
  88. package/build/transport/oauth-middleware.js.map +1 -0
  89. package/build/transport/streamable-http.d.ts +54 -0
  90. package/build/transport/streamable-http.d.ts.map +1 -0
  91. package/build/transport/streamable-http.js +57 -0
  92. package/build/transport/streamable-http.js.map +1 -0
  93. package/package.json +88 -0
@@ -0,0 +1,8 @@
1
+ export interface EncryptResult {
2
+ ciphertext: Uint8Array;
3
+ iv: Uint8Array;
4
+ tag: Uint8Array;
5
+ }
6
+ export declare function encrypt(key: CryptoKey, plaintext: string): Promise<EncryptResult>;
7
+ export declare function decrypt(key: CryptoKey, ciphertext: Uint8Array, iv: Uint8Array, tag?: Uint8Array): Promise<string>;
8
+ //# sourceMappingURL=aes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aes.d.ts","sourceRoot":"","sources":["../../src/crypto/aes.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,CAAA;IACtB,EAAE,EAAE,UAAU,CAAA;IACd,GAAG,EAAE,UAAU,CAAA;CAChB;AAED,wBAAsB,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAWvF;AAED,wBAAsB,OAAO,CAC3B,GAAG,EAAE,SAAS,EACd,UAAU,EAAE,UAAU,EACtB,EAAE,EAAE,UAAU,EACd,GAAG,CAAC,EAAE,UAAU,GACf,OAAO,CAAC,MAAM,CAAC,CAYjB"}
@@ -0,0 +1,25 @@
1
+ export async function encrypt(key, plaintext) {
2
+ const iv = crypto.getRandomValues(new Uint8Array(12));
3
+ const encoded = new TextEncoder().encode(plaintext);
4
+ const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encoded);
5
+ // WebCrypto appends 16-byte GCM tag to ciphertext
6
+ const combined = new Uint8Array(encrypted);
7
+ const ciphertext = combined.slice(0, combined.length - 16);
8
+ const tag = combined.slice(combined.length - 16);
9
+ return { ciphertext, iv, tag };
10
+ }
11
+ export async function decrypt(key, ciphertext, iv, tag) {
12
+ let data;
13
+ if (tag) {
14
+ data = new Uint8Array(ciphertext.length + tag.length);
15
+ data.set(ciphertext, 0);
16
+ data.set(tag, ciphertext.length);
17
+ }
18
+ else {
19
+ data = new Uint8Array(ciphertext);
20
+ }
21
+ const ivCopy = new Uint8Array(iv);
22
+ const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv: ivCopy }, key, data);
23
+ return new TextDecoder().decode(decrypted);
24
+ }
25
+ //# sourceMappingURL=aes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aes.js","sourceRoot":"","sources":["../../src/crypto/aes.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAc,EAAE,SAAiB;IAC7D,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;IACrD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;IACnD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,CAAA;IAEpF,kDAAkD;IAClD,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,SAAS,CAAC,CAAA;IAC1C,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;IAC1D,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;IAEhD,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,GAAG,EAAE,CAAA;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAc,EACd,UAAsB,EACtB,EAAc,EACd,GAAgB;IAEhB,IAAI,IAA6B,CAAA;IACjC,IAAI,GAAG,EAAE,CAAC;QACR,IAAI,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAA;QACrD,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;QACvB,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;IAClC,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,CAAA;IACnC,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;IACjC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IACzF,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;AAC5C,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function generateKeyPair(): Promise<CryptoKeyPair>;
2
+ export declare function exportPublicKey(key: CryptoKey): Promise<string>;
3
+ export declare function importPublicKey(base64url: string): Promise<CryptoKey>;
4
+ export declare function deriveSharedSecret(privateKey: CryptoKey, publicKey: CryptoKey): Promise<ArrayBuffer>;
5
+ //# sourceMappingURL=ecdh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ecdh.d.ts","sourceRoot":"","sources":["../../src/crypto/ecdh.ts"],"names":[],"mappings":"AAEA,wBAAsB,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,CAE9D;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAGrE;AAED,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAG3E;AAED,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAE1G"}
@@ -0,0 +1,16 @@
1
+ const ALGORITHM = { name: 'ECDH', namedCurve: 'P-256' };
2
+ export async function generateKeyPair() {
3
+ return crypto.subtle.generateKey(ALGORITHM, true, ['deriveKey', 'deriveBits']);
4
+ }
5
+ export async function exportPublicKey(key) {
6
+ const raw = await crypto.subtle.exportKey('raw', key);
7
+ return Buffer.from(raw).toString('base64url');
8
+ }
9
+ export async function importPublicKey(base64url) {
10
+ const raw = Buffer.from(base64url, 'base64url');
11
+ return crypto.subtle.importKey('raw', raw, ALGORITHM, true, []);
12
+ }
13
+ export async function deriveSharedSecret(privateKey, publicKey) {
14
+ return crypto.subtle.deriveBits({ name: 'ECDH', public: publicKey }, privateKey, 256);
15
+ }
16
+ //# sourceMappingURL=ecdh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ecdh.js","sourceRoot":"","sources":["../../src/crypto/ecdh.ts"],"names":[],"mappings":"AAAA,MAAM,SAAS,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,CAAA;AAEvD,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,OAAO,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAA;AAChF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAc;IAClD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACrD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;AAC/C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,SAAiB;IACrD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAA;IAC/C,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,UAAqB,EAAE,SAAoB;IAClF,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,UAAU,EAAE,GAAG,CAAC,CAAA;AACvF,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { decrypt, type EncryptResult, encrypt } from './aes.js';
2
+ export { deriveSharedSecret, exportPublicKey, generateKeyPair, importPublicKey } from './ecdh.js';
3
+ export { deriveAesKey } from './kdf.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AACjG,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { decrypt, encrypt } from './aes.js';
2
+ export { deriveSharedSecret, exportPublicKey, generateKeyPair, importPublicKey } from './ecdh.js';
3
+ export { deriveAesKey } from './kdf.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crypto/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAsB,OAAO,EAAE,MAAM,UAAU,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AACjG,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,2 @@
1
+ export declare function deriveAesKey(sharedSecret: ArrayBuffer, passphrase: string): Promise<CryptoKey>;
2
+ //# sourceMappingURL=kdf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kdf.d.ts","sourceRoot":"","sources":["../../src/crypto/kdf.ts"],"names":[],"mappings":"AAEA,wBAAsB,YAAY,CAAC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAWpG"}
@@ -0,0 +1,7 @@
1
+ const INFO = new TextEncoder().encode('mcp-relay');
2
+ export async function deriveAesKey(sharedSecret, passphrase) {
3
+ const salt = new TextEncoder().encode(passphrase);
4
+ const keyMaterial = await crypto.subtle.importKey('raw', sharedSecret, 'HKDF', false, ['deriveKey']);
5
+ return crypto.subtle.deriveKey({ name: 'HKDF', hash: 'SHA-256', salt, info: INFO }, keyMaterial, { name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']);
6
+ }
7
+ //# sourceMappingURL=kdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kdf.js","sourceRoot":"","sources":["../../src/crypto/kdf.ts"],"names":[],"mappings":"AAAA,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;AAElD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,YAAyB,EAAE,UAAkB;IAC9E,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IACjD,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;IAEpG,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAC5B,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EACnD,WAAW,EACX,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,EAChC,IAAI,EACJ,CAAC,SAAS,EAAE,SAAS,CAAC,CACvB,CAAA;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ export * from './crypto/index.js';
2
+ export { JWTIssuer } from './oauth/jwt-issuer.js';
3
+ export { InMemoryAuthCache, type IOAuthSessionCache, OAuthProvider, type OAuthProviderOptions, type PreAuthSession } from './oauth/provider.js';
4
+ export { type IUserCredentialStore, SqliteUserStore } from './oauth/user-store.js';
5
+ export { tryOpenBrowser } from './relay/browser.js';
6
+ export { createSession, generatePassphrase, pollForResponses, pollForResult, type RelaySession, sendMessage } from './relay/client.js';
7
+ export type * from './schema/types.js';
8
+ export { deleteConfig, exportConfig, importConfig, listConfigs, readConfig, writeConfig } from './storage/config-file.js';
9
+ export { clearMode, getMode, type ServerMode, setLocalMode } from './storage/mode.js';
10
+ export * from './storage/resolver.js';
11
+ export { acquireSessionLock, releaseSessionLock, type SessionInfo, writeSessionLock } from './storage/session-lock.js';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACpB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,KAAK,oBAAoB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,KAAK,YAAY,EACjB,WAAW,EACZ,MAAM,mBAAmB,CAAA;AAC1B,mBAAmB,mBAAmB,CAAA;AACtC,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,UAAU,EACV,WAAW,EACZ,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrF,cAAc,uBAAuB,CAAA;AACrC,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,WAAW,EAChB,gBAAgB,EACjB,MAAM,2BAA2B,CAAA"}
package/build/index.js ADDED
@@ -0,0 +1,12 @@
1
+ export * from './crypto/index.js';
2
+ // OAuth 2.1 multi-user infrastructure (HTTP mode)
3
+ export { JWTIssuer } from './oauth/jwt-issuer.js';
4
+ export { InMemoryAuthCache, OAuthProvider } from './oauth/provider.js';
5
+ export { SqliteUserStore } from './oauth/user-store.js';
6
+ export { tryOpenBrowser } from './relay/browser.js';
7
+ export { createSession, generatePassphrase, pollForResponses, pollForResult, sendMessage } from './relay/client.js';
8
+ export { deleteConfig, exportConfig, importConfig, listConfigs, readConfig, writeConfig } from './storage/config-file.js';
9
+ export { clearMode, getMode, setLocalMode } from './storage/mode.js';
10
+ export * from './storage/resolver.js';
11
+ export { acquireSessionLock, releaseSessionLock, writeSessionLock } from './storage/session-lock.js';
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAA;AACjC,kDAAkD;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAA;AACjD,OAAO,EACL,iBAAiB,EAEjB,aAAa,EAGd,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAA6B,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EAEb,WAAW,EACZ,MAAM,mBAAmB,CAAA;AAE1B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,UAAU,EACV,WAAW,EACZ,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAmB,YAAY,EAAE,MAAM,mBAAmB,CAAA;AACrF,cAAc,uBAAuB,CAAA;AACrC,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAElB,gBAAgB,EACjB,MAAM,2BAA2B,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { JWTIssuer } from './jwt-issuer.js';
2
+ export { InMemoryAuthCache, type IOAuthSessionCache, OAuthProvider, type OAuthProviderOptions, type PreAuthSession } from './provider.js';
3
+ export { type IUserCredentialStore, SqliteUserStore } from './user-store.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EACL,iBAAiB,EACjB,KAAK,kBAAkB,EACvB,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACpB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,KAAK,oBAAoB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { JWTIssuer } from './jwt-issuer.js';
2
+ export { InMemoryAuthCache, OAuthProvider } from './provider.js';
3
+ export { SqliteUserStore } from './user-store.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EACL,iBAAiB,EAEjB,aAAa,EAGd,MAAM,eAAe,CAAA;AACtB,OAAO,EAA6B,eAAe,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * RSA JWT Issuer and JWKS generation for TypeScript MCP servers.
3
+ * Uses jose (industry-standard, zero-dep, Web Crypto compatible).
4
+ */
5
+ import * as jose from 'jose';
6
+ export declare class JWTIssuer {
7
+ private serverName;
8
+ private keysDir;
9
+ private privateKeyPath;
10
+ private publicKeyPath;
11
+ private kid;
12
+ private privateKey;
13
+ private publicKey;
14
+ private _initialized;
15
+ constructor(serverName: string, keysDir?: string);
16
+ /** Must call before using issuer — loads or generates RSA keys. */
17
+ init(): Promise<void>;
18
+ /** Return JWKS payload for /.well-known/jwks.json */
19
+ getJwks(): Promise<jose.JSONWebKeySet>;
20
+ /** Issue an RS256 JWT access token. */
21
+ issueAccessToken(sub: string, expiresInSeconds?: number): Promise<string>;
22
+ /** Verify JWT and return payload. Throws on failure. */
23
+ verifyAccessToken(token: string): Promise<jose.JWTPayload>;
24
+ }
25
+ //# sourceMappingURL=jwt-issuer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-issuer.d.ts","sourceRoot":"","sources":["../../src/oauth/jwt-issuer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAI5B,qBAAa,SAAS;IACpB,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,GAAG,CAAU;IACrB,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,YAAY,CAAQ;gBAEhB,UAAU,EAAE,MAAM,EAAE,OAAO,SAAmB;IAO1D,mEAAmE;IAC7D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B3B,qDAAqD;IAC/C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC;IAS5C,uCAAuC;IACjC,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,gBAAgB,SAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAW7E,wDAAwD;IAClD,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;CAQjE"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * RSA JWT Issuer and JWKS generation for TypeScript MCP servers.
3
+ * Uses jose (industry-standard, zero-dep, Web Crypto compatible).
4
+ */
5
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
6
+ import { homedir } from 'node:os';
7
+ import { join } from 'node:path';
8
+ import * as jose from 'jose';
9
+ const DEFAULT_KEYS_DIR = join(homedir(), '.mcp-core', 'jwt-keys');
10
+ export class JWTIssuer {
11
+ constructor(serverName, keysDir = DEFAULT_KEYS_DIR) {
12
+ this.kid = 'key-1';
13
+ this.privateKey = null;
14
+ this.publicKey = null;
15
+ this._initialized = false;
16
+ this.serverName = serverName;
17
+ this.keysDir = keysDir;
18
+ this.privateKeyPath = join(this.keysDir, `${serverName}_private.pem`);
19
+ this.publicKeyPath = join(this.keysDir, `${serverName}_public.pem`);
20
+ }
21
+ /** Must call before using issuer — loads or generates RSA keys. */
22
+ async init() {
23
+ if (this._initialized)
24
+ return;
25
+ mkdirSync(this.keysDir, { recursive: true });
26
+ if (existsSync(this.privateKeyPath) && existsSync(this.publicKeyPath)) {
27
+ const privatePem = readFileSync(this.privateKeyPath, 'utf-8');
28
+ const publicPem = readFileSync(this.publicKeyPath, 'utf-8');
29
+ this.privateKey = await jose.importPKCS8(privatePem, 'RS256');
30
+ this.publicKey = await jose.importSPKI(publicPem, 'RS256');
31
+ }
32
+ else {
33
+ const { publicKey, privateKey } = await jose.generateKeyPair('RS256', {
34
+ modulusLength: 2048,
35
+ extractable: true
36
+ });
37
+ this.privateKey = privateKey;
38
+ this.publicKey = publicKey;
39
+ const privatePem = await jose.exportPKCS8(privateKey);
40
+ const publicPem = await jose.exportSPKI(publicKey);
41
+ writeFileSync(this.privateKeyPath, privatePem, { mode: 0o600 });
42
+ writeFileSync(this.publicKeyPath, publicPem, { mode: 0o644 });
43
+ }
44
+ this._initialized = true;
45
+ }
46
+ /** Return JWKS payload for /.well-known/jwks.json */
47
+ async getJwks() {
48
+ if (!this.publicKey)
49
+ throw new Error('JWTIssuer not initialized');
50
+ const jwk = await jose.exportJWK(this.publicKey);
51
+ jwk.kid = this.kid;
52
+ jwk.use = 'sig';
53
+ jwk.alg = 'RS256';
54
+ return { keys: [jwk] };
55
+ }
56
+ /** Issue an RS256 JWT access token. */
57
+ async issueAccessToken(sub, expiresInSeconds = 3600) {
58
+ if (!this.privateKey)
59
+ throw new Error('JWTIssuer not initialized');
60
+ return new jose.SignJWT({ sub })
61
+ .setProtectedHeader({ alg: 'RS256', kid: this.kid })
62
+ .setIssuer(this.serverName)
63
+ .setAudience(this.serverName)
64
+ .setIssuedAt()
65
+ .setExpirationTime(`${expiresInSeconds}s`)
66
+ .sign(this.privateKey);
67
+ }
68
+ /** Verify JWT and return payload. Throws on failure. */
69
+ async verifyAccessToken(token) {
70
+ if (!this.publicKey)
71
+ throw new Error('JWTIssuer not initialized');
72
+ const { payload } = await jose.jwtVerify(token, this.publicKey, {
73
+ issuer: this.serverName,
74
+ audience: this.serverName
75
+ });
76
+ return payload;
77
+ }
78
+ }
79
+ //# sourceMappingURL=jwt-issuer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt-issuer.js","sourceRoot":"","sources":["../../src/oauth/jwt-issuer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * OAuth 2.1 Provider logic for TypeScript MCP servers.
3
+ *
4
+ * Implements the "MCP Server as Authorization Server" pattern.
5
+ * The MCP Server issues JWTs, processes PKCE verification,
6
+ * and uses the Relay Server purely as a UI consent transport.
7
+ */
8
+ import type { RelayConfigSchema } from '../schema/types.js';
9
+ import type { JWTIssuer } from './jwt-issuer.js';
10
+ export interface PreAuthSession {
11
+ sessionId: string;
12
+ clientId: string;
13
+ redirectUri: string;
14
+ state: string;
15
+ codeChallenge: string;
16
+ codeChallengeMethod: string;
17
+ /** Serialized CryptoKeyPair for later credential retrieval */
18
+ keyPairJwk: JsonWebKey;
19
+ passphrase: string;
20
+ expiresAt: number;
21
+ }
22
+ export interface IOAuthSessionCache {
23
+ save(session: PreAuthSession): void;
24
+ getAndDelete(sessionId: string): PreAuthSession | null;
25
+ }
26
+ export declare class InMemoryAuthCache implements IOAuthSessionCache {
27
+ private cache;
28
+ save(session: PreAuthSession): void;
29
+ getAndDelete(sessionId: string): PreAuthSession | null;
30
+ }
31
+ export interface OAuthProviderOptions {
32
+ serverName: string;
33
+ relayBaseUrl: string;
34
+ relaySchema: RelayConfigSchema;
35
+ jwtIssuer: JWTIssuer;
36
+ cache?: IOAuthSessionCache;
37
+ }
38
+ export declare class OAuthProvider {
39
+ private serverName;
40
+ private relayBaseUrl;
41
+ private relaySchema;
42
+ private jwtIssuer;
43
+ private cache;
44
+ constructor(options: OAuthProviderOptions);
45
+ /**
46
+ * Create a relay session and return the URL to redirect the user to.
47
+ */
48
+ createAuthorizeRedirect(clientId: string, redirectUri: string, state: string, codeChallenge: string, codeChallengeMethod?: string): Promise<string>;
49
+ /**
50
+ * Exchange the authorization code (relay session ID) for an access_token.
51
+ * PKCE verification is performed.
52
+ *
53
+ * @param code The authorization code from the client.
54
+ * @param codeVerifier The PKCE code verifier.
55
+ * @param userIdExtractor Function to derive a unique user_id from the credentials.
56
+ * @returns Tuple of [access_token, credentials]
57
+ */
58
+ exchangeCode(code: string, codeVerifier: string, userIdExtractor: (credentials: Record<string, string>) => string): Promise<{
59
+ accessToken: string;
60
+ credentials: Record<string, string>;
61
+ }>;
62
+ /**
63
+ * Get RFC 8414 Authorization Server Metadata.
64
+ */
65
+ getMetadata(baseUrl: string): Record<string, unknown>;
66
+ }
67
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/oauth/provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,CAAA;IACrB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,8DAA8D;IAC9D,UAAU,EAAE,UAAU,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;IACnC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAAA;CACvD;AAED,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,KAAK,CAAoC;IAEjD,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IASnC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;CAOvD;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,iBAAiB,CAAA;IAC9B,SAAS,EAAE,SAAS,CAAA;IACpB,KAAK,CAAC,EAAE,kBAAkB,CAAA;CAC3B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,SAAS,CAAW;IAC5B,OAAO,CAAC,KAAK,CAAoB;gBAErB,OAAO,EAAE,oBAAoB;IAQzC;;OAEG;IACG,uBAAuB,CAC3B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,mBAAmB,SAAS,GAC3B,OAAO,CAAC,MAAM,CAAC;IAqBlB;;;;;;;;OAQG;IACG,YAAY,CAChB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,MAAM,GAC/D,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IAwDxE;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAYtD"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * OAuth 2.1 Provider logic for TypeScript MCP servers.
3
+ *
4
+ * Implements the "MCP Server as Authorization Server" pattern.
5
+ * The MCP Server issues JWTs, processes PKCE verification,
6
+ * and uses the Relay Server purely as a UI consent transport.
7
+ */
8
+ import { createHash, timingSafeEqual } from 'node:crypto';
9
+ import { createSession, pollForResult } from '../relay/client.js';
10
+ export class InMemoryAuthCache {
11
+ constructor() {
12
+ this.cache = new Map();
13
+ }
14
+ save(session) {
15
+ this.cache.set(session.sessionId, session);
16
+ // Cleanup expired entries
17
+ const now = Math.floor(Date.now() / 1000);
18
+ for (const [id, sess] of this.cache) {
19
+ if (sess.expiresAt < now)
20
+ this.cache.delete(id);
21
+ }
22
+ }
23
+ getAndDelete(sessionId) {
24
+ const sess = this.cache.get(sessionId);
25
+ if (!sess)
26
+ return null;
27
+ this.cache.delete(sessionId);
28
+ if (sess.expiresAt < Math.floor(Date.now() / 1000))
29
+ return null;
30
+ return sess;
31
+ }
32
+ }
33
+ export class OAuthProvider {
34
+ constructor(options) {
35
+ this.serverName = options.serverName;
36
+ this.relayBaseUrl = options.relayBaseUrl;
37
+ this.relaySchema = options.relaySchema;
38
+ this.jwtIssuer = options.jwtIssuer;
39
+ this.cache = options.cache ?? new InMemoryAuthCache();
40
+ }
41
+ /**
42
+ * Create a relay session and return the URL to redirect the user to.
43
+ */
44
+ async createAuthorizeRedirect(clientId, redirectUri, state, codeChallenge, codeChallengeMethod = 'S256') {
45
+ const session = await createSession(this.relayBaseUrl, this.serverName, this.relaySchema);
46
+ // Export private key for later credential retrieval
47
+ const privateJwk = await crypto.subtle.exportKey('jwk', session.keyPair.privateKey);
48
+ const preAuth = {
49
+ sessionId: session.sessionId,
50
+ clientId,
51
+ redirectUri,
52
+ state,
53
+ codeChallenge,
54
+ codeChallengeMethod,
55
+ keyPairJwk: privateJwk,
56
+ passphrase: session.passphrase,
57
+ expiresAt: Math.floor(Date.now() / 1000) + 600 // 10 minutes
58
+ };
59
+ this.cache.save(preAuth);
60
+ return session.relayUrl;
61
+ }
62
+ /**
63
+ * Exchange the authorization code (relay session ID) for an access_token.
64
+ * PKCE verification is performed.
65
+ *
66
+ * @param code The authorization code from the client.
67
+ * @param codeVerifier The PKCE code verifier.
68
+ * @param userIdExtractor Function to derive a unique user_id from the credentials.
69
+ * @returns Tuple of [access_token, credentials]
70
+ */
71
+ async exchangeCode(code, codeVerifier, userIdExtractor) {
72
+ const preAuth = this.cache.getAndDelete(code);
73
+ if (!preAuth)
74
+ throw new Error('invalid_grant: Expired or invalid code');
75
+ // Verify PKCE
76
+ if (preAuth.codeChallengeMethod === 'S256') {
77
+ const digest = createHash('sha256').update(codeVerifier).digest('base64url');
78
+ const expected = Buffer.from(digest);
79
+ const actual = Buffer.from(preAuth.codeChallenge);
80
+ if (expected.length !== actual.length || !timingSafeEqual(expected, actual)) {
81
+ throw new Error('invalid_grant: PKCE verification failed');
82
+ }
83
+ }
84
+ else if (preAuth.codeChallengeMethod === 'plain') {
85
+ const expected = Buffer.from(codeVerifier);
86
+ const actual = Buffer.from(preAuth.codeChallenge);
87
+ if (expected.length !== actual.length || !timingSafeEqual(expected, actual)) {
88
+ throw new Error('invalid_grant: PKCE plain verification failed');
89
+ }
90
+ }
91
+ else {
92
+ throw new Error('unsupported_challenge_method');
93
+ }
94
+ // Reconstruct key pair to decrypt relay credentials
95
+ const privateKey = await crypto.subtle.importKey('jwk', preAuth.keyPairJwk, { name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey', 'deriveBits']);
96
+ const publicKey = await crypto.subtle.importKey('jwk', { ...preAuth.keyPairJwk, d: undefined }, { name: 'ECDH', namedCurve: 'P-256' }, true, []);
97
+ const reconstructedSession = {
98
+ sessionId: preAuth.sessionId,
99
+ keyPair: { privateKey, publicKey },
100
+ passphrase: preAuth.passphrase,
101
+ relayUrl: ''
102
+ };
103
+ // Poll for credentials (short timeout — form already submitted)
104
+ const credentials = await pollForResult(this.relayBaseUrl, reconstructedSession, 1000, 10_000);
105
+ // Extract unique user_id
106
+ const userId = userIdExtractor(credentials);
107
+ if (!userId)
108
+ throw new Error('server_error: Unable to extract user_id from credentials');
109
+ // Issue access token
110
+ const accessToken = await this.jwtIssuer.issueAccessToken(userId);
111
+ return { accessToken, credentials };
112
+ }
113
+ /**
114
+ * Get RFC 8414 Authorization Server Metadata.
115
+ */
116
+ getMetadata(baseUrl) {
117
+ return {
118
+ issuer: baseUrl,
119
+ authorization_endpoint: `${baseUrl}/authorize`,
120
+ token_endpoint: `${baseUrl}/token`,
121
+ jwks_uri: `${baseUrl}/.well-known/jwks.json`,
122
+ response_types_supported: ['code'],
123
+ grant_types_supported: ['authorization_code'],
124
+ code_challenge_methods_supported: ['S256', 'plain'],
125
+ token_endpoint_auth_methods_supported: ['none']
126
+ };
127
+ }
128
+ }
129
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/oauth/provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Per-user encrypted credential store for MCP HTTP modes.
3
+ * Uses better-sqlite3 for persistence and Node.js crypto for AES-256-GCM at-rest encryption.
4
+ */
5
+ export interface IUserCredentialStore {
6
+ saveCredentials(userId: string, config: Record<string, string>): void;
7
+ getCredentials(userId: string): Record<string, string> | null;
8
+ deleteCredentials(userId: string): void;
9
+ }
10
+ export declare class SqliteUserStore implements IUserCredentialStore {
11
+ private db;
12
+ private masterKey;
13
+ /**
14
+ * @param dbPath Path to the SQLite DB file.
15
+ * @param masterKey 32-byte AES key for at-rest encryption.
16
+ */
17
+ constructor(dbPath: string, masterKey: Buffer);
18
+ private encrypt;
19
+ private decrypt;
20
+ saveCredentials(userId: string, config: Record<string, string>): void;
21
+ getCredentials(userId: string): Record<string, string> | null;
22
+ deleteCredentials(userId: string): void;
23
+ close(): void;
24
+ }
25
+ //# sourceMappingURL=user-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-store.d.ts","sourceRoot":"","sources":["../../src/oauth/user-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,MAAM,WAAW,oBAAoB;IACnC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;IACrE,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;IAC7D,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CACxC;AAED,qBAAa,eAAgB,YAAW,oBAAoB;IAC1D,OAAO,CAAC,EAAE,CAAmB;IAC7B,OAAO,CAAC,SAAS,CAAQ;IAEzB;;;OAGG;gBACS,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAmB7C,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,OAAO;IASf,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAerE,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAc7D,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIvC,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Per-user encrypted credential store for MCP HTTP modes.
3
+ * Uses better-sqlite3 for persistence and Node.js crypto for AES-256-GCM at-rest encryption.
4
+ */
5
+ import { createCipheriv, createDecipheriv, randomBytes } from 'node:crypto';
6
+ import { mkdirSync } from 'node:fs';
7
+ import { dirname } from 'node:path';
8
+ import Database from 'better-sqlite3';
9
+ export class SqliteUserStore {
10
+ /**
11
+ * @param dbPath Path to the SQLite DB file.
12
+ * @param masterKey 32-byte AES key for at-rest encryption.
13
+ */
14
+ constructor(dbPath, masterKey) {
15
+ if (masterKey.length !== 32)
16
+ throw new Error('masterKey must be 32 bytes');
17
+ this.masterKey = masterKey;
18
+ // Ensure directory exists
19
+ mkdirSync(dirname(dbPath), { recursive: true });
20
+ this.db = new Database(dbPath);
21
+ this.db.pragma('journal_mode = WAL');
22
+ this.db.exec(`
23
+ CREATE TABLE IF NOT EXISTS users (
24
+ user_id TEXT PRIMARY KEY,
25
+ encrypted_config BLOB NOT NULL,
26
+ created_at INTEGER NOT NULL,
27
+ updated_at INTEGER NOT NULL
28
+ )
29
+ `);
30
+ }
31
+ encrypt(plaintext) {
32
+ const iv = randomBytes(12);
33
+ const cipher = createCipheriv('aes-256-gcm', this.masterKey, iv, { authTagLength: 16 });
34
+ const encrypted = Buffer.concat([cipher.update(plaintext, 'utf-8'), cipher.final()]);
35
+ const tag = cipher.getAuthTag();
36
+ // Layout: [12 iv] [16 tag] [... ciphertext]
37
+ return Buffer.concat([iv, tag, encrypted]);
38
+ }
39
+ decrypt(payload) {
40
+ const iv = payload.subarray(0, 12);
41
+ const tag = payload.subarray(12, 28);
42
+ const ciphertext = payload.subarray(28);
43
+ const decipher = createDecipheriv('aes-256-gcm', this.masterKey, iv, { authTagLength: 16 });
44
+ decipher.setAuthTag(tag);
45
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString('utf-8');
46
+ }
47
+ saveCredentials(userId, config) {
48
+ const now = Math.floor(Date.now() / 1000);
49
+ const encrypted = this.encrypt(JSON.stringify(config));
50
+ this.db
51
+ .prepare(`
52
+ INSERT INTO users (user_id, encrypted_config, created_at, updated_at)
53
+ VALUES (?, ?, ?, ?)
54
+ ON CONFLICT(user_id) DO UPDATE SET
55
+ encrypted_config = excluded.encrypted_config,
56
+ updated_at = excluded.updated_at
57
+ `)
58
+ .run(userId, encrypted, now, now);
59
+ }
60
+ getCredentials(userId) {
61
+ const row = this.db.prepare('SELECT encrypted_config FROM users WHERE user_id = ?').get(userId);
62
+ if (!row)
63
+ return null;
64
+ try {
65
+ return JSON.parse(this.decrypt(Buffer.from(row.encrypted_config)));
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ deleteCredentials(userId) {
72
+ this.db.prepare('DELETE FROM users WHERE user_id = ?').run(userId);
73
+ }
74
+ close() {
75
+ this.db.close();
76
+ }
77
+ }
78
+ //# sourceMappingURL=user-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user-store.js","sourceRoot":"","sources":["../../src/oauth/user-store.ts"],"names":[],"mappings":"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"}