@olane/o-mcp 0.6.13 → 0.7.2

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 (48) hide show
  1. package/dist/src/mcp-bridge.tool.d.ts +7 -4
  2. package/dist/src/mcp-bridge.tool.d.ts.map +1 -1
  3. package/dist/src/mcp-bridge.tool.js +17 -12
  4. package/dist/src/mcp.tool.d.ts +12 -5
  5. package/dist/src/mcp.tool.d.ts.map +1 -1
  6. package/dist/src/mcp.tool.js +8 -10
  7. package/dist/src/methods/mcp-bridge.methods.d.ts.map +1 -1
  8. package/dist/src/methods/mcp-bridge.methods.js +16 -2
  9. package/dist/src/o-client.mcp.d.ts.map +1 -1
  10. package/dist/src/oauth/index.d.ts +8 -0
  11. package/dist/src/oauth/index.d.ts.map +1 -0
  12. package/dist/src/oauth/index.js +7 -0
  13. package/dist/src/oauth/interfaces/client-metadata.interface.d.ts +17 -0
  14. package/dist/src/oauth/interfaces/client-metadata.interface.d.ts.map +1 -0
  15. package/dist/src/oauth/interfaces/client-metadata.interface.js +1 -0
  16. package/dist/src/oauth/interfaces/index.d.ts +4 -0
  17. package/dist/src/oauth/interfaces/index.d.ts.map +1 -0
  18. package/dist/src/oauth/interfaces/index.js +3 -0
  19. package/dist/src/oauth/interfaces/oauth-client-info.interface.d.ts +12 -0
  20. package/dist/src/oauth/interfaces/oauth-client-info.interface.d.ts.map +1 -0
  21. package/dist/src/oauth/interfaces/oauth-client-info.interface.js +1 -0
  22. package/dist/src/oauth/interfaces/oauth-tokens.interface.d.ts +10 -0
  23. package/dist/src/oauth/interfaces/oauth-tokens.interface.d.ts.map +1 -0
  24. package/dist/src/oauth/interfaces/oauth-tokens.interface.js +1 -0
  25. package/dist/src/oauth/mcp-dynamic-registration.d.ts +33 -0
  26. package/dist/src/oauth/mcp-dynamic-registration.d.ts.map +1 -0
  27. package/dist/src/oauth/mcp-dynamic-registration.js +107 -0
  28. package/dist/src/oauth/mcp-oauth-callback-server.d.ts +51 -0
  29. package/dist/src/oauth/mcp-oauth-callback-server.d.ts.map +1 -0
  30. package/dist/src/oauth/mcp-oauth-callback-server.js +179 -0
  31. package/dist/src/oauth/mcp-oauth-manager.d.ts +61 -0
  32. package/dist/src/oauth/mcp-oauth-manager.d.ts.map +1 -0
  33. package/dist/src/oauth/mcp-oauth-manager.js +289 -0
  34. package/dist/src/oauth/mcp-oauth-storage.d.ts +60 -0
  35. package/dist/src/oauth/mcp-oauth-storage.d.ts.map +1 -0
  36. package/dist/src/oauth/mcp-oauth-storage.js +146 -0
  37. package/dist/src/oauth/methods/mcp-oauth.methods.d.ts +5 -0
  38. package/dist/src/oauth/methods/mcp-oauth.methods.d.ts.map +1 -0
  39. package/dist/src/oauth/methods/mcp-oauth.methods.js +99 -0
  40. package/dist/src/oauth/oauth-aware-transport.d.ts +50 -0
  41. package/dist/src/oauth/oauth-aware-transport.d.ts.map +1 -0
  42. package/dist/src/oauth/oauth-aware-transport.js +120 -0
  43. package/dist/test/benchmark.spec.d.ts +0 -1
  44. package/dist/test/benchmark.spec.js +49 -48
  45. package/dist/test/tools.spec.d.ts +2 -0
  46. package/dist/test/tools.spec.d.ts.map +1 -0
  47. package/dist/test/tools.spec.js +13 -0
  48. package/package.json +20 -14
@@ -0,0 +1,179 @@
1
+ import express from 'express';
2
+ import { EventEmitter } from 'events';
3
+ /**
4
+ * HTTP server for handling OAuth callbacks
5
+ *
6
+ * This server runs locally to receive the OAuth redirect after user authorization.
7
+ * It automatically shuts down after receiving the callback.
8
+ */
9
+ export class McpOAuthCallbackServer {
10
+ constructor(port) {
11
+ this.server = null;
12
+ this.port = 3334;
13
+ this.callbackResult = null;
14
+ if (port) {
15
+ this.port = port;
16
+ }
17
+ this.app = express();
18
+ this.events = new EventEmitter();
19
+ this.setupRoutes();
20
+ }
21
+ /**
22
+ * Setup Express routes
23
+ */
24
+ setupRoutes() {
25
+ // OAuth callback endpoint
26
+ this.app.get('/oauth/callback', (req, res) => {
27
+ const { code, state, error, error_description } = req.query;
28
+ if (error) {
29
+ this.callbackResult = {
30
+ code: '',
31
+ error: error,
32
+ error_description: error_description,
33
+ };
34
+ res.send(`
35
+ <html>
36
+ <head><title>OAuth Error</title></head>
37
+ <body style="font-family: Arial, sans-serif; padding: 40px; text-align: center;">
38
+ <h1 style="color: #d32f2f;">Authentication Failed</h1>
39
+ <p style="color: #666;">Error: ${error}</p>
40
+ <p style="color: #666;">${error_description || ''}</p>
41
+ <p style="margin-top: 40px; color: #999;">You can close this window.</p>
42
+ </body>
43
+ </html>
44
+ `);
45
+ }
46
+ else if (code) {
47
+ this.callbackResult = {
48
+ code: code,
49
+ state: state,
50
+ };
51
+ res.send(`
52
+ <html>
53
+ <head><title>OAuth Success</title></head>
54
+ <body style="font-family: Arial, sans-serif; padding: 40px; text-align: center;">
55
+ <h1 style="color: #4caf50;">✓ Authentication Successful</h1>
56
+ <p style="color: #666;">You have successfully authenticated with the MCP server.</p>
57
+ <p style="margin-top: 40px; color: #999;">You can close this window.</p>
58
+ <script>
59
+ setTimeout(() => window.close(), 3000);
60
+ </script>
61
+ </body>
62
+ </html>
63
+ `);
64
+ }
65
+ else {
66
+ this.callbackResult = {
67
+ code: '',
68
+ error: 'invalid_request',
69
+ error_description: 'No code or error in callback',
70
+ };
71
+ res.status(400).send(`
72
+ <html>
73
+ <head><title>OAuth Error</title></head>
74
+ <body style="font-family: Arial, sans-serif; padding: 40px; text-align: center;">
75
+ <h1 style="color: #d32f2f;">Invalid Callback</h1>
76
+ <p style="color: #666;">The OAuth callback was missing required parameters.</p>
77
+ <p style="margin-top: 40px; color: #999;">You can close this window.</p>
78
+ </body>
79
+ </html>
80
+ `);
81
+ }
82
+ // Emit callback event
83
+ this.events.emit('callback', this.callbackResult);
84
+ });
85
+ // Health check endpoint
86
+ this.app.get('/health', (req, res) => {
87
+ res.json({ status: 'ok', port: this.port });
88
+ });
89
+ }
90
+ /**
91
+ * Start the callback server
92
+ */
93
+ async start(port) {
94
+ if (port) {
95
+ this.port = port;
96
+ }
97
+ if (this.server) {
98
+ throw new Error('Callback server is already running');
99
+ }
100
+ return new Promise((resolve, reject) => {
101
+ try {
102
+ this.server = this.app.listen(this.port, () => {
103
+ console.log(`OAuth callback server listening on http://localhost:${this.port}`);
104
+ resolve();
105
+ });
106
+ this.server.on('error', (error) => {
107
+ if (error.code === 'EADDRINUSE') {
108
+ reject(new Error(`Port ${this.port} is already in use. Please close other OAuth flows or choose a different port.`));
109
+ }
110
+ else {
111
+ reject(error);
112
+ }
113
+ });
114
+ }
115
+ catch (error) {
116
+ reject(error);
117
+ }
118
+ });
119
+ }
120
+ /**
121
+ * Stop the callback server
122
+ */
123
+ async stop() {
124
+ if (!this.server) {
125
+ return;
126
+ }
127
+ return new Promise((resolve, reject) => {
128
+ this.server.close((error) => {
129
+ if (error) {
130
+ reject(error);
131
+ }
132
+ else {
133
+ this.server = null;
134
+ this.callbackResult = null;
135
+ resolve();
136
+ }
137
+ });
138
+ });
139
+ }
140
+ /**
141
+ * Wait for OAuth callback
142
+ * @param timeout Timeout in milliseconds (default: 5 minutes)
143
+ */
144
+ async waitForCallback(timeout = 300000) {
145
+ return new Promise((resolve, reject) => {
146
+ const timeoutId = setTimeout(() => {
147
+ this.events.removeAllListeners('callback');
148
+ reject(new Error('OAuth callback timeout. User did not complete authentication.'));
149
+ }, timeout);
150
+ this.events.once('callback', (result) => {
151
+ clearTimeout(timeoutId);
152
+ if (result.error) {
153
+ reject(new Error(`OAuth error: ${result.error}. ${result.error_description || ''}`));
154
+ }
155
+ else {
156
+ resolve(result);
157
+ }
158
+ });
159
+ });
160
+ }
161
+ /**
162
+ * Get the callback URL
163
+ */
164
+ getCallbackUrl() {
165
+ return `http://localhost:${this.port}/oauth/callback`;
166
+ }
167
+ /**
168
+ * Get the current port
169
+ */
170
+ getPort() {
171
+ return this.port;
172
+ }
173
+ /**
174
+ * Check if server is running
175
+ */
176
+ isRunning() {
177
+ return this.server !== null;
178
+ }
179
+ }
@@ -0,0 +1,61 @@
1
+ import { oRequest } from '@olane/o-core';
2
+ import { oLaneTool } from '@olane/o-lane';
3
+ import { oNodeToolConfig } from '@olane/o-node';
4
+ import { ToolResult } from '@olane/o-tool';
5
+ /**
6
+ * MCP OAuth Manager Tool
7
+ *
8
+ * Coordinates OAuth authentication flows for MCP servers:
9
+ * - Dynamic client registration (RFC 7591)
10
+ * - PKCE authorization flow
11
+ * - Token storage and refresh
12
+ * - Callback server management
13
+ */
14
+ export declare class McpOAuthManager extends oLaneTool {
15
+ private storage;
16
+ private callbackServer;
17
+ private dynamicRegistration;
18
+ private oauthToolAddress;
19
+ constructor(config: oNodeToolConfig);
20
+ /**
21
+ * Authenticate with an OAuth-protected MCP server
22
+ */
23
+ _tool_authenticate_server(request: oRequest): Promise<ToolResult>;
24
+ /**
25
+ * Refresh OAuth tokens for an MCP server
26
+ */
27
+ _tool_refresh_tokens(request: oRequest): Promise<ToolResult>;
28
+ /**
29
+ * Check OAuth token status for an MCP server
30
+ */
31
+ _tool_check_tokens(request: oRequest): Promise<ToolResult>;
32
+ /**
33
+ * Clear OAuth tokens and client info for an MCP server
34
+ */
35
+ _tool_clear_tokens(request: oRequest): Promise<ToolResult>;
36
+ /**
37
+ * List all authenticated MCP servers
38
+ */
39
+ _tool_list_authenticated_servers(request: oRequest): Promise<ToolResult>;
40
+ /**
41
+ * Public method for refreshing tokens (used by transport)
42
+ */
43
+ refreshTokens(serverUrl: string): Promise<void>;
44
+ /**
45
+ * Get service name for OAuth tool
46
+ */
47
+ private getServiceName;
48
+ /**
49
+ * Hash server URL for service name
50
+ */
51
+ private hashServerUrl;
52
+ /**
53
+ * Launch browser for OAuth authorization
54
+ */
55
+ private launchBrowser;
56
+ /**
57
+ * Cleanup on shutdown
58
+ */
59
+ stop(): Promise<void>;
60
+ }
61
+ //# sourceMappingURL=mcp-oauth-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-oauth-manager.d.ts","sourceRoot":"","sources":["../../../src/oauth/mcp-oauth-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAO3C;;;;;;;;GAQG;AACH,qBAAa,eAAgB,SAAQ,SAAS;IAC5C,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,cAAc,CAAuC;IAC7D,OAAO,CAAC,mBAAmB,CAAyB;IACpD,OAAO,CAAC,gBAAgB,CAAW;gBAEvB,MAAM,EAAE,eAAe;IAkBnC;;OAEG;IACG,yBAAyB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAyLvE;;OAEG;IACG,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAwClE;;OAEG;IACG,kBAAkB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAehE;;OAEG;IACG,kBAAkB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAahE;;OAEG;IACG,gCAAgC,CACpC,OAAO,EAAE,QAAQ,GAChB,OAAO,CAAC,UAAU,CAAC;IAWtB;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAarD;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;OAEG;YACW,aAAa;IAY3B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAO5B"}
@@ -0,0 +1,289 @@
1
+ import { oAddress } from '@olane/o-core';
2
+ import { oLaneTool } from '@olane/o-lane';
3
+ import { McpOAuthStorage } from './mcp-oauth-storage.js';
4
+ import { McpOAuthCallbackServer } from './mcp-oauth-callback-server.js';
5
+ import { McpDynamicRegistration } from './mcp-dynamic-registration.js';
6
+ import { MCP_OAUTH_METHODS } from './methods/mcp-oauth.methods.js';
7
+ /**
8
+ * MCP OAuth Manager Tool
9
+ *
10
+ * Coordinates OAuth authentication flows for MCP servers:
11
+ * - Dynamic client registration (RFC 7591)
12
+ * - PKCE authorization flow
13
+ * - Token storage and refresh
14
+ * - Callback server management
15
+ */
16
+ export class McpOAuthManager extends oLaneTool {
17
+ constructor(config) {
18
+ super({
19
+ ...config,
20
+ address: new oAddress('o://mcp/oauth'),
21
+ description: 'OAuth authentication manager for MCP servers',
22
+ methods: MCP_OAUTH_METHODS,
23
+ });
24
+ this.callbackServer = null;
25
+ // Initialize storage adapter with o://secure
26
+ this.storage = new McpOAuthStorage({
27
+ storageAddress: new oAddress('o://secure'),
28
+ useFunction: this.use.bind(this),
29
+ });
30
+ this.dynamicRegistration = new McpDynamicRegistration();
31
+ this.oauthToolAddress = new oAddress('o://oauth');
32
+ }
33
+ /**
34
+ * Authenticate with an OAuth-protected MCP server
35
+ */
36
+ async _tool_authenticate_server(request) {
37
+ const { serverUrl, clientName, scope, staticClientInfo, useDynamicRegistration = true, callbackPort = 3334, } = request.params;
38
+ try {
39
+ this.logger.info(`Starting OAuth authentication for ${serverUrl}`);
40
+ // 1. Check if we already have valid tokens
41
+ const existingTokens = await this.storage.getTokens(serverUrl);
42
+ if (existingTokens &&
43
+ !(await this.storage.areTokensExpired(serverUrl))) {
44
+ this.logger.info(`Already authenticated with ${serverUrl}`);
45
+ return {
46
+ success: true,
47
+ message: 'Already authenticated',
48
+ hasTokens: true,
49
+ };
50
+ }
51
+ // 2. Get or register OAuth client
52
+ let clientInfo;
53
+ if (staticClientInfo) {
54
+ // Use provided static client credentials
55
+ this.logger.info(`Using static OAuth client info for ${serverUrl}`);
56
+ const staticInfo = staticClientInfo;
57
+ // Discover endpoints if not provided
58
+ const endpoints = await this.dynamicRegistration.discoverEndpoints(serverUrl);
59
+ clientInfo = {
60
+ client_id: staticInfo.client_id,
61
+ client_secret: staticInfo.client_secret,
62
+ authorization_endpoint: staticInfo.authorization_endpoint ||
63
+ endpoints.authorization_endpoint ||
64
+ '',
65
+ token_endpoint: staticInfo.token_endpoint || endpoints.token_endpoint || '',
66
+ scope: (staticInfo.scope ||
67
+ scope ||
68
+ 'openid profile email'),
69
+ };
70
+ if (!clientInfo.authorization_endpoint || !clientInfo.token_endpoint) {
71
+ throw new Error(`Could not determine OAuth endpoints for ${serverUrl}. Please provide authorization_endpoint and token_endpoint in staticClientInfo.`);
72
+ }
73
+ }
74
+ else if (useDynamicRegistration) {
75
+ // Dynamic client registration
76
+ this.logger.info(`Attempting dynamic client registration for ${serverUrl}`);
77
+ const existingClientInfo = await this.storage.getClientInfo(serverUrl);
78
+ // Start callback server to get redirect URI
79
+ this.callbackServer = new McpOAuthCallbackServer(callbackPort);
80
+ await this.callbackServer.start();
81
+ const redirectUri = this.callbackServer.getCallbackUrl();
82
+ clientInfo = await this.dynamicRegistration.getOrRegisterClient(serverUrl, clientName || 'Olane MCP Client', redirectUri, existingClientInfo, scope);
83
+ // Save client info to encrypted storage
84
+ await this.storage.saveClientInfo(serverUrl, clientInfo);
85
+ this.logger.info(`Client registered successfully for ${serverUrl}`);
86
+ }
87
+ else {
88
+ throw new Error(`No OAuth client credentials provided for ${serverUrl}. Please provide staticClientInfo or enable useDynamicRegistration.`);
89
+ }
90
+ // 3. Start callback server if not already started
91
+ if (!this.callbackServer) {
92
+ this.callbackServer = new McpOAuthCallbackServer(callbackPort);
93
+ await this.callbackServer.start();
94
+ }
95
+ const redirectUri = this.callbackServer.getCallbackUrl();
96
+ // 4. Configure OAuth via existing OAuthTool
97
+ const serviceName = this.getServiceName(serverUrl);
98
+ await this.use(this.oauthToolAddress, {
99
+ method: 'configure',
100
+ params: {
101
+ serviceName,
102
+ clientId: clientInfo.client_id,
103
+ clientSecret: clientInfo.client_secret,
104
+ redirectUri,
105
+ authorizationUrl: clientInfo.authorization_endpoint,
106
+ tokenUrl: clientInfo.token_endpoint,
107
+ scope: clientInfo.scope || scope || 'openid profile email',
108
+ },
109
+ });
110
+ // 5. Get authorization URL (with PKCE)
111
+ const authUrlResponse = await this.use(this.oauthToolAddress, {
112
+ method: 'getAuthorizationUrl',
113
+ params: {
114
+ serviceName,
115
+ scope: clientInfo.scope || scope,
116
+ },
117
+ });
118
+ const authUrl = authUrlResponse.result?.data?.authorizationUrl ||
119
+ authUrlResponse.result?.authorizationUrl;
120
+ this.logger.info(`Authorization URL: ${authUrl}`);
121
+ // 6. Launch browser
122
+ this.logger.info('Opening browser for user authorization...');
123
+ await this.launchBrowser(authUrl);
124
+ // 7. Wait for callback
125
+ this.logger.info('Waiting for OAuth callback...');
126
+ const { code, state } = await this.callbackServer.waitForCallback(300000); // 5 min timeout
127
+ this.logger.info('OAuth callback received');
128
+ // 8. Exchange code for tokens
129
+ const tokenResponse = await this.use(this.oauthToolAddress, {
130
+ method: 'exchangeCode',
131
+ params: {
132
+ serviceName,
133
+ code,
134
+ state,
135
+ },
136
+ });
137
+ const tokens = tokenResponse.result?.data?.tokens ||
138
+ tokenResponse.result?.tokens;
139
+ // 9. Persist tokens to encrypted storage
140
+ await this.storage.saveTokens(serverUrl, tokens);
141
+ // 10. Stop callback server
142
+ await this.callbackServer.stop();
143
+ this.callbackServer = null;
144
+ this.logger.info(`OAuth authentication successful for ${serverUrl}`);
145
+ return {
146
+ success: true,
147
+ message: 'OAuth authentication successful',
148
+ serverUrl,
149
+ hasTokens: true,
150
+ };
151
+ }
152
+ catch (error) {
153
+ // Clean up callback server on error
154
+ if (this.callbackServer) {
155
+ await this.callbackServer.stop().catch(() => { });
156
+ this.callbackServer = null;
157
+ }
158
+ this.logger.error(`OAuth authentication failed: ${error.message}`);
159
+ throw new Error(`OAuth authentication failed: ${error.message}`);
160
+ }
161
+ }
162
+ /**
163
+ * Refresh OAuth tokens for an MCP server
164
+ */
165
+ async _tool_refresh_tokens(request) {
166
+ const { serverUrl } = request.params;
167
+ try {
168
+ this.logger.info(`Refreshing OAuth tokens for ${serverUrl}`);
169
+ const tokens = await this.storage.getTokens(serverUrl);
170
+ if (!tokens?.refresh_token) {
171
+ throw new Error('No refresh token available');
172
+ }
173
+ const serviceName = this.getServiceName(serverUrl);
174
+ const refreshResponse = await this.use(this.oauthToolAddress, {
175
+ method: 'refreshToken',
176
+ params: {
177
+ serviceName,
178
+ refreshToken: tokens.refresh_token,
179
+ },
180
+ });
181
+ const newTokens = refreshResponse.result?.data?.tokens ||
182
+ refreshResponse.result?.tokens;
183
+ // Save new tokens to encrypted storage
184
+ await this.storage.saveTokens(serverUrl, newTokens);
185
+ this.logger.info(`Tokens refreshed successfully for ${serverUrl}`);
186
+ return {
187
+ success: true,
188
+ message: 'Tokens refreshed successfully',
189
+ };
190
+ }
191
+ catch (error) {
192
+ this.logger.error(`Token refresh failed: ${error.message}`);
193
+ throw new Error(`Token refresh failed: ${error.message}`);
194
+ }
195
+ }
196
+ /**
197
+ * Check OAuth token status for an MCP server
198
+ */
199
+ async _tool_check_tokens(request) {
200
+ const { serverUrl } = request.params;
201
+ const tokens = await this.storage.getTokens(serverUrl);
202
+ const isExpired = await this.storage.areTokensExpired(serverUrl);
203
+ return {
204
+ success: true,
205
+ hasTokens: !!tokens,
206
+ isExpired: tokens ? isExpired : null,
207
+ expiresAt: tokens?.expires_at || null,
208
+ hasRefreshToken: !!tokens?.refresh_token,
209
+ };
210
+ }
211
+ /**
212
+ * Clear OAuth tokens and client info for an MCP server
213
+ */
214
+ async _tool_clear_tokens(request) {
215
+ const { serverUrl } = request.params;
216
+ await this.storage.clearServer(serverUrl);
217
+ this.logger.info(`Cleared OAuth data for ${serverUrl}`);
218
+ return {
219
+ success: true,
220
+ message: `Cleared OAuth data for ${serverUrl}`,
221
+ };
222
+ }
223
+ /**
224
+ * List all authenticated MCP servers
225
+ */
226
+ async _tool_list_authenticated_servers(request) {
227
+ // This would require maintaining an index of servers
228
+ // For now, return empty list
229
+ // TODO: Implement server list tracking in storage
230
+ return {
231
+ success: true,
232
+ servers: [],
233
+ message: 'Server list tracking not yet implemented',
234
+ };
235
+ }
236
+ /**
237
+ * Public method for refreshing tokens (used by transport)
238
+ */
239
+ async refreshTokens(serverUrl) {
240
+ // await this._tool_refresh_tokens({
241
+ // jsonrpc: '2.0',
242
+ // method: 'refresh_tokens',
243
+ // id: Date.now().toString(),
244
+ // params: { serverUrl },
245
+ // state: {},
246
+ // peerId: this.peerId,
247
+ // source: this.address!,
248
+ // target: this.address!,
249
+ // } as oRequest);
250
+ }
251
+ /**
252
+ * Get service name for OAuth tool
253
+ */
254
+ getServiceName(serverUrl) {
255
+ return `mcp_${this.hashServerUrl(serverUrl)}`;
256
+ }
257
+ /**
258
+ * Hash server URL for service name
259
+ */
260
+ hashServerUrl(url) {
261
+ return Buffer.from(url)
262
+ .toString('base64')
263
+ .replace(/[^a-zA-Z0-9]/g, '_')
264
+ .substring(0, 16);
265
+ }
266
+ /**
267
+ * Launch browser for OAuth authorization
268
+ */
269
+ async launchBrowser(url) {
270
+ try {
271
+ const open = (await import('open')).default;
272
+ await open(url);
273
+ }
274
+ catch (error) {
275
+ this.logger.warn(`Could not automatically open browser: ${error.message}`);
276
+ this.logger.info(`Please open this URL in your browser: ${url}`);
277
+ }
278
+ }
279
+ /**
280
+ * Cleanup on shutdown
281
+ */
282
+ async stop() {
283
+ if (this.callbackServer) {
284
+ await this.callbackServer.stop().catch(() => { });
285
+ this.callbackServer = null;
286
+ }
287
+ await super.stop();
288
+ }
289
+ }
@@ -0,0 +1,60 @@
1
+ import { oAddress } from '@olane/o-core';
2
+ import { OAuthTokens } from './interfaces/oauth-tokens.interface.js';
3
+ import { OAuthClientInfo } from './interfaces/oauth-client-info.interface.js';
4
+ interface OAuthStorageConfig {
5
+ storageAddress: oAddress;
6
+ useFunction: (address: oAddress, request: any) => Promise<any>;
7
+ }
8
+ /**
9
+ * OAuth storage adapter that uses Olane OS o-storage for encrypted persistence
10
+ *
11
+ * This adapter provides a thin layer over o://secure storage for OAuth tokens
12
+ * and client information, with automatic encryption handled by the storage layer.
13
+ */
14
+ export declare class McpOAuthStorage {
15
+ private storageAddress;
16
+ private use;
17
+ constructor(config: OAuthStorageConfig);
18
+ /**
19
+ * Save OAuth tokens for a server (encrypted via o://secure)
20
+ */
21
+ saveTokens(serverUrl: string, tokens: OAuthTokens): Promise<void>;
22
+ /**
23
+ * Get OAuth tokens for a server (decrypted automatically)
24
+ */
25
+ getTokens(serverUrl: string): Promise<OAuthTokens | null>;
26
+ /**
27
+ * Save OAuth client info for a server (encrypted)
28
+ */
29
+ saveClientInfo(serverUrl: string, clientInfo: OAuthClientInfo): Promise<void>;
30
+ /**
31
+ * Get OAuth client info for a server (decrypted automatically)
32
+ */
33
+ getClientInfo(serverUrl: string): Promise<OAuthClientInfo | null>;
34
+ /**
35
+ * Clear all OAuth data for a server
36
+ */
37
+ clearServer(serverUrl: string): Promise<void>;
38
+ /**
39
+ * Check if tokens exist for a server
40
+ */
41
+ hasTokens(serverUrl: string): Promise<boolean>;
42
+ /**
43
+ * Check if tokens are expired
44
+ */
45
+ areTokensExpired(serverUrl: string): Promise<boolean>;
46
+ /**
47
+ * Get the token key for storage
48
+ */
49
+ private getTokenKey;
50
+ /**
51
+ * Get the client info key for storage
52
+ */
53
+ private getClientKey;
54
+ /**
55
+ * Hash server URL for use as storage key
56
+ */
57
+ private hashServerUrl;
58
+ }
59
+ export {};
60
+ //# sourceMappingURL=mcp-oauth-storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-oauth-storage.d.ts","sourceRoot":"","sources":["../../../src/oauth/mcp-oauth-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,6CAA6C,CAAC;AAE9E,UAAU,kBAAkB;IAC1B,cAAc,EAAE,QAAQ,CAAC;IACzB,WAAW,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CAChE;AAED;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,cAAc,CAAW;IACjC,OAAO,CAAC,GAAG,CAAoD;gBAEnD,MAAM,EAAE,kBAAkB;IAKtC;;OAEG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBvE;;OAEG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAkB/D;;OAEG;IACG,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,eAAe,GAC1B,OAAO,CAAC,IAAI,CAAC;IAYhB;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAgBvE;;OAEG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBnD;;OAEG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAepD;;OAEG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAY3D;;OAEG;IACH,OAAO,CAAC,WAAW;IAInB;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;OAEG;IACH,OAAO,CAAC,aAAa;CAOtB"}