Skip to content

Commit fae0557

Browse files
committed
feat(backend): update user configuration routes and scopes for OAuth2 access
1 parent 97b0b2d commit fae0557

File tree

5 files changed

+147
-51
lines changed

5 files changed

+147
-51
lines changed

services/backend/api-spec.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19400,7 +19400,7 @@
1940019400
"tags": [
1940119401
"MCP User Configurations"
1940219402
],
19403-
"description": "Retrieves all user-specific configurations for an MCP server installation belonging to the authenticated user. No Content-Type header required for this GET request. Supports both cookie-based authentication (for web users) and OAuth2 Bearer token authentication (for CLI users). Requires mcp:read scope for OAuth2 access.",
19403+
"description": "Retrieves all user-specific configurations for an MCP server installation belonging to the authenticated user. No Content-Type header required for this GET request. Supports both cookie-based authentication (for web users) and OAuth2 Bearer token authentication (for CLI users). Requires mcp:user-configs:read scope for OAuth2 access.",
1940419404
"parameters": [
1940519405
{
1940619406
"schema": {
@@ -19654,6 +19654,11 @@
1965419654
},
1965519655
"/api/teams/{teamId}/mcp/installations/{installationId}/user-configs/{configId}": {
1965619656
"get": {
19657+
"summary": "Get user configuration by ID",
19658+
"tags": [
19659+
"MCP User Configurations"
19660+
],
19661+
"description": "Retrieves a specific user configuration for an MCP server installation. No Content-Type header required for this GET request. Supports both cookie-based authentication (for web users) and OAuth2 Bearer token authentication (for CLI users). Requires mcp:user-configs:read scope for OAuth2 access.",
1965719662
"parameters": [
1965819663
{
1965919664
"schema": {
@@ -19696,7 +19701,7 @@
1969619701
],
1969719702
"responses": {
1969819703
"200": {
19699-
"description": "Default Response",
19704+
"description": "User configuration retrieved successfully",
1970019705
"content": {
1970119706
"application/json": {
1970219707
"schema": {
@@ -19773,7 +19778,8 @@
1977319778
"success",
1977419779
"data"
1977519780
],
19776-
"additionalProperties": false
19781+
"additionalProperties": false,
19782+
"description": "User configuration retrieved successfully"
1977719783
}
1977819784
}
1977919785
}

services/backend/api-spec.yaml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13360,7 +13360,7 @@ paths:
1336013360
installation belonging to the authenticated user. No Content-Type header
1336113361
required for this GET request. Supports both cookie-based authentication
1336213362
(for web users) and OAuth2 Bearer token authentication (for CLI users).
13363-
Requires mcp:read scope for OAuth2 access.
13363+
Requires mcp:user-configs:read scope for OAuth2 access.
1336413364
parameters:
1336513365
- schema:
1336613366
type: string
@@ -13536,6 +13536,14 @@ paths:
1353613536
description: Internal Server Error
1353713537
/api/teams/{teamId}/mcp/installations/{installationId}/user-configs/{configId}:
1353813538
get:
13539+
summary: Get user configuration by ID
13540+
tags:
13541+
- MCP User Configurations
13542+
description: Retrieves a specific user configuration for an MCP server
13543+
installation. No Content-Type header required for this GET request.
13544+
Supports both cookie-based authentication (for web users) and OAuth2
13545+
Bearer token authentication (for CLI users). Requires
13546+
mcp:user-configs:read scope for OAuth2 access.
1353913547
parameters:
1354013548
- schema:
1354113549
type: string
@@ -13563,7 +13571,7 @@ paths:
1356313571
- bearerAuth: []
1356413572
responses:
1356513573
"200":
13566-
description: Default Response
13574+
description: User configuration retrieved successfully
1356713575
content:
1356813576
application/json:
1356913577
schema:
@@ -13623,6 +13631,7 @@ paths:
1362313631
- success
1362413632
- data
1362513633
additionalProperties: false
13634+
description: User configuration retrieved successfully
1362613635
"400":
1362713636
description: Bad Request
1362813637
content:
Lines changed: 124 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,130 @@
1-
import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
2-
import { getUserConfigurationByIdSchema, GetUserConfigurationByIdRequest, formatUserConfigResponse } from './schemas';
3-
import { mcpUserConfigurationService } from '../../../services/mcpUserConfigurationService';
4-
import { authHook } from '../../../hooks/authHook';
5-
6-
export default async function getUserConfigurationRoute(fastify: FastifyInstance) {
7-
fastify.get<GetUserConfigurationByIdRequest>(
8-
'/teams/:teamId/mcp/installations/:installationId/user-configs/:configId',
9-
{
10-
schema: getUserConfigurationByIdSchema,
11-
preHandler: [authHook]
12-
},
13-
async (request: FastifyRequest<GetUserConfigurationByIdRequest>, reply: FastifyReply) => {
14-
const { teamId, installationId, configId } = request.params;
15-
const userId = request.user!.id;
16-
17-
try {
18-
// Get the user configuration
19-
const userConfig = await mcpUserConfigurationService.getUserConfigurationById(
20-
configId,
21-
userId,
22-
teamId
23-
);
24-
25-
if (!userConfig) {
26-
return reply.status(404).send({
27-
error: 'User configuration not found'
28-
});
29-
}
30-
31-
// Format and return the response
32-
const response = formatUserConfigResponse(userConfig);
33-
return reply.send(response);
34-
35-
} catch (error) {
36-
fastify.log.error({
37-
operation: 'get_user_configuration',
38-
error,
1+
import { type FastifyInstance } from 'fastify';
2+
import { requireAuthenticationAny, requireOAuthScope } from '../../../middleware/oauthMiddleware';
3+
import { requireTeamPermission } from '../../../middleware/roleMiddleware';
4+
import { McpUserConfigurationService } from '../../../services/mcpUserConfigurationService';
5+
import { getDb } from '../../../db';
6+
import {
7+
TEAM_AND_INSTALLATION_AND_CONFIG_PARAMS_SCHEMA,
8+
USER_CONFIG_SUCCESS_RESPONSE_SCHEMA,
9+
COMMON_ERROR_RESPONSES,
10+
DUAL_AUTH_SECURITY,
11+
formatUserConfigResponse,
12+
type TeamAndInstallationAndConfigParams,
13+
type UserConfigSuccessResponse,
14+
type ErrorResponse
15+
} from './schemas';
16+
17+
export default async function getUserConfigurationRoute(server: FastifyInstance) {
18+
server.get<{
19+
Params: TeamAndInstallationAndConfigParams;
20+
}>('/teams/:teamId/mcp/installations/:installationId/user-configs/:configId', {
21+
preValidation: [
22+
requireAuthenticationAny(),
23+
requireOAuthScope('mcp:user-configs:read'),
24+
requireTeamPermission('mcp.installations.view')
25+
],
26+
schema: {
27+
tags: ['MCP User Configurations'],
28+
summary: 'Get user configuration by ID',
29+
description: 'Retrieves a specific user configuration for an MCP server installation. No Content-Type header required for this GET request. Supports both cookie-based authentication (for web users) and OAuth2 Bearer token authentication (for CLI users). Requires mcp:user-configs:read scope for OAuth2 access.',
30+
security: DUAL_AUTH_SECURITY,
31+
32+
// Fastify validation schema
33+
params: TEAM_AND_INSTALLATION_AND_CONFIG_PARAMS_SCHEMA,
34+
35+
response: {
36+
200: {
37+
...USER_CONFIG_SUCCESS_RESPONSE_SCHEMA,
38+
description: 'User configuration retrieved successfully'
39+
},
40+
...COMMON_ERROR_RESPONSES
41+
}
42+
}
43+
}, async (request, reply) => {
44+
const { teamId, installationId, configId } = request.params;
45+
const userId = request.user!.id;
46+
const authType = request.tokenPayload ? 'oauth2' : 'cookie';
47+
48+
request.log.debug({
49+
operation: 'mcp_user_config_operation',
50+
userId,
51+
authType,
52+
clientId: request.tokenPayload?.clientId,
53+
scope: request.tokenPayload?.scope,
54+
endpoint: request.url
55+
}, 'Authentication method determined for MCP user configuration operation');
56+
57+
request.log.info({
58+
operation: 'get_mcp_user_config',
59+
teamId,
60+
installationId,
61+
configId,
62+
userId,
63+
authType
64+
}, 'Getting MCP user configuration');
65+
66+
try {
67+
const db = getDb();
68+
const userConfigService = new McpUserConfigurationService(db, request.log);
69+
70+
const userConfig = await userConfigService.getUserConfigurationById(
71+
configId,
72+
userId,
73+
teamId
74+
);
75+
76+
if (!userConfig) {
77+
request.log.warn({
78+
operation: 'get_mcp_user_config',
3979
teamId,
4080
installationId,
4181
configId,
42-
userId
43-
}, 'Error getting user configuration');
44-
return reply.status(500).send({
45-
error: 'Internal server error'
46-
});
82+
userId,
83+
found: false
84+
}, 'MCP user configuration not found');
85+
86+
const errorResponse: ErrorResponse = {
87+
success: false,
88+
error: 'User configuration not found'
89+
};
90+
const jsonString = JSON.stringify(errorResponse);
91+
return reply.status(404).type('application/json').send(jsonString);
4792
}
93+
94+
request.log.info({
95+
operation: 'get_mcp_user_config',
96+
teamId,
97+
installationId,
98+
configId,
99+
userId,
100+
authType
101+
}, 'Successfully retrieved MCP user configuration');
102+
103+
const successResponse: UserConfigSuccessResponse = {
104+
success: true,
105+
data: formatUserConfigResponse(userConfig)
106+
};
107+
const jsonString = JSON.stringify(successResponse);
108+
return reply.status(200).type('application/json').send(jsonString);
109+
110+
} catch (error) {
111+
request.log.error({
112+
operation: 'get_mcp_user_config',
113+
error,
114+
teamId,
115+
installationId,
116+
configId,
117+
userId
118+
}, 'Failed to retrieve MCP user configuration');
119+
120+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
121+
122+
const errorResponse: ErrorResponse = {
123+
success: false,
124+
error: errorMessage
125+
};
126+
const jsonString = JSON.stringify(errorResponse);
127+
return reply.status(500).type('application/json').send(jsonString);
48128
}
49-
);
129+
});
50130
}

services/backend/src/routes/mcp/user-configurations/list.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ export default async function listUserConfigsRoute(server: FastifyInstance) {
2020
}>('/teams/:teamId/mcp/installations/:installationId/user-configs', {
2121
preValidation: [
2222
requireAuthenticationAny(),
23-
requireOAuthScope('mcp:read'),
23+
requireOAuthScope('mcp:user-configs:read'),
2424
requireTeamPermission('mcp.installations.view')
2525
],
2626
schema: {
2727
tags: ['MCP User Configurations'],
2828
summary: 'List user configurations for MCP installation',
29-
description: 'Retrieves all user-specific configurations for an MCP server installation belonging to the authenticated user. No Content-Type header required for this GET request. Supports both cookie-based authentication (for web users) and OAuth2 Bearer token authentication (for CLI users). Requires mcp:read scope for OAuth2 access.',
29+
description: 'Retrieves all user-specific configurations for an MCP server installation belonging to the authenticated user. No Content-Type header required for this GET request. Supports both cookie-based authentication (for web users) and OAuth2 Bearer token authentication (for CLI users). Requires mcp:user-configs:read scope for OAuth2 access.',
3030
security: DUAL_AUTH_SECURITY,
3131

3232
// Fastify validation schema

services/backend/src/services/oauth/authorizationService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export class AuthorizationService {
6464
const allowedScopes = [
6565
'mcp:read',
6666
'mcp:categories:read',
67+
'mcp:user-configs:read',
6768
'account:read',
6869
'user:read',
6970
'teams:read',

0 commit comments

Comments
 (0)