Skip to content

Commit c755887

Browse files
committed
feat(backend): implement instance path and token generation in createInstance
1 parent 1a5759e commit c755887

File tree

1 file changed

+55
-12
lines changed

1 file changed

+55
-12
lines changed

services/backend/src/services/mcpInstanceService.ts

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { eq, and, inArray } from 'drizzle-orm';
33
import type { AnyDatabase } from '../db';
44
import type { FastifyBaseLogger } from 'fastify';
55
import { nanoid } from 'nanoid';
6+
import { generateInstancePath, generateInstanceToken } from '../utils/instancePathGenerator';
67

78
/**
89
* Instance with user information (includes user_slug and user_email from authUser table)
@@ -13,6 +14,7 @@ export interface InstanceWithUser {
1314
user_id: string;
1415
user_slug: string;
1516
user_email: string;
17+
instance_path: string | null;
1618
status: string;
1719
status_message: string | null;
1820
status_updated_at: Date | null;
@@ -42,37 +44,77 @@ export class McpInstanceService {
4244
* @param installationId - Installation ID
4345
* @param userId - User ID
4446
* @param status - Initial status (default: 'provisioning')
47+
* @returns Object with instanceId, instancePath, and instanceToken (plaintext)
4548
*/
4649
async createInstance(
4750
installationId: string,
4851
userId: string,
4952
status: string = 'provisioning',
5053
statusMessage?: string
51-
): Promise<void> {
54+
): Promise<{ instanceId: string; instancePath: string; instanceToken: string }> {
5255
const schema = await import('../db/schema');
5356
const { mcpServerInstances } = schema;
5457

5558
const instanceId = `inst_${nanoid()}`;
5659

57-
await this.db.insert(mcpServerInstances).values({
58-
id: instanceId,
59-
installation_id: installationId,
60-
user_id: userId,
61-
status,
62-
status_message: statusMessage,
63-
status_updated_at: new Date(),
64-
created_at: new Date(),
65-
updated_at: new Date(),
66-
});
60+
const MAX_PATH_RETRIES = 5;
61+
let instancePath = '';
62+
let instanceToken: string;
63+
let instanceTokenHash: string;
64+
let inserted = false;
65+
66+
// Generate token once (outside retry loop)
67+
const tokenResult = await generateInstanceToken();
68+
instanceToken = tokenResult.plaintext;
69+
instanceTokenHash = tokenResult.hash;
70+
71+
for (let attempt = 0; attempt < MAX_PATH_RETRIES; attempt++) {
72+
instancePath = generateInstancePath();
73+
74+
try {
75+
await this.db.insert(mcpServerInstances).values({
76+
id: instanceId,
77+
installation_id: installationId,
78+
user_id: userId,
79+
instance_path: instancePath,
80+
instance_token: instanceTokenHash, // Store hash, not plaintext
81+
status,
82+
status_message: statusMessage,
83+
status_updated_at: new Date(),
84+
created_at: new Date(),
85+
updated_at: new Date(),
86+
});
87+
inserted = true;
88+
break;
89+
} catch (error: any) {
90+
// Check if it's a unique constraint violation on instance_path
91+
if (error.code === '23505' && error.constraint?.includes('instance_path')) {
92+
this.logger.warn({
93+
attempt: attempt + 1,
94+
instancePath
95+
}, 'Instance path collision detected, retrying with new path');
96+
continue;
97+
}
98+
// Re-throw non-uniqueness errors
99+
throw error;
100+
}
101+
}
102+
103+
if (!inserted) {
104+
throw new Error(`Failed to generate unique instance path after ${MAX_PATH_RETRIES} retries`);
105+
}
67106

68107
this.logger.info({
69108
operation: 'create_instance',
70109
instanceId,
71110
installationId,
72111
userId,
112+
instancePath,
73113
status,
74114
statusMessage
75-
}, 'Created MCP server instance');
115+
}, 'Created MCP server instance with path-based access');
116+
117+
return { instanceId, instancePath, instanceToken };
76118
}
77119

78120
/**
@@ -250,6 +292,7 @@ export class McpInstanceService {
250292
user_id: mcpServerInstances.user_id,
251293
user_slug: authUser.username,
252294
user_email: authUser.email,
295+
instance_path: mcpServerInstances.instance_path,
253296
status: mcpServerInstances.status,
254297
status_message: mcpServerInstances.status_message,
255298
status_updated_at: mcpServerInstances.status_updated_at,

0 commit comments

Comments
 (0)