Skip to content

Commit 5ca072b

Browse files
author
Lasim
committed
feat(gateway): add user configuration retrieval and processing logic
1 parent fae0557 commit 5ca072b

File tree

7 files changed

+112
-39
lines changed

7 files changed

+112
-39
lines changed

services/gateway/src/core/auth/api-client.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,18 @@ export class DeployStackAPI {
8686
return response as MCPInstallationsResponse;
8787
}
8888

89+
/**
90+
* Get user configurations for an MCP installation
91+
* @param teamId Team ID
92+
* @param installationId Installation ID
93+
* @returns User configurations response
94+
*/
95+
async getUserConfigurations(teamId: string, installationId: string): Promise<any> {
96+
const endpoint = `${this.baseUrl}/api/teams/${teamId}/mcp/installations/${installationId}/user-configs`;
97+
const response = await this.makeRequest(endpoint);
98+
return response;
99+
}
100+
89101
/**
90102
* Make an authenticated API request
91103
* @param endpoint API endpoint URL

services/gateway/src/core/mcp/config-processor.ts

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,89 @@
1-
import { MCPInstallation, MCPServerConfig, TeamMCPConfig } from '../../types/mcp';
1+
import { MCPInstallation, MCPServerConfig, TeamMCPConfig, MCPUserConfiguration } from '../../types/mcp';
22

33
/**
4-
* Process MCP installations into server configurations for the Gateway
4+
* Process MCP installations into server configurations for the Gateway (Three-tier architecture)
55
* @param teamId Team ID
66
* @param teamName Team name
77
* @param installations Raw MCP installations from API
8+
* @param userConfigurations User configurations from API
89
* @returns Processed team MCP configuration
910
*/
1011
export function processMCPInstallations(
1112
teamId: string,
1213
teamName: string,
13-
installations: MCPInstallation[]
14+
installations: MCPInstallation[],
15+
userConfigurations: MCPUserConfiguration[] = []
1416
): TeamMCPConfig {
1517
const servers: MCPServerConfig[] = installations.map(installation => {
16-
// Process installation methods to extract command and args
18+
// Process installation methods to extract template command and args
1719
const installationMethods = installation.server.installation_methods || [];
18-
let command = 'npx';
19-
let args: string[] = [];
20+
let templateCommand = 'npx';
21+
let templateArgs: string[] = [];
2022

21-
22-
// Find the claude-desktop installation method
23+
// Find the claude-desktop installation method for template args
2324
const claudeDesktopMethod = installationMethods.find(
2425
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
2526
(method: any) => method.client === 'claude-desktop'
2627
);
2728

2829
if (claudeDesktopMethod) {
2930
// Use the installation method data directly
30-
command = claudeDesktopMethod.command || 'npx';
31-
args = claudeDesktopMethod.args || [];
31+
templateCommand = claudeDesktopMethod.command || 'npx';
32+
templateArgs = claudeDesktopMethod.args || [];
3233
} else {
3334
// Fallback logic for servers without proper installation_methods
3435
const runtime = installation.server.runtime;
3536

3637
if (runtime === 'node' || runtime === 'nodejs') {
37-
command = 'npx';
38-
args = [installation.server.name];
38+
templateCommand = 'npx';
39+
templateArgs = [installation.server.name];
3940
} else if (runtime === 'python') {
40-
command = 'python';
41-
args = ['-m', installation.server.name];
41+
templateCommand = 'python';
42+
templateArgs = ['-m', installation.server.name];
4243
} else if (runtime === 'go') {
43-
command = installation.server.name;
44-
args = [];
44+
templateCommand = installation.server.name;
45+
templateArgs = [];
4546
} else {
4647
// Final fallback
47-
command = 'npx';
48-
args = [installation.server.name];
48+
templateCommand = 'npx';
49+
templateArgs = [installation.server.name];
4950
}
5051
}
5152

52-
// Merge environment variables from server definition and user customization
53+
// Find user configuration for this installation (use first one for now)
54+
const userConfig = userConfigurations.find(config => config.installation_id === installation.id);
55+
56+
// Three-tier assembly: Template + Team + User
57+
const finalArgs = [
58+
...templateArgs, // Template args (fixed)
59+
...(installation.team_args || []), // Team args (shared)
60+
...(userConfig?.user_args || []) // User args (personal)
61+
];
62+
63+
// Three-tier environment assembly: Template + Team + User
5364
const serverEnvVars = installation.server.environment_variables || [];
5465
const env: Record<string, string> = {};
5566

56-
// Add server-defined environment variables (if they have default values)
67+
// Add server-defined environment variables (template level)
5768
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5869
serverEnvVars.forEach((envVar: any) => {
5970
if (envVar.name && envVar.default_value) {
6071
env[envVar.name] = envVar.default_value;
6172
}
6273
});
6374

64-
// Override with user-provided environment variables
65-
Object.assign(env, installation.user_environment_variables || {});
75+
// Add team-level environment variables
76+
Object.assign(env, installation.team_env || {});
77+
78+
// Add user-level environment variables
79+
Object.assign(env, userConfig?.user_env || {});
6680

6781
return {
6882
id: installation.id,
6983
name: installation.server.name,
7084
installation_name: installation.installation_name,
71-
command,
72-
args,
85+
command: templateCommand,
86+
args: finalArgs,
7387
env,
7488
runtime: installation.server.runtime,
7589
installation_type: installation.installation_type,
@@ -81,6 +95,7 @@ export function processMCPInstallations(
8195
team_id: teamId,
8296
team_name: teamName,
8397
installations,
98+
user_configurations: userConfigurations,
8499
servers,
85100
last_updated: new Date().toISOString()
86101
};

services/gateway/src/core/mcp/config-service.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,25 @@ export class MCPConfigService {
6060
const installations = response.data || [];
6161

6262
if (showSpinner && spinner) {
63-
spinner.text = `Processing ${installations.length} MCP installation${installations.length === 1 ? '' : 's'}...`;
63+
spinner.text = `Downloading user configurations for ${installations.length} installation${installations.length === 1 ? '' : 's'}...`;
64+
}
65+
66+
// Download user configurations for each installation
67+
const allUserConfigurations = [];
68+
for (const installation of installations) {
69+
try {
70+
const userConfigResponse = await apiClient.getUserConfigurations(teamId, installation.id);
71+
if (userConfigResponse.success && userConfigResponse.data) {
72+
allUserConfigurations.push(...userConfigResponse.data);
73+
}
74+
} catch (error) {
75+
// Log warning but continue - user configs are optional
76+
console.log(chalk.yellow(`⚠️ Could not fetch user configurations for installation ${installation.installation_name}: ${error instanceof Error ? error.message : String(error)}`));
77+
}
78+
}
79+
80+
if (showSpinner && spinner) {
81+
spinner.text = `Processing ${installations.length} installation${installations.length === 1 ? '' : 's'} with ${allUserConfigurations.length} user configuration${allUserConfigurations.length === 1 ? '' : 's'}...`;
6482
}
6583

6684
// Filter and validate installations
@@ -71,8 +89,8 @@ export class MCPConfigService {
7189
console.log(chalk.yellow(`⚠️ Skipped ${invalidCount} invalid installation${invalidCount === 1 ? '' : 's'}`));
7290
}
7391

74-
// Process installations into server configurations
75-
const config = processMCPInstallations(teamId, teamName || `Team ${teamId}`, validInstallations);
92+
// Process installations into server configurations with three-tier architecture
93+
const config = processMCPInstallations(teamId, teamName || `Team ${teamId}`, validInstallations, allUserConfigurations);
7694

7795
if (showSpinner && spinner) {
7896
spinner.text = 'Storing MCP configuration securely...';

services/gateway/src/core/mcp/test-processor.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ import { processMCPInstallations, validateMCPInstallation, filterValidInstallati
88
export function testMCPProcessing(): void {
99
console.log('🧪 Testing MCP configuration processing...');
1010

11-
// Sample MCP installation data based on API spec
11+
// Sample MCP installation data based on API spec (three-tier architecture)
1212
const sampleInstallations: MCPInstallation[] = [
1313
{
1414
id: 'inst-001',
1515
team_id: 'team-123',
1616
server_id: 'server-001',
17-
user_id: 'user-001',
17+
created_by: 'user-001',
1818
installation_name: 'Bright Data MCP',
1919
installation_type: 'local',
20-
user_environment_variables: {
21-
'API_TOKEN': 'test-token-123',
20+
team_args: ['--api-token', 'team-token-123'],
21+
team_env: {
2222
'API_URL': 'https://brightdata.example.com'
2323
},
2424
created_at: '2024-01-01T00:00:00Z',
@@ -50,10 +50,11 @@ export function testMCPProcessing(): void {
5050
id: 'inst-002',
5151
team_id: 'team-123',
5252
server_id: 'server-002',
53-
user_id: 'user-001',
53+
created_by: 'user-001',
5454
installation_name: 'Python File Manager',
5555
installation_type: 'local',
56-
user_environment_variables: {
56+
team_args: null,
57+
team_env: {
5758
'BASE_PATH': '/home/user/files'
5859
},
5960
created_at: '2024-01-01T00:00:00Z',
@@ -87,10 +88,11 @@ export function testMCPProcessing(): void {
8788
id: 'inst-003',
8889
team_id: 'team-123',
8990
server_id: 'server-003',
90-
user_id: 'user-001',
91+
created_by: 'user-001',
9192
installation_name: 'Invalid Server',
9293
installation_type: 'local',
93-
user_environment_variables: {},
94+
team_args: null,
95+
team_env: null,
9496
created_at: '2024-01-01T00:00:00Z',
9597
updated_at: '2024-01-01T00:00:00Z',
9698
last_used_at: null,

services/gateway/src/services/server-start-service.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ export class ServerStartService {
232232
team_id: targetTeamId,
233233
team_name: targetTeamName,
234234
installations: [],
235+
user_configurations: [],
235236
servers: [],
236237
last_updated: new Date().toISOString()
237238
};
@@ -242,6 +243,7 @@ export class ServerStartService {
242243
team_id: targetTeamId,
243244
team_name: targetTeamName,
244245
installations: [],
246+
user_configurations: [],
245247
servers: [],
246248
last_updated: new Date().toISOString()
247249
};

services/gateway/src/types/mcp.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@ export interface MCPServer {
77
env?: Record<string, string>;
88
}
99

10-
// MCP Server Installation from API
10+
// MCP Server Installation from API (Three-tier architecture)
1111
export interface MCPInstallation {
1212
id: string;
1313
team_id: string;
1414
server_id: string;
15-
user_id: string;
15+
created_by: string;
1616
installation_name: string;
1717
installation_type: 'local' | 'cloud';
18-
user_environment_variables: Record<string, string>;
18+
team_args: string[] | null;
19+
team_env: Record<string, string> | null;
1920
created_at: string;
2021
updated_at: string;
2122
last_used_at: string | null;
@@ -33,12 +34,32 @@ export interface MCPInstallation {
3334
};
3435
}
3536

37+
// MCP User Configuration from API (Three-tier architecture)
38+
export interface MCPUserConfiguration {
39+
id: string;
40+
installation_id: string;
41+
user_id: string;
42+
device_name: string | null;
43+
user_args: string[] | null;
44+
user_env: Record<string, string> | null;
45+
created_at: string;
46+
updated_at: string;
47+
last_used_at: string | null;
48+
}
49+
3650
// MCP Installation API Response
3751
export interface MCPInstallationsResponse {
3852
success: boolean;
3953
data: MCPInstallation[];
4054
}
4155

56+
// MCP User Configurations API Response
57+
export interface MCPUserConfigurationsResponse {
58+
success: boolean;
59+
data: MCPUserConfiguration[];
60+
message?: string;
61+
}
62+
4263
// Processed MCP Server Config for Gateway
4364
export interface MCPServerConfig {
4465
id: string;
@@ -52,11 +73,12 @@ export interface MCPServerConfig {
5273
transport_type: 'stdio' | 'http' | 'sse';
5374
}
5475

55-
// Team MCP Configuration stored securely
76+
// Team MCP Configuration stored securely (Three-tier architecture)
5677
export interface TeamMCPConfig {
5778
team_id: string;
5879
team_name: string;
5980
installations: MCPInstallation[];
81+
user_configurations: MCPUserConfiguration[];
6082
servers: MCPServerConfig[];
6183
last_updated: string;
6284
}

services/gateway/src/utils/auth-config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export const DEFAULT_AUTH_CONFIG: AuthConfig = {
2424
scopes: [
2525
'mcp:read',
2626
'mcp:categories:read',
27+
'mcp:user-configs:read',
2728
'account:read',
2829
'user:read',
2930
'teams:read',
@@ -55,6 +56,7 @@ export function buildAuthConfig(baseUrl: string): AuthConfig {
5556
export const SCOPE_DESCRIPTIONS: Record<string, string> = {
5657
'mcp:read': 'Access your MCP server installations and configurations',
5758
'mcp:categories:read': 'Read MCP server categories and organization',
59+
'mcp:user-configs:read': 'Access your personal MCP server configurations and device-specific settings',
5860
'account:read': 'Read your account information',
5961
'user:read': 'Read your user profile information',
6062
'teams:read': 'Read your team memberships and information',

0 commit comments

Comments
 (0)