@dxheroes/local-mcp-backend 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/AGENTS.md +4 -0
- package/CHANGELOG.md +32 -0
- package/dist/app.module.js +5 -0
- package/dist/app.module.js.map +1 -1
- package/dist/modules/profiles/profiles.service.js +15 -0
- package/dist/modules/profiles/profiles.service.js.map +1 -1
- package/dist/modules/proxy/proxy.controller.js +258 -9
- package/dist/modules/proxy/proxy.controller.js.map +1 -1
- package/dist/modules/proxy/proxy.module.js +4 -1
- package/dist/modules/proxy/proxy.module.js.map +1 -1
- package/dist/modules/settings/settings.constants.js +18 -0
- package/dist/modules/settings/settings.constants.js.map +1 -0
- package/dist/modules/settings/settings.controller.js +89 -0
- package/dist/modules/settings/settings.controller.js.map +1 -0
- package/dist/modules/settings/settings.module.js +30 -0
- package/dist/modules/settings/settings.module.js.map +1 -0
- package/dist/modules/settings/settings.service.js +110 -0
- package/dist/modules/settings/settings.service.js.map +1 -0
- package/package.json +6 -5
- package/src/AGENTS.md +23 -0
- package/src/app.module.ts +6 -0
- package/src/common/AGENTS.md +19 -0
- package/src/config/AGENTS.md +17 -0
- package/src/modules/AGENTS.md +31 -0
- package/src/modules/database/AGENTS.md +30 -0
- package/src/modules/debug/AGENTS.md +30 -0
- package/src/modules/health/AGENTS.md +22 -0
- package/src/modules/mcp/AGENTS.md +38 -0
- package/src/modules/oauth/AGENTS.md +32 -0
- package/src/modules/profiles/AGENTS.md +33 -0
- package/src/modules/profiles/profiles.service.ts +19 -0
- package/src/modules/proxy/AGENTS.md +34 -0
- package/src/modules/proxy/proxy.controller.ts +249 -7
- package/src/modules/proxy/proxy.module.ts +3 -1
- package/src/modules/settings/AGENTS.md +31 -0
- package/src/modules/settings/settings.constants.ts +20 -0
- package/src/modules/settings/settings.controller.ts +47 -0
- package/src/modules/settings/settings.module.ts +16 -0
- package/src/modules/settings/settings.service.ts +99 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/modules/proxy/proxy.module.ts"],"sourcesContent":["/**\n * Proxy Module\n *\n * Handles MCP proxy endpoints for profiles.\n */\n\nimport { Module } from '@nestjs/common';\nimport { DebugModule } from '../debug/debug.module.js';\nimport { McpModule } from '../mcp/mcp.module.js';\nimport { ProxyController } from './proxy.controller.js';\nimport { ProxyService } from './proxy.service.js';\n\n@Module({\n imports: [McpModule, DebugModule],\n controllers: [ProxyController],\n providers: [ProxyService],\n exports: [ProxyService],\n})\nexport class ProxyModule {}\n"],"names":["Module","DebugModule","McpModule","ProxyController","ProxyService","ProxyModule","imports","controllers","providers","exports"],"mappings":";;;;;;AAAA
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/proxy/proxy.module.ts"],"sourcesContent":["/**\n * Proxy Module\n *\n * Handles MCP proxy endpoints for profiles.\n * Supports SSE notifications for MCP Streamable HTTP transport.\n */\n\nimport { Module } from '@nestjs/common';\nimport { DebugModule } from '../debug/debug.module.js';\nimport { McpModule } from '../mcp/mcp.module.js';\nimport { SettingsModule } from '../settings/settings.module.js';\nimport { ProxyController } from './proxy.controller.js';\nimport { ProxyService } from './proxy.service.js';\n\n@Module({\n imports: [McpModule, DebugModule, SettingsModule],\n controllers: [ProxyController],\n providers: [ProxyService],\n exports: [ProxyService],\n})\nexport class ProxyModule {}\n"],"names":["Module","DebugModule","McpModule","SettingsModule","ProxyController","ProxyService","ProxyModule","imports","controllers","providers","exports"],"mappings":";;;;;;AAAA;;;;;CAKC,GAED,SAASA,MAAM,QAAQ,iBAAiB;AACxC,SAASC,WAAW,QAAQ,2BAA2B;AACvD,SAASC,SAAS,QAAQ,uBAAuB;AACjD,SAASC,cAAc,QAAQ,iCAAiC;AAChE,SAASC,eAAe,QAAQ,wBAAwB;AACxD,SAASC,YAAY,QAAQ,qBAAqB;AAQlD,OAAO,MAAMC;AAAa;;;QALxBC,SAAS;YAACL;YAAWD;YAAaE;SAAe;QACjDK,aAAa;YAACJ;SAAgB;QAC9BK,WAAW;YAACJ;SAAa;QACzBK,SAAS;YAACL;SAAa"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings Constants
|
|
3
|
+
*
|
|
4
|
+
* Defines setting keys, defaults, and reserved profile names.
|
|
5
|
+
*/ // Setting keys
|
|
6
|
+
export const SETTING_KEYS = {
|
|
7
|
+
DEFAULT_GATEWAY_PROFILE: 'default_gateway_profile'
|
|
8
|
+
};
|
|
9
|
+
// Default values for settings
|
|
10
|
+
export const SETTING_DEFAULTS = {
|
|
11
|
+
[SETTING_KEYS.DEFAULT_GATEWAY_PROFILE]: 'default'
|
|
12
|
+
};
|
|
13
|
+
// Reserved profile names that cannot be created by users
|
|
14
|
+
export const RESERVED_PROFILE_NAMES = [
|
|
15
|
+
'gateway'
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=settings.constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/settings/settings.constants.ts"],"sourcesContent":["/**\n * Settings Constants\n *\n * Defines setting keys, defaults, and reserved profile names.\n */\n\n// Setting keys\nexport const SETTING_KEYS = {\n DEFAULT_GATEWAY_PROFILE: 'default_gateway_profile',\n} as const;\n\n// Default values for settings\nexport const SETTING_DEFAULTS: Record<string, string> = {\n [SETTING_KEYS.DEFAULT_GATEWAY_PROFILE]: 'default',\n};\n\n// Reserved profile names that cannot be created by users\nexport const RESERVED_PROFILE_NAMES = ['gateway'] as const;\n\nexport type SettingKey = (typeof SETTING_KEYS)[keyof typeof SETTING_KEYS];\n"],"names":["SETTING_KEYS","DEFAULT_GATEWAY_PROFILE","SETTING_DEFAULTS","RESERVED_PROFILE_NAMES"],"mappings":"AAAA;;;;CAIC,GAED,eAAe;AACf,OAAO,MAAMA,eAAe;IAC1BC,yBAAyB;AAC3B,EAAW;AAEX,8BAA8B;AAC9B,OAAO,MAAMC,mBAA2C;IACtD,CAACF,aAAaC,uBAAuB,CAAC,EAAE;AAC1C,EAAE;AAEF,yDAAyD;AACzD,OAAO,MAAME,yBAAyB;IAAC;CAAU,CAAU"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
}
|
|
7
|
+
function _ts_metadata(k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
}
|
|
10
|
+
function _ts_param(paramIndex, decorator) {
|
|
11
|
+
return function(target, key) {
|
|
12
|
+
decorator(target, key, paramIndex);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Settings Controller
|
|
17
|
+
*
|
|
18
|
+
* REST API endpoints for gateway settings management.
|
|
19
|
+
*/ import { Body, Controller, Get, Put } from "@nestjs/common";
|
|
20
|
+
import { IsNotEmpty, IsString, MaxLength } from "class-validator";
|
|
21
|
+
import { SettingsService } from "./settings.service.js";
|
|
22
|
+
export class UpdateDefaultGatewayProfileDto {
|
|
23
|
+
}
|
|
24
|
+
_ts_decorate([
|
|
25
|
+
IsString(),
|
|
26
|
+
IsNotEmpty({
|
|
27
|
+
message: 'Profile name cannot be empty'
|
|
28
|
+
}),
|
|
29
|
+
MaxLength(100, {
|
|
30
|
+
message: 'Profile name must be at most 100 characters'
|
|
31
|
+
}),
|
|
32
|
+
_ts_metadata("design:type", String)
|
|
33
|
+
], UpdateDefaultGatewayProfileDto.prototype, "profileName", void 0);
|
|
34
|
+
export class SettingsController {
|
|
35
|
+
constructor(settingsService){
|
|
36
|
+
this.settingsService = settingsService;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get all gateway settings
|
|
40
|
+
*/ async getAllSettings() {
|
|
41
|
+
return this.settingsService.getAllSettings();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the default gateway profile setting
|
|
45
|
+
*/ async getDefaultGatewayProfile() {
|
|
46
|
+
const profileName = await this.settingsService.getDefaultGatewayProfile();
|
|
47
|
+
return {
|
|
48
|
+
profileName
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Set the default gateway profile
|
|
53
|
+
*/ async setDefaultGatewayProfile(dto) {
|
|
54
|
+
await this.settingsService.setDefaultGatewayProfile(dto.profileName);
|
|
55
|
+
return {
|
|
56
|
+
profileName: dto.profileName
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
_ts_decorate([
|
|
61
|
+
Get(),
|
|
62
|
+
_ts_metadata("design:type", Function),
|
|
63
|
+
_ts_metadata("design:paramtypes", []),
|
|
64
|
+
_ts_metadata("design:returntype", Promise)
|
|
65
|
+
], SettingsController.prototype, "getAllSettings", null);
|
|
66
|
+
_ts_decorate([
|
|
67
|
+
Get('default-gateway-profile'),
|
|
68
|
+
_ts_metadata("design:type", Function),
|
|
69
|
+
_ts_metadata("design:paramtypes", []),
|
|
70
|
+
_ts_metadata("design:returntype", Promise)
|
|
71
|
+
], SettingsController.prototype, "getDefaultGatewayProfile", null);
|
|
72
|
+
_ts_decorate([
|
|
73
|
+
Put('default-gateway-profile'),
|
|
74
|
+
_ts_param(0, Body()),
|
|
75
|
+
_ts_metadata("design:type", Function),
|
|
76
|
+
_ts_metadata("design:paramtypes", [
|
|
77
|
+
typeof UpdateDefaultGatewayProfileDto === "undefined" ? Object : UpdateDefaultGatewayProfileDto
|
|
78
|
+
]),
|
|
79
|
+
_ts_metadata("design:returntype", Promise)
|
|
80
|
+
], SettingsController.prototype, "setDefaultGatewayProfile", null);
|
|
81
|
+
SettingsController = _ts_decorate([
|
|
82
|
+
Controller('settings'),
|
|
83
|
+
_ts_metadata("design:type", Function),
|
|
84
|
+
_ts_metadata("design:paramtypes", [
|
|
85
|
+
typeof SettingsService === "undefined" ? Object : SettingsService
|
|
86
|
+
])
|
|
87
|
+
], SettingsController);
|
|
88
|
+
|
|
89
|
+
//# sourceMappingURL=settings.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/settings/settings.controller.ts"],"sourcesContent":["/**\n * Settings Controller\n *\n * REST API endpoints for gateway settings management.\n */\n\nimport { Body, Controller, Get, Put } from '@nestjs/common';\nimport { IsNotEmpty, IsString, MaxLength } from 'class-validator';\nimport { SettingsService } from './settings.service.js';\n\nexport class UpdateDefaultGatewayProfileDto {\n @IsString()\n @IsNotEmpty({ message: 'Profile name cannot be empty' })\n @MaxLength(100, { message: 'Profile name must be at most 100 characters' })\n profileName: string;\n}\n\n@Controller('settings')\nexport class SettingsController {\n constructor(private readonly settingsService: SettingsService) {}\n\n /**\n * Get all gateway settings\n */\n @Get()\n async getAllSettings() {\n return this.settingsService.getAllSettings();\n }\n\n /**\n * Get the default gateway profile setting\n */\n @Get('default-gateway-profile')\n async getDefaultGatewayProfile() {\n const profileName = await this.settingsService.getDefaultGatewayProfile();\n return { profileName };\n }\n\n /**\n * Set the default gateway profile\n */\n @Put('default-gateway-profile')\n async setDefaultGatewayProfile(@Body() dto: UpdateDefaultGatewayProfileDto) {\n await this.settingsService.setDefaultGatewayProfile(dto.profileName);\n return { profileName: dto.profileName };\n }\n}\n"],"names":["Body","Controller","Get","Put","IsNotEmpty","IsString","MaxLength","SettingsService","UpdateDefaultGatewayProfileDto","message","SettingsController","settingsService","getAllSettings","getDefaultGatewayProfile","profileName","setDefaultGatewayProfile","dto"],"mappings":";;;;;;;;;;;;;;AAAA;;;;CAIC,GAED,SAASA,IAAI,EAAEC,UAAU,EAAEC,GAAG,EAAEC,GAAG,QAAQ,iBAAiB;AAC5D,SAASC,UAAU,EAAEC,QAAQ,EAAEC,SAAS,QAAQ,kBAAkB;AAClE,SAASC,eAAe,QAAQ,wBAAwB;AAExD,OAAO,MAAMC;AAKb;;;;QAHgBC,SAAS;;;QACLA,SAAS;;;;AAK7B,OAAO,MAAMC;IACX,YAAY,AAAiBC,eAAgC,CAAE;aAAlCA,kBAAAA;IAAmC;IAEhE;;GAEC,GACD,MACMC,iBAAiB;QACrB,OAAO,IAAI,CAACD,eAAe,CAACC,cAAc;IAC5C;IAEA;;GAEC,GACD,MACMC,2BAA2B;QAC/B,MAAMC,cAAc,MAAM,IAAI,CAACH,eAAe,CAACE,wBAAwB;QACvE,OAAO;YAAEC;QAAY;IACvB;IAEA;;GAEC,GACD,MACMC,yBAAyB,AAAQC,GAAmC,EAAE;QAC1E,MAAM,IAAI,CAACL,eAAe,CAACI,wBAAwB,CAACC,IAAIF,WAAW;QACnE,OAAO;YAAEA,aAAaE,IAAIF,WAAW;QAAC;IACxC;AACF"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Settings Module
|
|
9
|
+
*
|
|
10
|
+
* Handles gateway configuration settings.
|
|
11
|
+
*/ import { Module } from "@nestjs/common";
|
|
12
|
+
import { SettingsController } from "./settings.controller.js";
|
|
13
|
+
import { SettingsService } from "./settings.service.js";
|
|
14
|
+
export class SettingsModule {
|
|
15
|
+
}
|
|
16
|
+
SettingsModule = _ts_decorate([
|
|
17
|
+
Module({
|
|
18
|
+
controllers: [
|
|
19
|
+
SettingsController
|
|
20
|
+
],
|
|
21
|
+
providers: [
|
|
22
|
+
SettingsService
|
|
23
|
+
],
|
|
24
|
+
exports: [
|
|
25
|
+
SettingsService
|
|
26
|
+
]
|
|
27
|
+
})
|
|
28
|
+
], SettingsModule);
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=settings.module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/settings/settings.module.ts"],"sourcesContent":["/**\n * Settings Module\n *\n * Handles gateway configuration settings.\n */\n\nimport { Module } from '@nestjs/common';\nimport { SettingsController } from './settings.controller.js';\nimport { SettingsService } from './settings.service.js';\n\n@Module({\n controllers: [SettingsController],\n providers: [SettingsService],\n exports: [SettingsService],\n})\nexport class SettingsModule {}\n"],"names":["Module","SettingsController","SettingsService","SettingsModule","controllers","providers","exports"],"mappings":";;;;;;AAAA;;;;CAIC,GAED,SAASA,MAAM,QAAQ,iBAAiB;AACxC,SAASC,kBAAkB,QAAQ,2BAA2B;AAC9D,SAASC,eAAe,QAAQ,wBAAwB;AAOxD,OAAO,MAAMC;AAAgB;;;QAJ3BC,aAAa;YAACH;SAAmB;QACjCI,WAAW;YAACH;SAAgB;QAC5BI,SAAS;YAACJ;SAAgB"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
}
|
|
7
|
+
function _ts_metadata(k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Settings Service
|
|
12
|
+
*
|
|
13
|
+
* Business logic for gateway settings management.
|
|
14
|
+
* Emits events when gateway settings change for SSE notifications.
|
|
15
|
+
*/ import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
|
16
|
+
import { EventEmitter2 } from "@nestjs/event-emitter";
|
|
17
|
+
import { PrismaService } from "../database/prisma.service.js";
|
|
18
|
+
import { SETTING_DEFAULTS, SETTING_KEYS } from "./settings.constants.js";
|
|
19
|
+
/** Event name for gateway profile changes */ export const GATEWAY_PROFILE_CHANGED = 'gateway.profile.changed';
|
|
20
|
+
export class SettingsService {
|
|
21
|
+
constructor(prisma, eventEmitter){
|
|
22
|
+
this.prisma = prisma;
|
|
23
|
+
this.eventEmitter = eventEmitter;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Get a setting value by key, returns default if not set
|
|
27
|
+
*/ async getSetting(key) {
|
|
28
|
+
const setting = await this.prisma.gatewaySetting.findUnique({
|
|
29
|
+
where: {
|
|
30
|
+
key
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return setting?.value ?? SETTING_DEFAULTS[key];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Set a setting value
|
|
37
|
+
*/ async setSetting(key, value) {
|
|
38
|
+
const setting = await this.prisma.gatewaySetting.upsert({
|
|
39
|
+
where: {
|
|
40
|
+
key
|
|
41
|
+
},
|
|
42
|
+
update: {
|
|
43
|
+
value
|
|
44
|
+
},
|
|
45
|
+
create: {
|
|
46
|
+
key,
|
|
47
|
+
value
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
return {
|
|
51
|
+
key: setting.key,
|
|
52
|
+
value: setting.value
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get the default gateway profile name
|
|
57
|
+
*/ async getDefaultGatewayProfile() {
|
|
58
|
+
return this.getSetting(SETTING_KEYS.DEFAULT_GATEWAY_PROFILE);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Set the default gateway profile
|
|
62
|
+
* Validates that the profile exists before setting.
|
|
63
|
+
* Emits GATEWAY_PROFILE_CHANGED event for SSE subscribers.
|
|
64
|
+
*/ async setDefaultGatewayProfile(profileName) {
|
|
65
|
+
// Input sanitization
|
|
66
|
+
const trimmedName = profileName?.trim();
|
|
67
|
+
if (!trimmedName) {
|
|
68
|
+
throw new BadRequestException('Profile name cannot be empty');
|
|
69
|
+
}
|
|
70
|
+
// Validate that profile exists
|
|
71
|
+
const profile = await this.prisma.profile.findUnique({
|
|
72
|
+
where: {
|
|
73
|
+
name: trimmedName
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
if (!profile) {
|
|
77
|
+
throw new NotFoundException(`Profile "${trimmedName}" not found`);
|
|
78
|
+
}
|
|
79
|
+
const result = await this.setSetting(SETTING_KEYS.DEFAULT_GATEWAY_PROFILE, trimmedName);
|
|
80
|
+
// Emit event for SSE subscribers (MCP Streamable HTTP notifications)
|
|
81
|
+
this.eventEmitter.emit(GATEWAY_PROFILE_CHANGED, {
|
|
82
|
+
profileName: trimmedName
|
|
83
|
+
});
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get all settings with their current values
|
|
88
|
+
*/ async getAllSettings() {
|
|
89
|
+
const settings = await this.prisma.gatewaySetting.findMany();
|
|
90
|
+
// Start with defaults
|
|
91
|
+
const result = {
|
|
92
|
+
...SETTING_DEFAULTS
|
|
93
|
+
};
|
|
94
|
+
// Override with stored values
|
|
95
|
+
for (const setting of settings){
|
|
96
|
+
result[setting.key] = setting.value;
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
SettingsService = _ts_decorate([
|
|
102
|
+
Injectable(),
|
|
103
|
+
_ts_metadata("design:type", Function),
|
|
104
|
+
_ts_metadata("design:paramtypes", [
|
|
105
|
+
typeof PrismaService === "undefined" ? Object : PrismaService,
|
|
106
|
+
typeof EventEmitter2 === "undefined" ? Object : EventEmitter2
|
|
107
|
+
])
|
|
108
|
+
], SettingsService);
|
|
109
|
+
|
|
110
|
+
//# sourceMappingURL=settings.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/settings/settings.service.ts"],"sourcesContent":["/**\n * Settings Service\n *\n * Business logic for gateway settings management.\n * Emits events when gateway settings change for SSE notifications.\n */\n\nimport { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';\nimport { EventEmitter2 } from '@nestjs/event-emitter';\nimport { PrismaService } from '../database/prisma.service.js';\nimport { SETTING_DEFAULTS, SETTING_KEYS, type SettingKey } from './settings.constants.js';\n\n/** Event name for gateway profile changes */\nexport const GATEWAY_PROFILE_CHANGED = 'gateway.profile.changed';\n\n@Injectable()\nexport class SettingsService {\n constructor(\n private readonly prisma: PrismaService,\n private readonly eventEmitter: EventEmitter2\n ) {}\n\n /**\n * Get a setting value by key, returns default if not set\n */\n async getSetting(key: SettingKey): Promise<string> {\n const setting = await this.prisma.gatewaySetting.findUnique({\n where: { key },\n });\n\n return setting?.value ?? SETTING_DEFAULTS[key];\n }\n\n /**\n * Set a setting value\n */\n async setSetting(key: SettingKey, value: string): Promise<{ key: string; value: string }> {\n const setting = await this.prisma.gatewaySetting.upsert({\n where: { key },\n update: { value },\n create: { key, value },\n });\n\n return { key: setting.key, value: setting.value };\n }\n\n /**\n * Get the default gateway profile name\n */\n async getDefaultGatewayProfile(): Promise<string> {\n return this.getSetting(SETTING_KEYS.DEFAULT_GATEWAY_PROFILE);\n }\n\n /**\n * Set the default gateway profile\n * Validates that the profile exists before setting.\n * Emits GATEWAY_PROFILE_CHANGED event for SSE subscribers.\n */\n async setDefaultGatewayProfile(profileName: string): Promise<{ key: string; value: string }> {\n // Input sanitization\n const trimmedName = profileName?.trim();\n if (!trimmedName) {\n throw new BadRequestException('Profile name cannot be empty');\n }\n\n // Validate that profile exists\n const profile = await this.prisma.profile.findUnique({\n where: { name: trimmedName },\n });\n\n if (!profile) {\n throw new NotFoundException(`Profile \"${trimmedName}\" not found`);\n }\n\n const result = await this.setSetting(SETTING_KEYS.DEFAULT_GATEWAY_PROFILE, trimmedName);\n\n // Emit event for SSE subscribers (MCP Streamable HTTP notifications)\n this.eventEmitter.emit(GATEWAY_PROFILE_CHANGED, { profileName: trimmedName });\n\n return result;\n }\n\n /**\n * Get all settings with their current values\n */\n async getAllSettings(): Promise<Record<string, string>> {\n const settings = await this.prisma.gatewaySetting.findMany();\n\n // Start with defaults\n const result: Record<string, string> = { ...SETTING_DEFAULTS };\n\n // Override with stored values\n for (const setting of settings) {\n result[setting.key] = setting.value;\n }\n\n return result;\n }\n}\n"],"names":["BadRequestException","Injectable","NotFoundException","EventEmitter2","PrismaService","SETTING_DEFAULTS","SETTING_KEYS","GATEWAY_PROFILE_CHANGED","SettingsService","prisma","eventEmitter","getSetting","key","setting","gatewaySetting","findUnique","where","value","setSetting","upsert","update","create","getDefaultGatewayProfile","DEFAULT_GATEWAY_PROFILE","setDefaultGatewayProfile","profileName","trimmedName","trim","profile","name","result","emit","getAllSettings","settings","findMany"],"mappings":";;;;;;;;;AAAA;;;;;CAKC,GAED,SAASA,mBAAmB,EAAEC,UAAU,EAAEC,iBAAiB,QAAQ,iBAAiB;AACpF,SAASC,aAAa,QAAQ,wBAAwB;AACtD,SAASC,aAAa,QAAQ,gCAAgC;AAC9D,SAASC,gBAAgB,EAAEC,YAAY,QAAyB,0BAA0B;AAE1F,2CAA2C,GAC3C,OAAO,MAAMC,0BAA0B,0BAA0B;AAGjE,OAAO,MAAMC;IACX,YACE,AAAiBC,MAAqB,EACtC,AAAiBC,YAA2B,CAC5C;aAFiBD,SAAAA;aACAC,eAAAA;IAChB;IAEH;;GAEC,GACD,MAAMC,WAAWC,GAAe,EAAmB;QACjD,MAAMC,UAAU,MAAM,IAAI,CAACJ,MAAM,CAACK,cAAc,CAACC,UAAU,CAAC;YAC1DC,OAAO;gBAAEJ;YAAI;QACf;QAEA,OAAOC,SAASI,SAASZ,gBAAgB,CAACO,IAAI;IAChD;IAEA;;GAEC,GACD,MAAMM,WAAWN,GAAe,EAAEK,KAAa,EAA2C;QACxF,MAAMJ,UAAU,MAAM,IAAI,CAACJ,MAAM,CAACK,cAAc,CAACK,MAAM,CAAC;YACtDH,OAAO;gBAAEJ;YAAI;YACbQ,QAAQ;gBAAEH;YAAM;YAChBI,QAAQ;gBAAET;gBAAKK;YAAM;QACvB;QAEA,OAAO;YAAEL,KAAKC,QAAQD,GAAG;YAAEK,OAAOJ,QAAQI,KAAK;QAAC;IAClD;IAEA;;GAEC,GACD,MAAMK,2BAA4C;QAChD,OAAO,IAAI,CAACX,UAAU,CAACL,aAAaiB,uBAAuB;IAC7D;IAEA;;;;GAIC,GACD,MAAMC,yBAAyBC,WAAmB,EAA2C;QAC3F,qBAAqB;QACrB,MAAMC,cAAcD,aAAaE;QACjC,IAAI,CAACD,aAAa;YAChB,MAAM,IAAI1B,oBAAoB;QAChC;QAEA,+BAA+B;QAC/B,MAAM4B,UAAU,MAAM,IAAI,CAACnB,MAAM,CAACmB,OAAO,CAACb,UAAU,CAAC;YACnDC,OAAO;gBAAEa,MAAMH;YAAY;QAC7B;QAEA,IAAI,CAACE,SAAS;YACZ,MAAM,IAAI1B,kBAAkB,CAAC,SAAS,EAAEwB,YAAY,WAAW,CAAC;QAClE;QAEA,MAAMI,SAAS,MAAM,IAAI,CAACZ,UAAU,CAACZ,aAAaiB,uBAAuB,EAAEG;QAE3E,qEAAqE;QACrE,IAAI,CAAChB,YAAY,CAACqB,IAAI,CAACxB,yBAAyB;YAAEkB,aAAaC;QAAY;QAE3E,OAAOI;IACT;IAEA;;GAEC,GACD,MAAME,iBAAkD;QACtD,MAAMC,WAAW,MAAM,IAAI,CAACxB,MAAM,CAACK,cAAc,CAACoB,QAAQ;QAE1D,sBAAsB;QACtB,MAAMJ,SAAiC;YAAE,GAAGzB,gBAAgB;QAAC;QAE7D,8BAA8B;QAC9B,KAAK,MAAMQ,WAAWoB,SAAU;YAC9BH,MAAM,CAACjB,QAAQD,GAAG,CAAC,GAAGC,QAAQI,KAAK;QACrC;QAEA,OAAOa;IACT;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxheroes/local-mcp-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "NestJS API server providing MCP proxy, server aggregation, OAuth 2.1, and profile management",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"@nestjs/common": "^11.1.11",
|
|
11
11
|
"@nestjs/config": "^4.0.2",
|
|
12
12
|
"@nestjs/core": "^11.1.11",
|
|
13
|
+
"@nestjs/event-emitter": "^3.0.1",
|
|
13
14
|
"@nestjs/platform-express": "^11.1.11",
|
|
14
15
|
"@nestjs/throttler": "^6.5.0",
|
|
15
16
|
"class-transformer": "^0.5.1",
|
|
@@ -19,9 +20,9 @@
|
|
|
19
20
|
"reflect-metadata": "^0.2.2",
|
|
20
21
|
"rxjs": "^7.8.2",
|
|
21
22
|
"zod": "^4.3.5",
|
|
22
|
-
"@dxheroes/local-mcp-core": "0.
|
|
23
|
-
"@dxheroes/mcp-gemini-deep-research": "0.
|
|
24
|
-
"@dxheroes/local-mcp-database": "0.
|
|
23
|
+
"@dxheroes/local-mcp-core": "0.4.0",
|
|
24
|
+
"@dxheroes/mcp-gemini-deep-research": "0.4.0",
|
|
25
|
+
"@dxheroes/local-mcp-database": "0.4.0"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"@nestjs/cli": "^11.0.14",
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
"@types/node": "^25.0.6",
|
|
35
36
|
"typescript": "^5.9.3",
|
|
36
37
|
"vitest": "^4.0.17",
|
|
37
|
-
"@dxheroes/local-mcp-config": "0.
|
|
38
|
+
"@dxheroes/local-mcp-config": "0.4.0"
|
|
38
39
|
},
|
|
39
40
|
"scripts": {
|
|
40
41
|
"build": "nest build",
|
package/src/AGENTS.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Backend Source Directory
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Root source directory for the NestJS backend application. Contains the main entry point, app module, configuration, common utilities, and all feature modules.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- `main.ts` - NestJS bootstrap and server initialization
|
|
10
|
+
- `app.module.ts` - Root module that imports all feature modules
|
|
11
|
+
|
|
12
|
+
## Subdirectories
|
|
13
|
+
|
|
14
|
+
- **[config/](config/AGENTS.md)** - Application and database configuration
|
|
15
|
+
- **[common/](common/AGENTS.md)** - Shared utilities (filters, interceptors, decorators, pipes)
|
|
16
|
+
- **[modules/](modules/AGENTS.md)** - Feature modules (mcp, profiles, proxy, oauth, etc.)
|
|
17
|
+
|
|
18
|
+
## Key Concepts
|
|
19
|
+
|
|
20
|
+
- NestJS follows modular architecture with dependency injection
|
|
21
|
+
- Each feature has its own module with controller, service, and DTOs
|
|
22
|
+
- Global modules (database) are imported in app.module.ts
|
|
23
|
+
- Configuration is loaded via @nestjs/config
|
package/src/app.module.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { Module } from '@nestjs/common';
|
|
9
9
|
import { ConfigModule } from '@nestjs/config';
|
|
10
|
+
import { EventEmitterModule } from '@nestjs/event-emitter';
|
|
10
11
|
import { ThrottlerModule } from '@nestjs/throttler';
|
|
11
12
|
import appConfig from './config/app.config.js';
|
|
12
13
|
import databaseConfig from './config/database.config.js';
|
|
@@ -17,6 +18,7 @@ import { McpModule } from './modules/mcp/mcp.module.js';
|
|
|
17
18
|
import { OAuthModule } from './modules/oauth/oauth.module.js';
|
|
18
19
|
import { ProfilesModule } from './modules/profiles/profiles.module.js';
|
|
19
20
|
import { ProxyModule } from './modules/proxy/proxy.module.js';
|
|
21
|
+
import { SettingsModule } from './modules/settings/settings.module.js';
|
|
20
22
|
|
|
21
23
|
@Module({
|
|
22
24
|
imports: [
|
|
@@ -27,6 +29,9 @@ import { ProxyModule } from './modules/proxy/proxy.module.js';
|
|
|
27
29
|
envFilePath: ['../../.env', '.env.local', '.env'],
|
|
28
30
|
}),
|
|
29
31
|
|
|
32
|
+
// Event emitter for SSE notifications
|
|
33
|
+
EventEmitterModule.forRoot(),
|
|
34
|
+
|
|
30
35
|
// Rate limiting
|
|
31
36
|
ThrottlerModule.forRoot([
|
|
32
37
|
{
|
|
@@ -51,6 +56,7 @@ import { ProxyModule } from './modules/proxy/proxy.module.js';
|
|
|
51
56
|
McpModule,
|
|
52
57
|
ProfilesModule,
|
|
53
58
|
OAuthModule, // For OAuth MCP servers, not user authentication
|
|
59
|
+
SettingsModule, // Gateway settings
|
|
54
60
|
ProxyModule,
|
|
55
61
|
HealthModule,
|
|
56
62
|
DebugModule,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Common Directory
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Shared utilities and cross-cutting concerns for the NestJS backend. Contains reusable decorators, filters, interceptors, and pipes.
|
|
6
|
+
|
|
7
|
+
## Subdirectories
|
|
8
|
+
|
|
9
|
+
- `decorators/` - Custom decorators for route handlers
|
|
10
|
+
- `filters/` - Exception filters for error handling
|
|
11
|
+
- `interceptors/` - Request/response interceptors (logging, timeout)
|
|
12
|
+
- `pipes/` - Validation pipes for input transformation
|
|
13
|
+
|
|
14
|
+
## Key Concepts
|
|
15
|
+
|
|
16
|
+
- Common utilities are used across all modules
|
|
17
|
+
- Filters handle uncaught exceptions globally
|
|
18
|
+
- Interceptors can modify request/response flow
|
|
19
|
+
- Pipes validate and transform incoming data
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Config Directory
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Application configuration files using @nestjs/config. Provides type-safe configuration for the NestJS backend.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- `app.config.ts` - General application configuration (port, environment)
|
|
10
|
+
- `database.config.ts` - Database/Prisma configuration (SQLite path)
|
|
11
|
+
|
|
12
|
+
## Key Concepts
|
|
13
|
+
|
|
14
|
+
- Configuration is loaded at application startup
|
|
15
|
+
- Uses environment variables with defaults
|
|
16
|
+
- Database path defaults to `~/.local-mcp-gateway-data/local-mcp-gateway.db`
|
|
17
|
+
- Configuration is injected via ConfigService
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Modules Directory
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
NestJS feature modules organized by domain. Each module encapsulates related functionality with its own controller, service, and DTOs.
|
|
6
|
+
|
|
7
|
+
## Subdirectories
|
|
8
|
+
|
|
9
|
+
- **[database/](database/AGENTS.md)** - Prisma database service (global module)
|
|
10
|
+
- **[debug/](debug/AGENTS.md)** - Debug logging for MCP traffic
|
|
11
|
+
- **[health/](health/AGENTS.md)** - Health check endpoints
|
|
12
|
+
- **[mcp/](mcp/AGENTS.md)** - MCP server management, discovery, and registry
|
|
13
|
+
- **[oauth/](oauth/AGENTS.md)** - OAuth 2.1 authentication for MCP servers
|
|
14
|
+
- **[profiles/](profiles/AGENTS.md)** - Profile CRUD operations
|
|
15
|
+
- **[proxy/](proxy/AGENTS.md)** - MCP proxy endpoints (HTTP/SSE)
|
|
16
|
+
- **[settings/](settings/AGENTS.md)** - Application settings management
|
|
17
|
+
|
|
18
|
+
## Module Structure Pattern
|
|
19
|
+
|
|
20
|
+
Each module typically contains:
|
|
21
|
+
- `*.module.ts` - Module definition with imports/providers/controllers
|
|
22
|
+
- `*.controller.ts` - REST API endpoints
|
|
23
|
+
- `*.service.ts` - Business logic and data access
|
|
24
|
+
- `dto/` - Data transfer objects (optional)
|
|
25
|
+
|
|
26
|
+
## Key Concepts
|
|
27
|
+
|
|
28
|
+
- Modules are self-contained units with clear boundaries
|
|
29
|
+
- Services use Prisma for database access
|
|
30
|
+
- Controllers handle HTTP requests and validation
|
|
31
|
+
- Dependency injection connects all components
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Database Module
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Global database module providing Prisma ORM access to all other modules. Handles SQLite database connection and lifecycle.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- `database.module.ts` - Global module definition
|
|
10
|
+
- `prisma.service.ts` - Prisma client wrapper with lifecycle hooks
|
|
11
|
+
|
|
12
|
+
## Key Concepts
|
|
13
|
+
|
|
14
|
+
- **Global Module**: Imported once in AppModule, available everywhere
|
|
15
|
+
- **PrismaService**: Extends PrismaClient with NestJS lifecycle integration
|
|
16
|
+
- **Connection Management**: Handles connect/disconnect on app start/stop
|
|
17
|
+
- **SQLite**: Default database stored in `~/.local-mcp-gateway-data/`
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
@Injectable()
|
|
23
|
+
export class MyService {
|
|
24
|
+
constructor(private readonly prisma: PrismaService) {}
|
|
25
|
+
|
|
26
|
+
async findAll() {
|
|
27
|
+
return this.prisma.myModel.findMany();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Debug Module
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Debug logging module for capturing and querying MCP traffic. Records all requests/responses between AI clients and MCP servers.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- `debug.module.ts` - Module definition
|
|
10
|
+
- `debug.controller.ts` - REST API for debug log queries
|
|
11
|
+
- `debug.service.ts` - Debug log storage and retrieval
|
|
12
|
+
|
|
13
|
+
## Key Endpoints
|
|
14
|
+
|
|
15
|
+
- `GET /api/debug/logs` - Query debug logs with filters
|
|
16
|
+
- `DELETE /api/debug/logs` - Clear debug logs
|
|
17
|
+
|
|
18
|
+
## Key Concepts
|
|
19
|
+
|
|
20
|
+
- **Log Capture**: Records MCP requests and responses
|
|
21
|
+
- **Filtering**: Query by profile, server, type, status
|
|
22
|
+
- **Auto-Cleanup**: Configurable log retention
|
|
23
|
+
- **Real-time**: Supports polling for live monitoring
|
|
24
|
+
|
|
25
|
+
## Debug Log Fields
|
|
26
|
+
|
|
27
|
+
- Profile and MCP server identification
|
|
28
|
+
- Request/response payloads
|
|
29
|
+
- Duration and status
|
|
30
|
+
- Timestamps
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Health Module
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Health check endpoints for monitoring application status. Used by container orchestrators and load balancers.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- `health.module.ts` - Module definition
|
|
10
|
+
- `health.controller.ts` - Health check endpoints
|
|
11
|
+
|
|
12
|
+
## Key Endpoints
|
|
13
|
+
|
|
14
|
+
- `GET /health` - Basic health check
|
|
15
|
+
- `GET /health/ready` - Readiness probe (database connection)
|
|
16
|
+
|
|
17
|
+
## Key Concepts
|
|
18
|
+
|
|
19
|
+
- **Liveness**: Application is running
|
|
20
|
+
- **Readiness**: Application can serve traffic
|
|
21
|
+
- **Docker**: Used by Docker health checks
|
|
22
|
+
- **Kubernetes**: Compatible with K8s probes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# MCP Module
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Core MCP server management module. Handles MCP server CRUD, auto-discovery of MCP packages, and the in-memory registry.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- `mcp.module.ts` - Module definition with all MCP services
|
|
10
|
+
- `mcp.controller.ts` - REST API for MCP server management
|
|
11
|
+
- `mcp.service.ts` - MCP server CRUD and connection management
|
|
12
|
+
- `mcp-discovery.service.ts` - Auto-discovery of MCP packages from `mcp-servers/`
|
|
13
|
+
- `mcp-registry.ts` - In-memory registry of discovered MCP packages
|
|
14
|
+
- `mcp-seed.service.ts` - Database seeding for discovered packages
|
|
15
|
+
- `dto/` - Data transfer objects for API validation
|
|
16
|
+
|
|
17
|
+
## Key Endpoints
|
|
18
|
+
|
|
19
|
+
- `GET /api/mcp-servers` - List all MCP servers
|
|
20
|
+
- `POST /api/mcp-servers` - Create new MCP server
|
|
21
|
+
- `GET /api/mcp-servers/:id` - Get MCP server details
|
|
22
|
+
- `PUT /api/mcp-servers/:id` - Update MCP server
|
|
23
|
+
- `DELETE /api/mcp-servers/:id` - Delete MCP server
|
|
24
|
+
|
|
25
|
+
## Key Concepts
|
|
26
|
+
|
|
27
|
+
- **Server Types**: builtin, custom, remote_http, remote_sse, external
|
|
28
|
+
- **Auto-Discovery**: Scans `mcp-servers/` for packages with `mcpPackage: true`
|
|
29
|
+
- **Registry**: In-memory store of discovered package metadata
|
|
30
|
+
- **Seeding**: Creates database records for discovered packages on startup
|
|
31
|
+
|
|
32
|
+
## MCP Package Discovery Flow
|
|
33
|
+
|
|
34
|
+
1. `McpDiscoveryService.onModuleInit()` - Scan dependencies
|
|
35
|
+
2. Filter packages with `mcpPackage: true` in package.json
|
|
36
|
+
3. Import and validate McpPackage interface
|
|
37
|
+
4. Register in `McpRegistry`
|
|
38
|
+
5. `McpSeedService` creates database records
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# OAuth Module
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
OAuth 2.1 authentication module for MCP servers. Handles authorization flows for MCP servers that require OAuth credentials.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- `oauth.module.ts` - Module definition
|
|
10
|
+
- `oauth.controller.ts` - OAuth callback and token endpoints
|
|
11
|
+
- `oauth.service.ts` - OAuth flow management and token storage
|
|
12
|
+
|
|
13
|
+
## Key Endpoints
|
|
14
|
+
|
|
15
|
+
- `GET /api/oauth/authorize/:serverId` - Initiate OAuth flow
|
|
16
|
+
- `GET /api/oauth/callback` - OAuth callback handler
|
|
17
|
+
- `POST /api/oauth/refresh/:serverId` - Refresh access token
|
|
18
|
+
|
|
19
|
+
## Key Concepts
|
|
20
|
+
|
|
21
|
+
- **OAuth 2.1**: Modern OAuth with PKCE support
|
|
22
|
+
- **DCR**: Dynamic Client Registration for MCP servers
|
|
23
|
+
- **Token Storage**: Encrypted token storage in database
|
|
24
|
+
- **Auto-Refresh**: Automatic token refresh before expiry
|
|
25
|
+
|
|
26
|
+
## OAuth Flow
|
|
27
|
+
|
|
28
|
+
1. User initiates authorization for MCP server
|
|
29
|
+
2. Redirect to provider's authorization endpoint
|
|
30
|
+
3. Callback receives authorization code
|
|
31
|
+
4. Exchange code for access/refresh tokens
|
|
32
|
+
5. Store tokens for future MCP calls
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Profiles Module
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Profile management module. Profiles are logical groupings of MCP servers that can be accessed via a single endpoint.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- `profiles.module.ts` - Module definition
|
|
10
|
+
- `profiles.controller.ts` - REST API for profile CRUD
|
|
11
|
+
- `profiles.service.ts` - Profile business logic and tool aggregation
|
|
12
|
+
|
|
13
|
+
## Key Endpoints
|
|
14
|
+
|
|
15
|
+
- `GET /api/profiles` - List all profiles
|
|
16
|
+
- `POST /api/profiles` - Create new profile
|
|
17
|
+
- `GET /api/profiles/:id` - Get profile details with MCP servers
|
|
18
|
+
- `PUT /api/profiles/:id` - Update profile
|
|
19
|
+
- `DELETE /api/profiles/:id` - Delete profile
|
|
20
|
+
|
|
21
|
+
## Key Concepts
|
|
22
|
+
|
|
23
|
+
- **Profile**: Named collection of MCP servers
|
|
24
|
+
- **Endpoint**: Each profile gets `/api/mcp/{slug}` endpoint
|
|
25
|
+
- **Tool Aggregation**: Combines tools from all servers in profile
|
|
26
|
+
- **AI Prompt**: Generates TOON/Markdown prompts for AI integration
|
|
27
|
+
- **Default Profile**: System creates "default" profile on first run
|
|
28
|
+
|
|
29
|
+
## Profile-MCP Relationship
|
|
30
|
+
|
|
31
|
+
- Profile has many MCP servers (many-to-many via ProfileMcpServer)
|
|
32
|
+
- Each assignment has order, enabled status, and tool filters
|
|
33
|
+
- Tools can be individually enabled/disabled per profile
|