mcp-orchestrator
Version:
MCP Orchestrator - Discover and install MCPs with automatic OAuth support. Uses Claude CLI for OAuth MCPs (Canva, Asana, etc). 34 trusted MCPs from Claude Partners.
120 lines (119 loc) • 4.02 kB
JavaScript
/**
* OAuth Client Provider for MCP Orchestrator
* Handles OAuth 2.1 authentication flow with automatic browser opening
*/
import { exec } from 'child_process';
const CALLBACK_PORT = 8095;
const CALLBACK_URL = `http://localhost:${CALLBACK_PORT}/callback`;
/**
* In-memory OAuth client provider
* Automatically opens browser for authorization
*/
export class MCPOAuthClientProvider {
serverName;
onAuthUrlGenerated;
storage = {};
constructor(serverName, onAuthUrlGenerated) {
this.serverName = serverName;
this.onAuthUrlGenerated = onAuthUrlGenerated;
}
get redirectUrl() {
return CALLBACK_URL;
}
get clientMetadata() {
return {
client_name: `MCP Orchestrator - ${this.serverName}`,
redirect_uris: [CALLBACK_URL],
grant_types: ['authorization_code', 'refresh_token'],
response_types: ['code'],
token_endpoint_auth_method: 'none', // Public client (no secret)
scope: 'mcp:tools'
};
}
clientInformation() {
return this.storage.clientInformation;
}
async saveClientInformation(clientInformation) {
this.storage.clientInformation = clientInformation;
console.error(`✅ Saved OAuth client information for ${this.serverName}`);
}
tokens() {
return this.storage.tokens;
}
async saveTokens(tokens) {
this.storage.tokens = tokens;
console.error(`✅ Saved OAuth tokens for ${this.serverName}`);
}
async redirectToAuthorization(authorizationUrl) {
console.error(`🌐 Opening browser for ${this.serverName} authentication...`);
console.error(`📍 Auth URL: ${authorizationUrl.toString()}`);
// Notify caller about auth URL
if (this.onAuthUrlGenerated) {
this.onAuthUrlGenerated(authorizationUrl);
}
// Open browser automatically
await this.openBrowser(authorizationUrl.toString());
}
async saveCodeVerifier(codeVerifier) {
this.storage.codeVerifier = codeVerifier;
}
codeVerifier() {
if (!this.storage.codeVerifier) {
throw new Error('No code verifier saved');
}
return this.storage.codeVerifier;
}
/**
* Opens URL in user's default browser
* Cross-platform support: Windows, macOS, Linux
*/
async openBrowser(url) {
const platform = process.platform;
let command;
switch (platform) {
case 'darwin': // macOS
command = `open "${url}"`;
break;
case 'win32': // Windows
command = `start "" "${url}"`;
break;
default: // Linux and others
command = `xdg-open "${url}"`;
break;
}
return new Promise((resolve, reject) => {
exec(command, (error) => {
if (error) {
console.error(`⚠️ Failed to open browser automatically: ${error.message}`);
console.error(`📋 Please manually open: ${url}`);
// Don't reject - manual opening is acceptable
resolve();
}
else {
console.error(`✅ Browser opened successfully`);
resolve();
}
});
});
}
/**
* Clear all stored credentials
*/
async invalidateCredentials(scope) {
switch (scope) {
case 'all':
this.storage = {};
break;
case 'client':
delete this.storage.clientInformation;
break;
case 'tokens':
delete this.storage.tokens;
break;
case 'verifier':
delete this.storage.codeVerifier;
break;
}
console.error(`🗑️ Invalidated ${scope} credentials for ${this.serverName}`);
}
}