Skip to main content
Glama
tenant-tool-bridge.ts•13.4 kB
#!/usr/bin/env node /** * Tenant Tool Bridge * * Bridges multi-tenant sessions with server-universal tools while maintaining isolation. * Each tenant can access server-universal tools within their isolated workspace. */ import { spawn, exec } from 'child_process'; import { promisify } from 'util'; import * as path from 'path'; import * as fs from 'fs/promises'; const execAsync = promisify(exec); interface ToolExecutionContext { sessionId: string; workspace: string; gitConfig: { name?: string; email?: string; pat?: string; }; sessionInfo: any; } interface ToolCallResult { success: boolean; stdout?: string; stderr?: string; exit_code?: number; message?: string; data?: any; } export class TenantToolBridge { private serverUniversalPath: string; private baseUrl: string; constructor(private orchestrator: any) { this.serverUniversalPath = path.resolve(process.cwd(), '../apps/local-server/src/server-universal.js'); this.baseUrl = 'http://localhost:3000/mcp'; console.log('šŸŒ‰ Tenant Tool Bridge initialized'); console.log(`šŸ“” Server Universal: ${this.serverUniversalPath}`); console.log(`šŸ”— Endpoint: ${this.baseUrl}`); } /** * Execute a server-universal tool within a tenant's session context */ async executeTool( sessionId: string, toolName: string, args: any = {} ): Promise<ToolCallResult> { try { // 1. Validate session exists and is active const context = await this.getSessionContext(sessionId); if (!context) { return { success: false, message: `Session ${sessionId} not found or inactive`, exit_code: -1 }; } // 2. Route to appropriate tool handler switch (toolName) { case 'bash': return await this.executeBashCommand(context, args.command || ''); case 'admin_local_server': return await this.executeAdminCommand(context, args.command || '', args.adminPassword); case 'search_local': return await this.executeSearchCommand(context, args); case 'get_local_book': return await this.executeBookCommand(context, args); case 'get_local_content': return await this.executeContentCommand(context, args); case 'list_local_books': return await this.executeListBooksCommand(context, args); case 'get_database_stats': return await this.executeStatsCommand(context); case 'find_egw_quotes': return await this.executeQuotesCommand(context, args); default: return { success: false, message: `Unknown tool: ${toolName}`, exit_code: -1 }; } } catch (error) { console.error(`āŒ Tool bridge error for ${toolName}:`, error.message); return { success: false, message: `Tool execution failed: ${error.message}`, exit_code: -1 }; } } /** * Get session context for tool execution */ private async getSessionContext(sessionId: string): Promise<ToolExecutionContext | null> { try { const session = await this.orchestrator.getSession(sessionId); if (!session || !session.isActive) { return null; } return { sessionId: session.id, workspace: session.workspace, gitConfig: session.gitConfig || {}, sessionInfo: session }; } catch (error) { console.error(`āŒ Failed to get session context:`, error.message); return null; } } /** * Execute bash command within tenant workspace */ private async executeBashCommand(context: ToolExecutionContext, command: string): Promise<ToolCallResult> { try { // Set up environment for this tenant const env = { ...process.env, PWD: context.workspace, GIT_WORK_TREE: context.workspace, GIT_DIR: path.join(context.workspace, '.git'), GIT_AUTHOR_NAME: context.gitConfig.name || 'Anonymous', GIT_AUTHOR_EMAIL: context.gitConfig.email || 'anonymous@example.com', GIT_COMMITTER_NAME: context.gitConfig.name || 'Anonymous', GIT_COMMITTER_EMAIL: context.gitConfig.email || 'anonymous@example.com' }; // Add tenant's PAT if available if (context.gitConfig.pat) { env.GITHUB_PAT = context.gitConfig.pat; } // Enhanced git command handling with tenant's PAT let enhancedCommand = command; if (context.gitConfig.pat && command.startsWith('git')) { enhancedCommand = this.enhanceGitCommand(command, context.gitConfig.pat); } // Execute command within tenant workspace const result = await execAsync(enhancedCommand, { cwd: context.workspace, env: env, timeout: 30000, maxBuffer: 1024 * 1024 * 10 // 10MB buffer }); return { success: true, stdout: result.stdout, stderr: result.stderr, exit_code: 0, message: 'Command executed successfully in tenant workspace' }; } catch (error: any) { return { success: false, stdout: error.stdout || '', stderr: error.stderr || error.message, exit_code: error.code || 1, message: 'Command failed in tenant workspace' }; } } /** * Execute admin command with security validation */ private async executeAdminCommand(context: ToolExecutionContext, command: string, adminPassword?: string): Promise<ToolCallResult> { try { // Validate admin password if required if (process.env.REQUIRE_ADMIN_PASSWORD !== 'false') { const requiredPassword = process.env.ADMIN_PASSWORD || 'admin18401844'; if (adminPassword !== requiredPassword) { return { success: false, message: 'Admin password required for system-level access', exit_code: -1 }; } } // Security: Ensure command stays within tenant workspace const safeCommand = this.validateAdminCommand(command, context.workspace); if (!safeCommand) { return { success: false, message: 'Command contains unsafe operations or attempts to access outside workspace', exit_code: -1 }; } const result = await execAsync(safeCommand, { cwd: context.workspace, timeout: 30000, maxBuffer: 1024 * 1024 * 10 }); return { success: true, stdout: result.stdout, stderr: result.stderr, exit_code: 0, message: 'Admin command executed successfully in tenant workspace' }; } catch (error: any) { return { success: false, stdout: error.stdout || '', stderr: error.stderr || error.message, exit_code: error.code || 1, message: 'Admin command failed in tenant workspace' }; } } /** * Execute database search command */ private async executeSearchCommand(context: ToolExecutionContext, args: any): Promise<ToolCallResult> { try { // Call server-universal via HTTP API const response = await this.callServerUniversal('search_local', args); return { success: true, data: response, message: 'Search completed successfully' }; } catch (error: any) { return { success: false, message: `Search failed: ${error.message}`, exit_code: -1 }; } } /** * Execute book command */ private async executeBookCommand(context: ToolExecutionContext, args: any): Promise<ToolCallResult> { try { const response = await this.callServerUniversal('get_local_book', args); return { success: true, data: response, message: 'Book retrieved successfully' }; } catch (error: any) { return { success: false, message: `Book retrieval failed: ${error.message}`, exit_code: -1 }; } } /** * Execute content command */ private async executeContentCommand(context: ToolExecutionContext, args: any): Promise<ToolCallResult> { try { const response = await this.callServerUniversal('get_local_content', args); return { success: true, data: response, message: 'Content retrieved successfully' }; } catch (error: any) { return { success: false, message: `Content retrieval failed: ${error.message}`, exit_code: -1 }; } } /** * Execute list books command */ private async executeListBooksCommand(context: ToolExecutionContext, args: any): Promise<ToolCallResult> { try { const response = await this.callServerUniversal('list_local_books', args); return { success: true, data: response, message: 'Books listed successfully' }; } catch (error: any) { return { success: false, message: `Book listing failed: ${error.message}`, exit_code: -1 }; } } /** * Execute stats command */ private async executeStatsCommand(context: ToolExecutionContext): Promise<ToolCallResult> { try { const response = await this.callServerUniversal('get_database_stats', {}); return { success: true, data: response, message: 'Stats retrieved successfully' }; } catch (error: any) { return { success: false, message: `Stats retrieval failed: ${error.message}`, exit_code: -1 }; } } /** * Execute quotes command */ private async executeQuotesCommand(context: ToolExecutionContext, args: any): Promise<ToolCallResult> { try { const response = await this.callServerUniversal('find_egw_quotes', args); return { success: true, data: response, message: 'Quotes found successfully' }; } catch (error: any) { return { success: false, message: `Quote search failed: ${error.message}`, exit_code: -1 }; } } /** * Call server-universal via HTTP API */ private async callServerUniversal(tool: string, args: any): Promise<any> { const requestBody = { jsonrpc: '2.0', id: Date.now(), method: 'tools/call', params: { name: tool, arguments: args } }; const response = await fetch(this.baseUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestBody) }); if (!response.ok) { throw new Error(`Server-universal HTTP error: ${response.status}`); } const result = await response.json(); if (result.error) { throw new Error(result.error.message); } return result.result; } /** * Enhance git command with tenant's PAT */ private enhanceGitCommand(command: string, pat: string): string { if (command.includes('git clone https://github.com/')) { return command.replace( 'https://github.com/', `https://${pat}@github.com/` ); } else if (command.includes('git push')) { return ` git remote set-url origin https://${pat}@github.com/$(git config --get remote.origin.url | sed 's/.*github\\.com\\///') git push origin `; } else if (command.includes('git pull') || command.includes('git fetch')) { return command.replace( 'origin', `https://${pat}@github.com/$(git config --get remote.origin.url | sed 's/.*github\\.com\\///')` ); } return command; } /** * Validate admin command for security */ private validateAdminCommand(command: string, workspace: string): string | null { // Dangerous patterns to block const dangerousPatterns = [ /rm\s+-rf\s+\//, /rm\s+-rf\s+\.\./, /cd\s+\.\./, /\.\.\/\.\./, /sudo/, /su\s/, /chmod\s+777/, /chown\s/, /passwd/, /useradd/, /userdel/, /groupadd/, /groupdel/ ]; for (const pattern of dangerousPatterns) { if (pattern.test(command)) { return null; } } // Ensure command doesn't try to escape workspace if (command.includes('..') && !command.includes('./')) { return null; } return command; } /** * Get available tools for a tenant */ getAvailableTools(): string[] { return [ 'bash', 'admin_local_server', 'search_local', 'get_local_book', 'get_local_content', 'list_local_books', 'get_database_stats', 'find_egw_quotes' ]; } /** * Get bridge status and health */ async getBridgeStatus(): Promise<any> { try { // Test server-universal connectivity const testResponse = await this.callServerUniversal('get_database_stats', {}); return { status: 'healthy', serverUniversalConnected: true, availableTools: this.getAvailableTools(), timestamp: new Date().toISOString() }; } catch (error) { return { status: 'error', serverUniversalConnected: false, error: error.message, availableTools: this.getAvailableTools(), timestamp: new Date().toISOString() }; } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pythondev-pro/egw_writings_mcp_server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server