Skip to content

Commit c79f52a

Browse files
author
Lasim
committed
feat(backend): add installation_type field for OAuth installations
1 parent fce8128 commit c79f52a

File tree

6 files changed

+83
-45
lines changed

6 files changed

+83
-45
lines changed

services/backend/api-spec.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23950,14 +23950,23 @@
2395023950
"maxLength": 100,
2395123951
"description": "Custom name for this installation (optional)"
2395223952
},
23953+
"installation_type": {
23954+
"type": "string",
23955+
"enum": [
23956+
"global",
23957+
"team"
23958+
],
23959+
"description": "Installation type - required for OAuth installations"
23960+
},
2395323961
"team_config": {
2395423962
"type": "object",
2395523963
"additionalProperties": true,
2395623964
"description": "Team-level configuration for installation (optional)"
2395723965
}
2395823966
},
2395923967
"required": [
23960-
"server_id"
23968+
"server_id",
23969+
"installation_type"
2396123970
],
2396223971
"additionalProperties": false
2396323972
}

services/backend/api-spec.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17030,12 +17030,19 @@ paths:
1703017030
minLength: 1
1703117031
maxLength: 100
1703217032
description: Custom name for this installation (optional)
17033+
installation_type:
17034+
type: string
17035+
enum:
17036+
- global
17037+
- team
17038+
description: Installation type - required for OAuth installations
1703317039
team_config:
1703417040
type: object
1703517041
additionalProperties: true
1703617042
description: Team-level configuration for installation (optional)
1703717043
required:
1703817044
- server_id
17045+
- installation_type
1703917046
additionalProperties: false
1704017047
required: true
1704117048
parameters:

services/backend/src/routes/mcp/installations/authorize.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ export default async function authorizeRoute(server: FastifyInstance) {
242242
server_id: mcpServer.id,
243243
created_by: userId,
244244
installation_name: body.installation_name || mcpServer.name,
245-
installation_type: 'global',
245+
installation_type: body.installation_type,
246246
team_args: null,
247247
team_env: body.team_config ? JSON.stringify(body.team_config) : null,
248248
team_headers: null,

services/backend/src/routes/mcp/installations/schemas.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,18 @@ export const OAUTH_AUTHORIZE_REQUEST_SCHEMA = {
222222
maxLength: 100,
223223
description: 'Custom name for this installation (optional)'
224224
},
225+
installation_type: {
226+
type: 'string',
227+
enum: ['global', 'team'],
228+
description: 'Installation type - required for OAuth installations'
229+
},
225230
team_config: {
226231
type: 'object',
227232
additionalProperties: true,
228233
description: 'Team-level configuration for installation (optional)'
229234
}
230235
},
231-
required: ['server_id'],
236+
required: ['server_id', 'installation_type'],
232237
additionalProperties: false
233238
} as const;
234239

@@ -713,6 +718,7 @@ export interface ClientConfigSuccessResponse {
713718
export interface OAuthAuthorizeRequest {
714719
server_id: string;
715720
installation_name?: string;
721+
installation_type: 'global' | 'team';
716722
// eslint-disable-next-line @typescript-eslint/no-explicit-any
717723
team_config?: Record<string, any>;
718724
}

services/frontend/src/components/mcp-server/wizard/McpServerInstallWizard.vue

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/* eslint-disable @typescript-eslint/no-explicit-any */
33
import { ref, computed, onMounted, onUnmounted } from 'vue'
44
import { useI18n } from 'vue-i18n'
5-
import { useRoute } from 'vue-router'
5+
import { useRoute, useRouter } from 'vue-router'
66
import { Button } from '@/components/ui/button'
77
import { DsProgressSteps, type ProgressStep } from '@/components/ui/ds-progress-steps'
88
import { toast } from 'vue-sonner'
@@ -34,6 +34,7 @@ const emit = defineEmits<{
3434
3535
const { t } = useI18n()
3636
const route = useRoute()
37+
const router = useRouter()
3738
const eventBus = useEventBus()
3839
3940
// Form data interface
@@ -97,17 +98,17 @@ const progressSteps = computed<ProgressStep[]>(() => {
9798
const wizardSteps = [
9899
{
99100
id: 1,
101+
title: t('mcpInstallations.wizard.steps.selectPlatform'),
102+
description: t('mcpInstallations.wizard.platform.helpText')
103+
},
104+
{
105+
id: 2,
100106
title: requiresOAuth.value
101107
? 'OAuth Authorization'
102108
: t('mcpInstallations.wizard.steps.configureEnvironment'),
103109
description: requiresOAuth.value
104110
? 'Authorize access to your account'
105111
: t('mcpInstallations.wizard.environment.helpText')
106-
},
107-
{
108-
id: 2,
109-
title: t('mcpInstallations.wizard.steps.selectPlatform'),
110-
description: t('mcpInstallations.wizard.platform.helpText')
111112
}
112113
]
113114
@@ -270,10 +271,16 @@ const submitInstallation = async () => {
270271
const response = await McpInstallationService.createInstallation(currentTeamId.value, installationData)
271272
272273
if (response.success) {
273-
emit('complete', {
274-
...installationData,
275-
id: response.data.id
274+
// Show success toast
275+
toast.success('Installation successful', {
276+
description: `${formData.value.server.server_data?.name || 'MCP server'} has been installed.`
276277
})
278+
279+
// Emit event to refresh installation list
280+
eventBus.emit('mcp-installations-updated')
281+
282+
// Redirect to installation list
283+
router.push('/mcp-server')
277284
} else {
278285
throw new Error(response.message || 'Failed to create installation')
279286
}
@@ -380,8 +387,7 @@ const handleOAuthAuthorization = async () => {
380387
const authorizationData = {
381388
server_id: formData.value.server.server_id,
382389
installation_name: formData.value.server.server_data?.name || 'Unknown Server',
383-
team_args: formData.value.environment.team_args,
384-
team_env: formData.value.environment.team_env
390+
installation_type: formData.value.platform.installation_type
385391
}
386392
387393
// Call backend to start OAuth flow
@@ -447,27 +453,22 @@ const handleOAuthMessage = (event: MessageEvent) => {
447453
448454
// Handle success message
449455
if (event.data.type === 'oauth_success') {
450-
const { installation_id } = event.data
451-
452456
// Close popup if still open
453457
if (oauthPopup.value && !oauthPopup.value.closed) {
454458
oauthPopup.value.close()
455459
}
456460
oauthPopup.value = null
457461
458-
// Store installation_id in platform data
459-
formData.value.platform.installation_id = installation_id
460-
461462
// Show success toast
462-
toast.success('Authorization successful', {
463-
description: `Connected to ${formData.value.server.server_data?.name || 'MCP server'}. Choose your platform to continue.`
463+
toast.success('Installation successful', {
464+
description: `${formData.value.server.server_data?.name || 'MCP server'} has been installed and connected.`
464465
})
465466
466-
// Auto-advance to next step (Platform Selection)
467-
currentStep.value++
468-
469467
// Emit event to refresh installation list
470468
eventBus.emit('mcp-installations-updated')
469+
470+
// Redirect to installation list
471+
router.push('/mcp-server')
471472
}
472473
473474
// Handle error message
@@ -627,25 +628,13 @@ onUnmounted(() => {
627628
:completed-steps="completedSteps"
628629
max-width="max-w-3xl"
629630
>
630-
<!-- Step 1 Content: Environment Variables OR OAuth Authorization -->
631+
<!-- Step 1 Content: Platform Selection -->
631632
<template #step-content-0>
632-
<!-- OAuth Authorization Step (if OAuth required) -->
633-
<OAuthAuthorizationStep
634-
v-if="requiresOAuth"
635-
:server-data="formData.server.server_data"
636-
:is-authorizing="isSubmitting"
637-
@authorize="handleOAuthAuthorization"
638-
/>
639-
640-
<!-- Environment Variables Step (if OAuth NOT required) -->
641-
<EnvironmentVariablesStep
642-
v-else
643-
v-model="formData.environment"
644-
:server-data="formData.server.server_data"
645-
@validation-change="handleValidationChange"
633+
<PlatformSelectionStep
634+
v-model="formData.platform.installation_type"
646635
/>
647636

648-
<!-- Navigation Buttons -->
637+
<!-- Navigation Buttons for Platform Step -->
649638
<div class="flex items-center justify-between mt-6">
650639
<Button variant="outline" @click="previousStep">
651640
{{ t('navigation.previous') }}
@@ -658,21 +647,33 @@ onUnmounted(() => {
658647

659648
<Button
660649
@click="nextStep"
661-
:disabled="!canProceedFromEnvironment"
650+
:disabled="!formData.platform.installation_type"
662651
>
663652
{{ t('navigation.next') }}
664653
</Button>
665654
</div>
666655
</div>
667656
</template>
668657

669-
<!-- Platform Selection Step Content -->
658+
<!-- Step 2 Content: Environment Variables OR OAuth Authorization -->
670659
<template #step-content-1>
671-
<PlatformSelectionStep
672-
v-model="formData.platform.installation_type"
660+
<!-- OAuth Authorization Step (if OAuth required) -->
661+
<OAuthAuthorizationStep
662+
v-if="requiresOAuth"
663+
:server-data="formData.server.server_data"
664+
:is-authorizing="isSubmitting"
665+
@authorize="handleOAuthAuthorization"
673666
/>
674667

675-
<!-- Navigation Buttons for Platform Step -->
668+
<!-- Environment Variables Step (if OAuth NOT required) -->
669+
<EnvironmentVariablesStep
670+
v-else
671+
v-model="formData.environment"
672+
:server-data="formData.server.server_data"
673+
@validation-change="handleValidationChange"
674+
/>
675+
676+
<!-- Navigation Buttons -->
676677
<div class="flex items-center justify-between mt-6">
677678
<Button variant="outline" @click="previousStep">
678679
{{ t('navigation.previous') }}
@@ -683,7 +684,20 @@ onUnmounted(() => {
683684
{{ t('navigation.cancel') }}
684685
</Button>
685686

687+
<!-- OAuth: "Authorize & Install" button -->
688+
<Button
689+
v-if="requiresOAuth"
690+
@click="handleOAuthAuthorization"
691+
:loading="isSubmitting"
692+
:loading-text="t('mcpInstallations.wizard.authorizing')"
693+
:disabled="!formData.platform.installation_type"
694+
>
695+
{{ t('mcpInstallations.wizard.authorizeAndInstall') }}
696+
</Button>
697+
698+
<!-- Non-OAuth: "Install" button -->
686699
<Button
700+
v-else
687701
@click="submitInstallation"
688702
:disabled="!canSubmit"
689703
:loading="isSubmitting"

services/frontend/src/i18n/locales/en/mcp-installations.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ export default {
8181
description: 'Follow the steps below to install a new MCP server for your team',
8282
installing: 'Installing...',
8383
install: 'Install Server',
84+
authorizing: 'Authorizing...',
85+
authorizeAndInstall: 'Authorize & Install',
8486

8587
steps: {
8688
selectServer: 'Select Server',

0 commit comments

Comments
 (0)