@sonoma-security/mcp-gateway 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.
package/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # @sonoma/mcp-gateway
2
+
3
+ Local MCP proxy for tool-level visibility. Intercepts stdio MCP servers, aggregates tools, forwards calls.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ # With config file
9
+ bun run src/cli.ts --config config.json
10
+
11
+ # Auto-detect Claude Desktop config
12
+ bun run src/cli.ts --auto --debug
13
+ ```
14
+
15
+ ## Config Format
16
+
17
+ ```json
18
+ {
19
+ "servers": [
20
+ { "name": "fs", "command": "npx", "args": ["-y", "@anthropic-ai/mcp-server-filesystem", "/tmp"] }
21
+ ]
22
+ }
23
+ ```
24
+
25
+ Also accepts Claude Desktop `mcpServers` format.
26
+
27
+ ## Add to MCP Client
28
+
29
+ **Cursor** (`~/.cursor/mcp.json`):
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "sonoma": {
34
+ "command": "bun",
35
+ "args": ["run", "/path/to/packages/mcp-gateway/src/cli.ts", "--config", "/path/to/config.json"]
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ **Claude Code**:
42
+ ```bash
43
+ claude mcp add sonoma -- bun run /path/to/packages/mcp-gateway/src/cli.ts --config /path/to/config.json
44
+ ```
45
+
46
+ ## Development
47
+
48
+ ```bash
49
+ # Run tests (vitest)
50
+ bun run test
51
+
52
+ # Watch mode
53
+ bun run test -- --watch
54
+
55
+ # Typecheck
56
+ bun run typecheck
57
+ ```
58
+
59
+ ## Manual JSON-RPC Testing
60
+
61
+ ```bash
62
+ cat << 'EOF' | bun run src/cli.ts --config tests/fixtures/echo-server.json
63
+ {"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}
64
+ {"jsonrpc":"2.0","method":"tools/list","id":2}
65
+ EOF
66
+ ```
67
+
68
+ ## Architecture
69
+
70
+ ```
71
+ AI Client (stdio) → Gateway → [Upstream MCP Servers]
72
+
73
+ Tools namespaced as serverName__toolName
74
+ ```
75
+
76
+ ## Status
77
+
78
+ - [x] Core proxy (tools/list, tools/call forwarding)
79
+ - [x] Config loader (native + Claude Desktop format)
80
+ - [x] CLI
81
+ - [ ] Telemetry reporter
82
+ - [ ] Policy enforcement
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Simple OAuth 2.0 client with Dynamic Client Registration (DCR)
3
+ *
4
+ * Flow:
5
+ * 1. Discover auth endpoints via /.well-known/oauth-authorization-server
6
+ * 2. Register client via DCR (if not already registered)
7
+ * 3. Authorization code flow with PKCE
8
+ * 4. Store tokens, auto-refresh when expired
9
+ */
10
+ export interface AuthClientOptions {
11
+ sonomaEndpoint: string;
12
+ debug?: boolean;
13
+ }
14
+ /**
15
+ * Login via OAuth - opens browser, waits for callback
16
+ */
17
+ export declare function login(options: AuthClientOptions): Promise<void>;
18
+ /**
19
+ * Get valid access token - refreshes if expired
20
+ */
21
+ export declare function getAccessToken(options: AuthClientOptions): Promise<string>;
22
+ /**
23
+ * Logout - clear stored credentials
24
+ */
25
+ export declare function logout(): void;
26
+ /**
27
+ * Get auth status
28
+ */
29
+ export declare function getAuthStatus(): {
30
+ loggedIn: boolean;
31
+ endpoint?: string;
32
+ expiresAt?: Date;
33
+ hasRefreshToken: boolean;
34
+ };
35
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/auth/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAwBH,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AA2HD;;GAEG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkErE;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiChF;AAED;;GAEG;AACH,wBAAgB,MAAM,IAAI,IAAI,CAG7B;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;CAC1B,CASA"}
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Simple OAuth 2.0 client with Dynamic Client Registration (DCR)
3
+ *
4
+ * Flow:
5
+ * 1. Discover auth endpoints via /.well-known/oauth-authorization-server
6
+ * 2. Register client via DCR (if not already registered)
7
+ * 3. Authorization code flow with PKCE
8
+ * 4. Store tokens, auto-refresh when expired
9
+ */
10
+ import { createHash, randomBytes } from "node:crypto";
11
+ import { loadCredentials, saveCredentials, clearCredentials } from "./storage";
12
+ import { startCallbackServer, getCallbackUrl } from "./server";
13
+ const CALLBACK_PORT = 19842;
14
+ const CLIENT_NAME = "Sonoma MCP Gateway";
15
+ function log(debug, msg, ...args) {
16
+ if (debug)
17
+ console.error(`[auth] ${msg}`, ...args);
18
+ }
19
+ /** Discover OAuth endpoints */
20
+ async function discoverAuthServer(sonomaUrl) {
21
+ const url = `${sonomaUrl}/.well-known/oauth-authorization-server`;
22
+ const res = await fetch(url);
23
+ if (!res.ok)
24
+ throw new Error(`Failed to discover auth server: ${res.status}`);
25
+ return res.json();
26
+ }
27
+ /** Generate PKCE code verifier and challenge */
28
+ function generatePKCE() {
29
+ const verifier = randomBytes(32).toString("base64url");
30
+ const challenge = createHash("sha256").update(verifier).digest("base64url");
31
+ return { verifier, challenge };
32
+ }
33
+ /** Open URL in browser */
34
+ async function openBrowser(url) {
35
+ const { exec } = await import("node:child_process");
36
+ const platform = process.platform;
37
+ if (platform === "darwin") {
38
+ exec(`open "${url}"`);
39
+ }
40
+ else if (platform === "win32") {
41
+ exec(`start "" "${url}"`);
42
+ }
43
+ else {
44
+ exec(`xdg-open "${url}"`);
45
+ }
46
+ }
47
+ /** Register client via DCR */
48
+ async function registerClient(metadata, debug) {
49
+ if (!metadata.registration_endpoint) {
50
+ throw new Error("Auth server does not support Dynamic Client Registration");
51
+ }
52
+ log(debug, "Registering client via DCR...");
53
+ const res = await fetch(metadata.registration_endpoint, {
54
+ method: "POST",
55
+ headers: { "Content-Type": "application/json" },
56
+ body: JSON.stringify({
57
+ client_name: CLIENT_NAME,
58
+ redirect_uris: [getCallbackUrl(CALLBACK_PORT)],
59
+ grant_types: ["authorization_code", "refresh_token"],
60
+ response_types: ["code"],
61
+ token_endpoint_auth_method: "none", // Public client (PKCE only)
62
+ }),
63
+ });
64
+ if (!res.ok) {
65
+ const error = await res.text();
66
+ throw new Error(`DCR failed: ${res.status} - ${error}`);
67
+ }
68
+ const data = await res.json();
69
+ log(debug, "Client registered:", data.client_id);
70
+ return {
71
+ clientId: data.client_id,
72
+ clientSecret: data.client_secret,
73
+ };
74
+ }
75
+ /** Exchange authorization code for tokens */
76
+ async function exchangeCode(metadata, code, codeVerifier, clientId) {
77
+ const res = await fetch(metadata.token_endpoint, {
78
+ method: "POST",
79
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
80
+ body: new URLSearchParams({
81
+ grant_type: "authorization_code",
82
+ code,
83
+ redirect_uri: getCallbackUrl(CALLBACK_PORT),
84
+ client_id: clientId,
85
+ code_verifier: codeVerifier,
86
+ }),
87
+ });
88
+ if (!res.ok) {
89
+ const error = await res.text();
90
+ throw new Error(`Token exchange failed: ${res.status} - ${error}`);
91
+ }
92
+ return res.json();
93
+ }
94
+ /** Refresh access token */
95
+ async function refreshTokens(metadata, refreshToken, clientId) {
96
+ const res = await fetch(metadata.token_endpoint, {
97
+ method: "POST",
98
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
99
+ body: new URLSearchParams({
100
+ grant_type: "refresh_token",
101
+ refresh_token: refreshToken,
102
+ client_id: clientId,
103
+ }),
104
+ });
105
+ if (!res.ok) {
106
+ const error = await res.text();
107
+ throw new Error(`Token refresh failed: ${res.status} - ${error}`);
108
+ }
109
+ return res.json();
110
+ }
111
+ /**
112
+ * Login via OAuth - opens browser, waits for callback
113
+ */
114
+ export async function login(options) {
115
+ const { sonomaEndpoint, debug = false } = options;
116
+ log(debug, "Starting login flow...");
117
+ // 1. Discover auth endpoints
118
+ const metadata = await discoverAuthServer(sonomaEndpoint);
119
+ log(debug, "Auth server:", metadata.issuer);
120
+ // 2. Check if we have a registered client, or register one
121
+ let creds = loadCredentials();
122
+ if (!creds?.clientId || creds.sonomaEndpoint !== sonomaEndpoint) {
123
+ const client = await registerClient(metadata, debug);
124
+ creds = {
125
+ clientId: client.clientId,
126
+ clientSecret: client.clientSecret,
127
+ sonomaEndpoint,
128
+ };
129
+ saveCredentials(creds);
130
+ }
131
+ // 3. Generate PKCE
132
+ const pkce = generatePKCE();
133
+ // 4. Build authorization URL
134
+ const state = randomBytes(16).toString("hex");
135
+ const authUrl = new URL(metadata.authorization_endpoint);
136
+ authUrl.searchParams.set("response_type", "code");
137
+ authUrl.searchParams.set("client_id", creds.clientId);
138
+ authUrl.searchParams.set("redirect_uri", getCallbackUrl(CALLBACK_PORT));
139
+ authUrl.searchParams.set("code_challenge", pkce.challenge);
140
+ authUrl.searchParams.set("code_challenge_method", "S256");
141
+ authUrl.searchParams.set("state", state);
142
+ authUrl.searchParams.set("scope", "openid profile email");
143
+ // 5. Start callback server and open browser
144
+ console.error("\nOpening browser for authentication...");
145
+ console.error(`If browser doesn't open, visit:\n${authUrl.toString()}\n`);
146
+ const callbackPromise = startCallbackServer({ port: CALLBACK_PORT, debug });
147
+ await openBrowser(authUrl.toString());
148
+ // 6. Wait for callback
149
+ const result = await callbackPromise;
150
+ if (result.state !== state) {
151
+ throw new Error("State mismatch - possible CSRF attack");
152
+ }
153
+ log(debug, "Received authorization code");
154
+ // 7. Exchange code for tokens
155
+ const tokens = await exchangeCode(metadata, result.code, pkce.verifier, creds.clientId);
156
+ log(debug, "Got tokens, expires_in:", tokens.expires_in);
157
+ // 8. Save tokens
158
+ saveCredentials({
159
+ ...creds,
160
+ accessToken: tokens.access_token,
161
+ refreshToken: tokens.refresh_token,
162
+ tokenType: tokens.token_type,
163
+ scope: tokens.scope,
164
+ expiresAt: tokens.expires_in ? Date.now() + tokens.expires_in * 1000 : undefined,
165
+ lastRefreshed: Date.now(),
166
+ });
167
+ console.error("\nAuthentication successful!");
168
+ }
169
+ /**
170
+ * Get valid access token - refreshes if expired
171
+ */
172
+ export async function getAccessToken(options) {
173
+ const { sonomaEndpoint, debug = false } = options;
174
+ const creds = loadCredentials();
175
+ if (!creds?.accessToken) {
176
+ throw new Error("Not logged in. Run: sonoma-gateway --login");
177
+ }
178
+ if (creds.sonomaEndpoint !== sonomaEndpoint) {
179
+ throw new Error(`Logged in to different endpoint: ${creds.sonomaEndpoint}`);
180
+ }
181
+ // Check if token needs refresh (5 min buffer)
182
+ const needsRefresh = creds.expiresAt && Date.now() + 300000 >= creds.expiresAt;
183
+ if (needsRefresh && creds.refreshToken && creds.clientId) {
184
+ log(debug, "Refreshing token...");
185
+ const metadata = await discoverAuthServer(sonomaEndpoint);
186
+ const tokens = await refreshTokens(metadata, creds.refreshToken, creds.clientId);
187
+ saveCredentials({
188
+ ...creds,
189
+ accessToken: tokens.access_token,
190
+ refreshToken: tokens.refresh_token || creds.refreshToken,
191
+ expiresAt: tokens.expires_in ? Date.now() + tokens.expires_in * 1000 : undefined,
192
+ lastRefreshed: Date.now(),
193
+ });
194
+ return tokens.access_token;
195
+ }
196
+ return creds.accessToken;
197
+ }
198
+ /**
199
+ * Logout - clear stored credentials
200
+ */
201
+ export function logout() {
202
+ clearCredentials();
203
+ console.error("Logged out successfully");
204
+ }
205
+ /**
206
+ * Get auth status
207
+ */
208
+ export function getAuthStatus() {
209
+ const creds = loadCredentials();
210
+ return {
211
+ loggedIn: !!creds?.accessToken,
212
+ endpoint: creds?.sonomaEndpoint,
213
+ expiresAt: creds?.expiresAt ? new Date(creds.expiresAt) : undefined,
214
+ hasRefreshToken: !!creds?.refreshToken,
215
+ };
216
+ }
217
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/auth/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/D,MAAM,aAAa,GAAG,KAAK,CAAC;AAC5B,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAsBzC,SAAS,GAAG,CAAC,KAAc,EAAE,GAAW,EAAE,GAAG,IAAe;IAC1D,IAAI,KAAK;QAAE,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,+BAA+B;AAC/B,KAAK,UAAU,kBAAkB,CAAC,SAAiB;IACjD,MAAM,GAAG,GAAG,GAAG,SAAS,yCAAyC,CAAC;IAClE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9E,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,gDAAgD;AAChD,SAAS,YAAY;IACnB,MAAM,QAAQ,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAC5E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC;AAED,0BAA0B;AAC1B,KAAK,UAAU,WAAW,CAAC,GAAW;IACpC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAElC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC;IACxB,CAAC;SAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChC,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,CAAC;IAC5B,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,8BAA8B;AAC9B,KAAK,UAAU,cAAc,CAC3B,QAA4B,EAC5B,KAAc;IAEd,IAAI,CAAC,QAAQ,CAAC,qBAAqB,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IAED,GAAG,CAAC,KAAK,EAAE,+BAA+B,CAAC,CAAC;IAE5C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,qBAAqB,EAAE;QACtD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,WAAW,EAAE,WAAW;YACxB,aAAa,EAAE,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;YAC9C,WAAW,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;YACpD,cAAc,EAAE,CAAC,MAAM,CAAC;YACxB,0BAA0B,EAAE,MAAM,EAAE,4BAA4B;SACjE,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,eAAe,GAAG,CAAC,MAAM,MAAM,KAAK,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,GAAG,CAAC,KAAK,EAAE,oBAAoB,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAEjD,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,SAAS;QACxB,YAAY,EAAE,IAAI,CAAC,aAAa;KACjC,CAAC;AACJ,CAAC;AAED,6CAA6C;AAC7C,KAAK,UAAU,YAAY,CACzB,QAA4B,EAC5B,IAAY,EACZ,YAAoB,EACpB,QAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE;QAC/C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;QAChE,IAAI,EAAE,IAAI,eAAe,CAAC;YACxB,UAAU,EAAE,oBAAoB;YAChC,IAAI;YACJ,YAAY,EAAE,cAAc,CAAC,aAAa,CAAC;YAC3C,SAAS,EAAE,QAAQ;YACnB,aAAa,EAAE,YAAY;SAC5B,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,CAAC,MAAM,MAAM,KAAK,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,2BAA2B;AAC3B,KAAK,UAAU,aAAa,CAC1B,QAA4B,EAC5B,YAAoB,EACpB,QAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE;QAC/C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;QAChE,IAAI,EAAE,IAAI,eAAe,CAAC;YACxB,UAAU,EAAE,eAAe;YAC3B,aAAa,EAAE,YAAY;YAC3B,SAAS,EAAE,QAAQ;SACpB,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,CAAC,MAAM,MAAM,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,OAA0B;IACpD,MAAM,EAAE,cAAc,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAElD,GAAG,CAAC,KAAK,EAAE,wBAAwB,CAAC,CAAC;IAErC,6BAA6B;IAC7B,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,cAAc,CAAC,CAAC;IAC1D,GAAG,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE5C,2DAA2D;IAC3D,IAAI,KAAK,GAAG,eAAe,EAAE,CAAC;IAC9B,IAAI,CAAC,KAAK,EAAE,QAAQ,IAAI,KAAK,CAAC,cAAc,KAAK,cAAc,EAAE,CAAC;QAChE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACrD,KAAK,GAAG;YACN,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,YAAY,EAAE,MAAM,CAAC,YAAY;YACjC,cAAc;SACf,CAAC;QACF,eAAe,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAED,mBAAmB;IACnB,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAE5B,6BAA6B;IAC7B,MAAM,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;IACzD,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAClD,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,QAAS,CAAC,CAAC;IACvD,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC;IACxE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3D,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC;IAC1D,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACzC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC;IAE1D,4CAA4C;IAC5C,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;IACzD,OAAO,CAAC,KAAK,CAAC,oCAAoC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAE1E,MAAM,eAAe,GAAG,mBAAmB,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5E,MAAM,WAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEtC,uBAAuB;IACvB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC;IACrC,IAAI,MAAM,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,GAAG,CAAC,KAAK,EAAE,6BAA6B,CAAC,CAAC;IAE1C,8BAA8B;IAC9B,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAS,CAAC,CAAC;IACzF,GAAG,CAAC,KAAK,EAAE,yBAAyB,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAEzD,iBAAiB;IACjB,eAAe,CAAC;QACd,GAAG,KAAK;QACR,WAAW,EAAE,MAAM,CAAC,YAAY;QAChC,YAAY,EAAE,MAAM,CAAC,aAAa;QAClC,SAAS,EAAE,MAAM,CAAC,UAAU;QAC5B,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS;QAChF,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;KAC1B,CAAC,CAAC;IAEH,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAA0B;IAC7D,MAAM,EAAE,cAAc,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAElD,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,KAAK,CAAC,cAAc,KAAK,cAAc,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,oCAAoC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,8CAA8C;IAC9C,MAAM,YAAY,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,SAAS,CAAC;IAE/E,IAAI,YAAY,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACzD,GAAG,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAC;QAElC,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,cAAc,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,QAAkB,CAAC,CAAC;QAE3F,eAAe,CAAC;YACd,GAAG,KAAK;YACR,WAAW,EAAE,MAAM,CAAC,YAAY;YAChC,YAAY,EAAE,MAAM,CAAC,aAAa,IAAI,KAAK,CAAC,YAAY;YACxD,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,SAAS;YAChF,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;SAC1B,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC,YAAY,CAAC;IAC7B,CAAC;IAED,OAAO,KAAK,CAAC,WAAW,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,MAAM;IACpB,gBAAgB,EAAE,CAAC;IACnB,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAM3B,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAEhC,OAAO;QACL,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW;QAC9B,QAAQ,EAAE,KAAK,EAAE,cAAc;QAC/B,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;QACnE,eAAe,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY;KACvC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Auth module exports
3
+ */
4
+ export { login, logout, getAccessToken, getAuthStatus, type AuthClientOptions } from "./client";
5
+ export { loadCredentials, saveCredentials, clearCredentials, getStoredDeviceId } from "./storage";
6
+ export { startCallbackServer, getCallbackUrl } from "./server";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Auth module exports
3
+ */
4
+ export { login, logout, getAccessToken, getAuthStatus } from "./client";
5
+ export { loadCredentials, saveCredentials, clearCredentials, getStoredDeviceId } from "./storage";
6
+ export { startCallbackServer, getCallbackUrl } from "./server";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,EAA0B,MAAM,UAAU,CAAC;AAChG,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Local HTTP callback server for OAuth redirect
3
+ *
4
+ * Starts a temporary HTTP server to receive the OAuth authorization code
5
+ * from the browser redirect after user authentication.
6
+ */
7
+ export interface CallbackResult {
8
+ code: string;
9
+ state?: string;
10
+ }
11
+ export interface CallbackServerOptions {
12
+ port?: number;
13
+ timeout?: number;
14
+ debug?: boolean;
15
+ }
16
+ /**
17
+ * Start a local HTTP server and wait for OAuth callback
18
+ *
19
+ * @returns Promise that resolves with the authorization code when received
20
+ */
21
+ export declare function startCallbackServer(options?: CallbackServerOptions): Promise<CallbackResult>;
22
+ /**
23
+ * Get the callback URL for OAuth configuration
24
+ */
25
+ export declare function getCallbackUrl(port?: number): string;
26
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/auth/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,cAAc,CAAC,CAsJhG;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,SAAe,GAAG,MAAM,CAE1D"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Local HTTP callback server for OAuth redirect
3
+ *
4
+ * Starts a temporary HTTP server to receive the OAuth authorization code
5
+ * from the browser redirect after user authentication.
6
+ */
7
+ import { createServer } from "node:http";
8
+ const DEFAULT_PORT = 19842;
9
+ const TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes
10
+ /**
11
+ * Start a local HTTP server and wait for OAuth callback
12
+ *
13
+ * @returns Promise that resolves with the authorization code when received
14
+ */
15
+ export function startCallbackServer(options = {}) {
16
+ const port = options.port || DEFAULT_PORT;
17
+ const timeout = options.timeout || TIMEOUT_MS;
18
+ const debug = options.debug || false;
19
+ const log = (message, ...args) => {
20
+ if (debug) {
21
+ console.error(`[callback-server] ${message}`, ...args);
22
+ }
23
+ };
24
+ return new Promise((resolve, reject) => {
25
+ let server = null;
26
+ let timeoutId = null;
27
+ const cleanup = () => {
28
+ if (timeoutId) {
29
+ clearTimeout(timeoutId);
30
+ timeoutId = null;
31
+ }
32
+ if (server) {
33
+ server.close();
34
+ server = null;
35
+ }
36
+ };
37
+ // Set up timeout
38
+ timeoutId = setTimeout(() => {
39
+ cleanup();
40
+ reject(new Error("OAuth callback timeout - no response received within 5 minutes"));
41
+ }, timeout);
42
+ server = createServer((req, res) => {
43
+ log("Received request:", req.url);
44
+ // Only handle GET /callback
45
+ if (!req.url?.startsWith("/callback")) {
46
+ res.writeHead(404);
47
+ res.end("Not Found");
48
+ return;
49
+ }
50
+ const url = new URL(req.url, `http://localhost:${port}`);
51
+ const code = url.searchParams.get("code");
52
+ const state = url.searchParams.get("state");
53
+ const error = url.searchParams.get("error");
54
+ const errorDescription = url.searchParams.get("error_description");
55
+ // Handle OAuth error
56
+ if (error) {
57
+ log("OAuth error:", error, errorDescription);
58
+ res.writeHead(400, { "Content-Type": "text/html" });
59
+ res.end(`
60
+ <!DOCTYPE html>
61
+ <html>
62
+ <head>
63
+ <title>Authentication Failed</title>
64
+ <style>
65
+ body { font-family: system-ui, sans-serif; padding: 40px; max-width: 600px; margin: 0 auto; }
66
+ h1 { color: #dc2626; }
67
+ .error { background: #fef2f2; border: 1px solid #fecaca; padding: 16px; border-radius: 8px; }
68
+ code { background: #f3f4f6; padding: 2px 6px; border-radius: 4px; }
69
+ </style>
70
+ </head>
71
+ <body>
72
+ <h1>Authentication Failed</h1>
73
+ <div class="error">
74
+ <p><strong>Error:</strong> <code>${error}</code></p>
75
+ ${errorDescription ? `<p>${errorDescription}</p>` : ""}
76
+ </div>
77
+ <p>You can close this window and try again.</p>
78
+ </body>
79
+ </html>
80
+ `);
81
+ cleanup();
82
+ reject(new Error(`OAuth error: ${error}${errorDescription ? ` - ${errorDescription}` : ""}`));
83
+ return;
84
+ }
85
+ // Handle missing code
86
+ if (!code) {
87
+ log("Missing authorization code");
88
+ res.writeHead(400, { "Content-Type": "text/html" });
89
+ res.end(`
90
+ <!DOCTYPE html>
91
+ <html>
92
+ <head>
93
+ <title>Authentication Failed</title>
94
+ <style>
95
+ body { font-family: system-ui, sans-serif; padding: 40px; max-width: 600px; margin: 0 auto; }
96
+ h1 { color: #dc2626; }
97
+ </style>
98
+ </head>
99
+ <body>
100
+ <h1>Authentication Failed</h1>
101
+ <p>No authorization code received. Please try again.</p>
102
+ </body>
103
+ </html>
104
+ `);
105
+ cleanup();
106
+ reject(new Error("No authorization code received"));
107
+ return;
108
+ }
109
+ // Success!
110
+ log("Received authorization code");
111
+ res.writeHead(200, { "Content-Type": "text/html" });
112
+ res.end(`
113
+ <!DOCTYPE html>
114
+ <html>
115
+ <head>
116
+ <title>Authentication Successful</title>
117
+ <style>
118
+ body { font-family: system-ui, sans-serif; padding: 40px; max-width: 600px; margin: 0 auto; }
119
+ h1 { color: #16a34a; }
120
+ .success { background: #f0fdf4; border: 1px solid #bbf7d0; padding: 16px; border-radius: 8px; }
121
+ </style>
122
+ </head>
123
+ <body>
124
+ <h1>Authentication Successful</h1>
125
+ <div class="success">
126
+ <p>You have been authenticated with Sonoma MCP Gateway.</p>
127
+ <p>You can close this window and return to your terminal.</p>
128
+ </div>
129
+ </body>
130
+ </html>
131
+ `);
132
+ cleanup();
133
+ resolve({ code, state: state || undefined });
134
+ });
135
+ server.on("error", (err) => {
136
+ cleanup();
137
+ if (err.code === "EADDRINUSE") {
138
+ reject(new Error(`Port ${port} is already in use. Is another gateway login in progress?`));
139
+ }
140
+ else {
141
+ reject(err);
142
+ }
143
+ });
144
+ server.listen(port, "127.0.0.1", () => {
145
+ log(`Callback server listening on http://localhost:${port}/callback`);
146
+ });
147
+ });
148
+ }
149
+ /**
150
+ * Get the callback URL for OAuth configuration
151
+ */
152
+ export function getCallbackUrl(port = DEFAULT_PORT) {
153
+ return `http://localhost:${port}/callback`;
154
+ }
155
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/auth/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Secure token storage for MCP Gateway OAuth credentials
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.
7
+ */
8
+ import type { OAuthTokens, OAuthClientInformationMixed } from "@modelcontextprotocol/sdk/shared/auth.js";
9
+ export interface StoredCredentials {
10
+ accessToken?: string;
11
+ refreshToken?: string;
12
+ expiresAt?: number;
13
+ tokenType?: string;
14
+ scope?: string;
15
+ clientId?: string;
16
+ clientSecret?: string;
17
+ clientSecretExpiresAt?: number;
18
+ codeVerifier?: string;
19
+ sonomaEndpoint?: string;
20
+ lastRefreshed?: number;
21
+ }
22
+ /**
23
+ * Load stored credentials from disk
24
+ */
25
+ export declare function loadCredentials(): StoredCredentials | null;
26
+ /**
27
+ * Save credentials to disk (encrypted)
28
+ */
29
+ export declare function saveCredentials(credentials: StoredCredentials): void;
30
+ /**
31
+ * Clear all stored credentials
32
+ */
33
+ export declare function clearCredentials(): void;
34
+ /**
35
+ * Convert stored credentials to MCP SDK OAuthTokens format
36
+ */
37
+ export declare function toOAuthTokens(creds: StoredCredentials): OAuthTokens | undefined;
38
+ /**
39
+ * Convert MCP SDK OAuthTokens to stored credentials format
40
+ */
41
+ export declare function fromOAuthTokens(tokens: OAuthTokens, existing?: StoredCredentials): StoredCredentials;
42
+ /**
43
+ * Convert stored credentials to MCP SDK client information format
44
+ */
45
+ export declare function toClientInformation(creds: StoredCredentials): OAuthClientInformationMixed | undefined;
46
+ /**
47
+ * Check if stored tokens are expired or about to expire
48
+ */
49
+ export declare function isTokenExpired(creds: StoredCredentials, bufferMs?: number): boolean;
50
+ /**
51
+ * Check if we have a valid refresh token
52
+ */
53
+ export declare function hasRefreshToken(creds: StoredCredentials): boolean;
54
+ /**
55
+ * Get device ID for telemetry
56
+ */
57
+ export declare function getStoredDeviceId(): string;
58
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,2BAA2B,EAAE,MAAM,0CAA0C,CAAC;AAYzG,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;AAgFD;;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"}