@metalabdesign/mcp-client 1.0.1
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/CHANGELOG.md +43 -0
- package/README.md +243 -0
- package/dist/bin/cli.d.ts +14 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +216 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/bin/metalab-mcp-config.d.ts +9 -0
- package/dist/bin/metalab-mcp-config.d.ts.map +1 -0
- package/dist/bin/metalab-mcp-config.js +224 -0
- package/dist/bin/metalab-mcp-config.js.map +1 -0
- package/dist/bin/metalab-mcp.d.ts +14 -0
- package/dist/bin/metalab-mcp.d.ts.map +1 -0
- package/dist/bin/metalab-mcp.js +242 -0
- package/dist/bin/metalab-mcp.js.map +1 -0
- package/dist/config/aws-sso.d.ts +21 -0
- package/dist/config/aws-sso.d.ts.map +1 -0
- package/dist/config/aws-sso.js +67 -0
- package/dist/config/aws-sso.js.map +1 -0
- package/dist/config/defaults.d.ts +14 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +20 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +3 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth.d.ts +34 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +401 -0
- package/dist/oauth.js.map +1 -0
- package/dist/proxy.d.ts +39 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +203 -0
- package/dist/proxy.js.map +1 -0
- package/dist/storage.d.ts +15 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +64 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.d.ts +78 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +40 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +42 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +89 -0
- package/dist/utils.js.map +1 -0
- package/package.json +51 -0
- package/src/bin/cli.ts +242 -0
- package/src/bin/metalab-mcp-config.ts +262 -0
- package/src/bin/metalab-mcp.ts +284 -0
- package/src/config/aws-sso.ts +78 -0
- package/src/config/defaults.ts +26 -0
- package/src/config/index.ts +8 -0
- package/src/index.ts +54 -0
- package/src/oauth.ts +540 -0
- package/src/proxy.ts +274 -0
- package/src/storage.ts +81 -0
- package/src/types.ts +79 -0
- package/src/utils.ts +115 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EACH,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,GACvB,MAAM,cAAc,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Local Proxy - Factory and exports
|
|
3
|
+
*/
|
|
4
|
+
import type { McpProxy } from './proxy.js';
|
|
5
|
+
export interface CreateProxyOptions {
|
|
6
|
+
/** Remote MCP server URL */
|
|
7
|
+
remoteUrl: string;
|
|
8
|
+
/** OAuth callback URL (port is extracted from this URL) */
|
|
9
|
+
callbackUrl: string;
|
|
10
|
+
/** Directory for token storage */
|
|
11
|
+
tokenStorageDir?: string;
|
|
12
|
+
/** Custom headers for remote requests */
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
/** Request timeout in ms (default: 30000) */
|
|
15
|
+
timeout?: number;
|
|
16
|
+
/** Auto-open browser for auth (default: true) */
|
|
17
|
+
openBrowser?: boolean;
|
|
18
|
+
/** Log level (default: 'info') */
|
|
19
|
+
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
20
|
+
/** Service-specific access tokens (e.g., { figma: "token", notion: "token" }) */
|
|
21
|
+
serviceTokens?: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Create and configure an MCP OAuth proxy
|
|
25
|
+
*/
|
|
26
|
+
export declare function createProxy(options: CreateProxyOptions): Promise<McpProxy>;
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,kBAAkB;IACjC,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/C,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACxC;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyBhF"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Local Proxy - Factory and exports
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Create and configure an MCP OAuth proxy
|
|
6
|
+
*/
|
|
7
|
+
export async function createProxy(options) {
|
|
8
|
+
const { ProxyConfigSchema } = await import('./types.js');
|
|
9
|
+
const { TokenStorage } = await import('./storage.js');
|
|
10
|
+
const { OAuthManager } = await import('./oauth.js');
|
|
11
|
+
const { McpProxy } = await import('./proxy.js');
|
|
12
|
+
const { StderrLogger } = await import('./utils.js');
|
|
13
|
+
// Validate and parse configuration
|
|
14
|
+
const config = ProxyConfigSchema.parse({
|
|
15
|
+
remoteUrl: options.remoteUrl,
|
|
16
|
+
callbackUrl: options.callbackUrl,
|
|
17
|
+
tokenStorageDir: options.tokenStorageDir,
|
|
18
|
+
headers: options.headers,
|
|
19
|
+
timeout: options.timeout ?? 30000,
|
|
20
|
+
openBrowser: options.openBrowser ?? true,
|
|
21
|
+
serviceTokens: options.serviceTokens,
|
|
22
|
+
});
|
|
23
|
+
// Create components
|
|
24
|
+
const logger = new StderrLogger(options.logLevel ?? 'info');
|
|
25
|
+
const storage = new TokenStorage(config.tokenStorageDir);
|
|
26
|
+
const oauthManager = new OAuthManager(config, storage, logger);
|
|
27
|
+
const proxy = new McpProxy(config, oauthManager, logger);
|
|
28
|
+
return proxy;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAuBH;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA2B;IAC3D,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IACzD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IACtD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IACpD,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IAChD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;IAEpD,mCAAmC;IACnC,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC;QACrC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,eAAe,EAAE,OAAO,CAAC,eAAe;QACxC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,KAAK;QACjC,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;QACxC,aAAa,EAAE,OAAO,CAAC,aAAa;KACrC,CAAC,CAAC;IAEH,oBAAoB;IACpB,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACzD,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC;IAEzD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/oauth.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 2.1 implementation with PKCE
|
|
3
|
+
* Handles metadata discovery, client registration, authorization flow, token management
|
|
4
|
+
*/
|
|
5
|
+
import type { Logger } from './utils.js';
|
|
6
|
+
import type { TokenStorage } from './storage.js';
|
|
7
|
+
import type { ProxyConfig } from './types.js';
|
|
8
|
+
export declare class OAuthManager {
|
|
9
|
+
private readonly config;
|
|
10
|
+
private readonly storage;
|
|
11
|
+
private readonly logger;
|
|
12
|
+
private clientRegistration;
|
|
13
|
+
private callbackServer;
|
|
14
|
+
private readonly callbackPort;
|
|
15
|
+
constructor(config: ProxyConfig, storage: TokenStorage, logger: Logger);
|
|
16
|
+
/**
|
|
17
|
+
* Get a valid access token, refreshing or re-authenticating as needed
|
|
18
|
+
*/
|
|
19
|
+
getAccessToken(): Promise<string>;
|
|
20
|
+
/**
|
|
21
|
+
* Clear stored tokens
|
|
22
|
+
*/
|
|
23
|
+
clearTokens(): Promise<void>;
|
|
24
|
+
private isTokenValid;
|
|
25
|
+
private ensureClientRegistration;
|
|
26
|
+
private discoverMetadata;
|
|
27
|
+
private parseMetadata;
|
|
28
|
+
private registerClient;
|
|
29
|
+
private performAuthorization;
|
|
30
|
+
private exchangeCode;
|
|
31
|
+
private refreshToken;
|
|
32
|
+
private parseTokenResponse;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAIV,WAAW,EACZ,MAAM,YAAY,CAAC;AAyLpB,qBAAa,YAAY;IAMrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPzB,OAAO,CAAC,kBAAkB,CAAmC;IAC7D,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAGnB,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,MAAM;IAQjC;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAwBvC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAKlC,OAAO,CAAC,YAAY;YAKN,wBAAwB;YA8BxB,gBAAgB;IA4B9B,OAAO,CAAC,aAAa;YAiCP,cAAc;YA+Cd,oBAAoB;YAyDpB,YAAY;YAyCZ,YAAY;IAuC1B,OAAO,CAAC,kBAAkB;CAS3B"}
|
package/dist/oauth.js
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 2.1 implementation with PKCE
|
|
3
|
+
* Handles metadata discovery, client registration, authorization flow, token management
|
|
4
|
+
*/
|
|
5
|
+
import { createServer } from 'node:http';
|
|
6
|
+
import { generateCodeChallenge, generateCodeVerifier, generateState, openBrowser } from './utils.js';
|
|
7
|
+
import { OAuthError } from './types.js';
|
|
8
|
+
// Constants
|
|
9
|
+
const AUTH_TIMEOUT_MS = 300000; // 5 minutes
|
|
10
|
+
const TOKEN_REFRESH_BUFFER_MS = 60000; // Refresh 1 minute before expiry
|
|
11
|
+
function createSuccessPage() {
|
|
12
|
+
return `<!DOCTYPE html>
|
|
13
|
+
<html>
|
|
14
|
+
<head>
|
|
15
|
+
<title>Authorization Complete</title>
|
|
16
|
+
<style>
|
|
17
|
+
body { font-family: system-ui, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #f5f5f5; }
|
|
18
|
+
.card { background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); text-align: center; max-width: 400px; }
|
|
19
|
+
h1 { color: #22c55e; margin-bottom: 0.5rem; }
|
|
20
|
+
p { color: #666; }
|
|
21
|
+
</style>
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
<div class="card">
|
|
25
|
+
<h1>✓ Authorization Complete</h1>
|
|
26
|
+
<p>You can close this window and return to your terminal.</p>
|
|
27
|
+
</div>
|
|
28
|
+
</body>
|
|
29
|
+
</html>`;
|
|
30
|
+
}
|
|
31
|
+
function createErrorPage(error) {
|
|
32
|
+
const escaped = error
|
|
33
|
+
.replace(/&/g, '&')
|
|
34
|
+
.replace(/</g, '<')
|
|
35
|
+
.replace(/>/g, '>')
|
|
36
|
+
.replace(/"/g, '"');
|
|
37
|
+
return `<!DOCTYPE html>
|
|
38
|
+
<html>
|
|
39
|
+
<head>
|
|
40
|
+
<title>Authorization Failed</title>
|
|
41
|
+
<style>
|
|
42
|
+
body { font-family: system-ui, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #f5f5f5; }
|
|
43
|
+
.card { background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); text-align: center; max-width: 400px; }
|
|
44
|
+
h1 { color: #ef4444; margin-bottom: 0.5rem; }
|
|
45
|
+
p { color: #666; }
|
|
46
|
+
.error { background: #fef2f2; padding: 1rem; border-radius: 4px; color: #991b1b; margin-top: 1rem; }
|
|
47
|
+
</style>
|
|
48
|
+
</head>
|
|
49
|
+
<body>
|
|
50
|
+
<div class="card">
|
|
51
|
+
<h1>✗ Authorization Failed</h1>
|
|
52
|
+
<p>Something went wrong during authorization.</p>
|
|
53
|
+
<div class="error">${escaped}</div>
|
|
54
|
+
</div>
|
|
55
|
+
</body>
|
|
56
|
+
</html>`;
|
|
57
|
+
}
|
|
58
|
+
class CallbackServer {
|
|
59
|
+
server = null;
|
|
60
|
+
pendingCallbacks = new Map();
|
|
61
|
+
callbackPath;
|
|
62
|
+
constructor(callbackPath) {
|
|
63
|
+
this.callbackPath = callbackPath;
|
|
64
|
+
}
|
|
65
|
+
async start(port) {
|
|
66
|
+
if (this.server)
|
|
67
|
+
return;
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
this.server = createServer((req, res) => this.handleRequest(req, res));
|
|
70
|
+
this.server.on('error', reject);
|
|
71
|
+
this.server.listen(port, '127.0.0.1', () => resolve());
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
handleRequest(req, res) {
|
|
75
|
+
const url = new URL(req.url ?? '/', `http://${req.headers.host}`);
|
|
76
|
+
if (url.pathname !== this.callbackPath) {
|
|
77
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
78
|
+
res.end('Not Found');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const code = url.searchParams.get('code');
|
|
82
|
+
const state = url.searchParams.get('state');
|
|
83
|
+
const error = url.searchParams.get('error');
|
|
84
|
+
const errorDescription = url.searchParams.get('error_description');
|
|
85
|
+
if (!state) {
|
|
86
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
87
|
+
res.end(createErrorPage('Missing state parameter'));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const pending = this.pendingCallbacks.get(state);
|
|
91
|
+
if (!pending) {
|
|
92
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
93
|
+
res.end(createErrorPage('Invalid or expired state'));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
clearTimeout(pending.timeout);
|
|
97
|
+
this.pendingCallbacks.delete(state);
|
|
98
|
+
if (error) {
|
|
99
|
+
const errorMessage = errorDescription ?? error;
|
|
100
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
101
|
+
res.end(createErrorPage(errorMessage));
|
|
102
|
+
pending.resolve({ error: errorMessage });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (!code) {
|
|
106
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
107
|
+
res.end(createErrorPage('Missing authorization code'));
|
|
108
|
+
pending.resolve({ error: 'Missing authorization code' });
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
112
|
+
res.end(createSuccessPage());
|
|
113
|
+
pending.resolve({ code });
|
|
114
|
+
}
|
|
115
|
+
waitForCallback(state, timeoutMs) {
|
|
116
|
+
return new Promise((resolve) => {
|
|
117
|
+
const timeout = setTimeout(() => {
|
|
118
|
+
this.pendingCallbacks.delete(state);
|
|
119
|
+
resolve({ error: 'Authorization timed out' });
|
|
120
|
+
}, timeoutMs);
|
|
121
|
+
this.pendingCallbacks.set(state, { resolve, timeout });
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
async stop() {
|
|
125
|
+
if (!this.server)
|
|
126
|
+
return;
|
|
127
|
+
for (const [state, pending] of this.pendingCallbacks) {
|
|
128
|
+
clearTimeout(pending.timeout);
|
|
129
|
+
pending.resolve({ error: 'Server stopped' });
|
|
130
|
+
this.pendingCallbacks.delete(state);
|
|
131
|
+
}
|
|
132
|
+
return new Promise((resolve) => {
|
|
133
|
+
this.server?.close(() => {
|
|
134
|
+
this.server = null;
|
|
135
|
+
resolve();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export class OAuthManager {
|
|
141
|
+
config;
|
|
142
|
+
storage;
|
|
143
|
+
logger;
|
|
144
|
+
clientRegistration = null;
|
|
145
|
+
callbackServer;
|
|
146
|
+
callbackPort;
|
|
147
|
+
constructor(config, storage, logger) {
|
|
148
|
+
this.config = config;
|
|
149
|
+
this.storage = storage;
|
|
150
|
+
this.logger = logger;
|
|
151
|
+
const callbackUrl = new URL(config.callbackUrl);
|
|
152
|
+
this.callbackServer = new CallbackServer(callbackUrl.pathname);
|
|
153
|
+
// Extract port from callback URL, default to 9876 if not specified
|
|
154
|
+
this.callbackPort = callbackUrl.port ? Number.parseInt(callbackUrl.port, 10) : 9876;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get a valid access token, refreshing or re-authenticating as needed
|
|
158
|
+
*/
|
|
159
|
+
async getAccessToken() {
|
|
160
|
+
let tokens = await this.storage.load(this.config.remoteUrl);
|
|
161
|
+
if (tokens) {
|
|
162
|
+
if (this.isTokenValid(tokens)) {
|
|
163
|
+
this.logger.debug('Using existing valid token');
|
|
164
|
+
return tokens.accessToken;
|
|
165
|
+
}
|
|
166
|
+
if (tokens.refreshToken) {
|
|
167
|
+
try {
|
|
168
|
+
tokens = await this.refreshToken(tokens.refreshToken);
|
|
169
|
+
this.logger.info('Token refreshed successfully');
|
|
170
|
+
return tokens.accessToken;
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
this.logger.warn('Token refresh failed, re-authenticating', error);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
tokens = await this.performAuthorization();
|
|
178
|
+
return tokens.accessToken;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Clear stored tokens
|
|
182
|
+
*/
|
|
183
|
+
async clearTokens() {
|
|
184
|
+
await this.storage.delete(this.config.remoteUrl);
|
|
185
|
+
this.logger.info('Tokens cleared');
|
|
186
|
+
}
|
|
187
|
+
isTokenValid(tokens) {
|
|
188
|
+
if (!tokens.expiresAt)
|
|
189
|
+
return true;
|
|
190
|
+
return tokens.expiresAt > Date.now() + TOKEN_REFRESH_BUFFER_MS;
|
|
191
|
+
}
|
|
192
|
+
async ensureClientRegistration() {
|
|
193
|
+
if (this.clientRegistration) {
|
|
194
|
+
return this.clientRegistration;
|
|
195
|
+
}
|
|
196
|
+
this.logger.info('Discovering OAuth metadata...');
|
|
197
|
+
const metadata = await this.discoverMetadata(this.config.remoteUrl);
|
|
198
|
+
if (!metadata) {
|
|
199
|
+
throw new OAuthError('Server does not support OAuth 2.1 (no metadata found)', 'NO_OAUTH_METADATA');
|
|
200
|
+
}
|
|
201
|
+
this.logger.debug('OAuth metadata discovered', {
|
|
202
|
+
issuer: metadata.issuer,
|
|
203
|
+
hasRegistration: !!metadata.registrationEndpoint
|
|
204
|
+
});
|
|
205
|
+
this.logger.info('Registering OAuth client...');
|
|
206
|
+
const client = await this.registerClient(metadata, this.config.callbackUrl);
|
|
207
|
+
this.logger.debug('Client registered', { clientId: client.clientId });
|
|
208
|
+
this.clientRegistration = { metadata, client };
|
|
209
|
+
return this.clientRegistration;
|
|
210
|
+
}
|
|
211
|
+
// ==================== OAuth Protocol Methods ====================
|
|
212
|
+
async discoverMetadata(serverUrl) {
|
|
213
|
+
const baseUrl = new URL(serverUrl);
|
|
214
|
+
const wellKnownPaths = [
|
|
215
|
+
'/.well-known/oauth-authorization-server',
|
|
216
|
+
'/.well-known/openid-configuration',
|
|
217
|
+
];
|
|
218
|
+
for (const path of wellKnownPaths) {
|
|
219
|
+
try {
|
|
220
|
+
const metadataUrl = new URL(path, baseUrl);
|
|
221
|
+
const response = await fetch(metadataUrl.toString(), {
|
|
222
|
+
method: 'GET',
|
|
223
|
+
headers: { 'Accept': 'application/json' },
|
|
224
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
225
|
+
});
|
|
226
|
+
if (response.ok) {
|
|
227
|
+
const data = await response.json();
|
|
228
|
+
return this.parseMetadata(data, baseUrl);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
// Continue to next path
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
parseMetadata(data, baseUrl) {
|
|
238
|
+
const getString = (key) => {
|
|
239
|
+
const value = data[key];
|
|
240
|
+
return typeof value === 'string' ? value : undefined;
|
|
241
|
+
};
|
|
242
|
+
const getStringArray = (key) => {
|
|
243
|
+
const value = data[key];
|
|
244
|
+
return Array.isArray(value) && value.every(v => typeof v === 'string') ? value : undefined;
|
|
245
|
+
};
|
|
246
|
+
const authorizationEndpoint = getString('authorization_endpoint');
|
|
247
|
+
const tokenEndpoint = getString('token_endpoint');
|
|
248
|
+
if (!authorizationEndpoint || !tokenEndpoint) {
|
|
249
|
+
throw new OAuthError('Invalid metadata: missing required endpoints', 'INVALID_METADATA');
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
issuer: getString('issuer') ?? baseUrl.origin,
|
|
253
|
+
authorizationEndpoint,
|
|
254
|
+
tokenEndpoint,
|
|
255
|
+
registrationEndpoint: getString('registration_endpoint'),
|
|
256
|
+
jwksUri: getString('jwks_uri'),
|
|
257
|
+
scopesSupported: getStringArray('scopes_supported'),
|
|
258
|
+
responseTypesSupported: getStringArray('response_types_supported') ?? ['code'],
|
|
259
|
+
codeChallengeMethodsSupported: getStringArray('code_challenge_methods_supported'),
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
async registerClient(metadata, redirectUri) {
|
|
263
|
+
if (!metadata.registrationEndpoint) {
|
|
264
|
+
throw new OAuthError('Server does not support dynamic client registration', 'REGISTRATION_NOT_SUPPORTED');
|
|
265
|
+
}
|
|
266
|
+
const registrationRequest = {
|
|
267
|
+
client_name: 'MCP OAuth Proxy',
|
|
268
|
+
redirect_uris: [redirectUri],
|
|
269
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
270
|
+
response_types: ['code'],
|
|
271
|
+
token_endpoint_auth_method: 'none',
|
|
272
|
+
};
|
|
273
|
+
const response = await fetch(metadata.registrationEndpoint, {
|
|
274
|
+
method: 'POST',
|
|
275
|
+
headers: {
|
|
276
|
+
'Content-Type': 'application/json',
|
|
277
|
+
'Accept': 'application/json',
|
|
278
|
+
},
|
|
279
|
+
body: JSON.stringify(registrationRequest),
|
|
280
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
281
|
+
});
|
|
282
|
+
if (!response.ok) {
|
|
283
|
+
const errorText = await response.text();
|
|
284
|
+
throw new OAuthError(`Client registration failed: ${errorText}`, 'REGISTRATION_FAILED', { status: response.status });
|
|
285
|
+
}
|
|
286
|
+
const data = await response.json();
|
|
287
|
+
return {
|
|
288
|
+
clientId: data.client_id,
|
|
289
|
+
clientSecret: data.client_secret,
|
|
290
|
+
redirectUri,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
async performAuthorization() {
|
|
294
|
+
const { metadata, client } = await this.ensureClientRegistration();
|
|
295
|
+
await this.callbackServer.start(this.callbackPort);
|
|
296
|
+
this.logger.debug('Callback server started on port', this.callbackPort);
|
|
297
|
+
try {
|
|
298
|
+
// Generate PKCE parameters
|
|
299
|
+
const state = generateState();
|
|
300
|
+
const codeVerifier = generateCodeVerifier();
|
|
301
|
+
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
302
|
+
// Build authorization URL
|
|
303
|
+
const authUrl = new URL(metadata.authorizationEndpoint);
|
|
304
|
+
authUrl.searchParams.set('response_type', 'code');
|
|
305
|
+
authUrl.searchParams.set('client_id', client.clientId);
|
|
306
|
+
authUrl.searchParams.set('redirect_uri', client.redirectUri);
|
|
307
|
+
authUrl.searchParams.set('state', state);
|
|
308
|
+
authUrl.searchParams.set('code_challenge', codeChallenge);
|
|
309
|
+
authUrl.searchParams.set('code_challenge_method', 'S256');
|
|
310
|
+
if (metadata.scopesSupported && metadata.scopesSupported.length > 0) {
|
|
311
|
+
authUrl.searchParams.set('scope', metadata.scopesSupported.join(' '));
|
|
312
|
+
}
|
|
313
|
+
this.logger.info('Authorization required. Opening browser...');
|
|
314
|
+
this.logger.info(`Authorization URL: ${authUrl.toString()}`);
|
|
315
|
+
if (this.config.openBrowser) {
|
|
316
|
+
await openBrowser(authUrl.toString());
|
|
317
|
+
}
|
|
318
|
+
// Wait for callback
|
|
319
|
+
this.logger.info('Waiting for authorization...');
|
|
320
|
+
const result = await this.callbackServer.waitForCallback(state, AUTH_TIMEOUT_MS);
|
|
321
|
+
if ('error' in result) {
|
|
322
|
+
throw new OAuthError(`Authorization failed: ${result.error}`, 'AUTHORIZATION_FAILED');
|
|
323
|
+
}
|
|
324
|
+
// Exchange code for tokens
|
|
325
|
+
this.logger.debug('Exchanging code for tokens...');
|
|
326
|
+
const tokens = await this.exchangeCode(metadata, client, result.code, codeVerifier);
|
|
327
|
+
await this.storage.save(this.config.remoteUrl, tokens);
|
|
328
|
+
this.logger.info('Authorization complete, tokens saved');
|
|
329
|
+
return tokens;
|
|
330
|
+
}
|
|
331
|
+
finally {
|
|
332
|
+
await this.callbackServer.stop();
|
|
333
|
+
this.logger.debug('Callback server stopped');
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
async exchangeCode(metadata, client, code, codeVerifier) {
|
|
337
|
+
const body = new URLSearchParams({
|
|
338
|
+
grant_type: 'authorization_code',
|
|
339
|
+
code,
|
|
340
|
+
redirect_uri: client.redirectUri,
|
|
341
|
+
client_id: client.clientId,
|
|
342
|
+
code_verifier: codeVerifier,
|
|
343
|
+
});
|
|
344
|
+
if (client.clientSecret) {
|
|
345
|
+
body.set('client_secret', client.clientSecret);
|
|
346
|
+
}
|
|
347
|
+
const response = await fetch(metadata.tokenEndpoint, {
|
|
348
|
+
method: 'POST',
|
|
349
|
+
headers: {
|
|
350
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
351
|
+
'Accept': 'application/json',
|
|
352
|
+
},
|
|
353
|
+
body: body.toString(),
|
|
354
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
355
|
+
});
|
|
356
|
+
if (!response.ok) {
|
|
357
|
+
const errorText = await response.text();
|
|
358
|
+
throw new OAuthError(`Token exchange failed: ${errorText}`, 'TOKEN_EXCHANGE_FAILED', { status: response.status });
|
|
359
|
+
}
|
|
360
|
+
const data = await response.json();
|
|
361
|
+
return this.parseTokenResponse(data);
|
|
362
|
+
}
|
|
363
|
+
async refreshToken(refreshToken) {
|
|
364
|
+
const { metadata, client } = await this.ensureClientRegistration();
|
|
365
|
+
const body = new URLSearchParams({
|
|
366
|
+
grant_type: 'refresh_token',
|
|
367
|
+
refresh_token: refreshToken,
|
|
368
|
+
client_id: client.clientId,
|
|
369
|
+
});
|
|
370
|
+
if (client.clientSecret) {
|
|
371
|
+
body.set('client_secret', client.clientSecret);
|
|
372
|
+
}
|
|
373
|
+
const response = await fetch(metadata.tokenEndpoint, {
|
|
374
|
+
method: 'POST',
|
|
375
|
+
headers: {
|
|
376
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
377
|
+
'Accept': 'application/json',
|
|
378
|
+
},
|
|
379
|
+
body: body.toString(),
|
|
380
|
+
signal: AbortSignal.timeout(this.config.timeout),
|
|
381
|
+
});
|
|
382
|
+
if (!response.ok) {
|
|
383
|
+
const errorText = await response.text();
|
|
384
|
+
throw new OAuthError(`Token refresh failed: ${errorText}`, 'TOKEN_REFRESH_FAILED', { status: response.status });
|
|
385
|
+
}
|
|
386
|
+
const data = await response.json();
|
|
387
|
+
const tokens = this.parseTokenResponse(data);
|
|
388
|
+
await this.storage.save(this.config.remoteUrl, tokens);
|
|
389
|
+
return tokens;
|
|
390
|
+
}
|
|
391
|
+
parseTokenResponse(data) {
|
|
392
|
+
return {
|
|
393
|
+
accessToken: data.access_token,
|
|
394
|
+
tokenType: data.token_type,
|
|
395
|
+
refreshToken: data.refresh_token,
|
|
396
|
+
expiresAt: data.expires_in ? Date.now() + data.expires_in * 1000 : undefined,
|
|
397
|
+
scope: data.scope,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
|
package/dist/proxy.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Proxy
|
|
3
|
+
* Bridges a local stdio MCP server to a remote OAuth-protected MCP server
|
|
4
|
+
*/
|
|
5
|
+
import type { Logger } from './utils.js';
|
|
6
|
+
import type { ProxyConfig } from './types.js';
|
|
7
|
+
import type { OAuthManager } from './oauth.js';
|
|
8
|
+
export declare class McpProxy {
|
|
9
|
+
private readonly config;
|
|
10
|
+
private readonly oauthManager;
|
|
11
|
+
private readonly logger;
|
|
12
|
+
private readonly server;
|
|
13
|
+
private client;
|
|
14
|
+
private transport;
|
|
15
|
+
private capabilities;
|
|
16
|
+
private isConnected;
|
|
17
|
+
private connectionPromise;
|
|
18
|
+
constructor(config: ProxyConfig, oauthManager: OAuthManager, logger: Logger);
|
|
19
|
+
/**
|
|
20
|
+
* Start the proxy using stdio transport
|
|
21
|
+
*/
|
|
22
|
+
start(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Disconnect from remote server
|
|
25
|
+
*/
|
|
26
|
+
disconnect(): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Ensure we're connected to the remote server (lazy initialization)
|
|
29
|
+
*/
|
|
30
|
+
private ensureConnected;
|
|
31
|
+
private connect;
|
|
32
|
+
/**
|
|
33
|
+
* Build service-specific token headers (X-[Service]-Token format)
|
|
34
|
+
*/
|
|
35
|
+
private buildServiceTokenHeaders;
|
|
36
|
+
private discoverCapabilities;
|
|
37
|
+
private setupProxyHandlers;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAwBH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAQ/C,qBAAa,QAAQ;IAajB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAdzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,YAAY,CAIlB;IACF,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAA8B;gBAGpC,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,MAAM;IAmBjC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC;;OAEG;YACW,eAAe;YAiBf,OAAO;IAqCrB;;OAEG;IACH,OAAO,CAAC,wBAAwB;YAmBlB,oBAAoB;IAiBlC,OAAO,CAAC,kBAAkB;CAiF3B"}
|