@samanhappy/mcphub 0.12.1 → 0.12.3
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/README.fr.md +4 -0
- package/README.md +4 -0
- package/README.zh.md +4 -0
- package/dist/betterAuth.js +63 -4
- package/dist/betterAuth.js.map +1 -1
- package/dist/controllers/configController.js +1 -1
- package/dist/controllers/dxtController.js +1 -137
- package/dist/controllers/dxtController.js.map +1 -1
- package/dist/controllers/mcpbController.js +138 -0
- package/dist/controllers/mcpbController.js.map +1 -0
- package/dist/controllers/serverController.js +76 -12
- package/dist/controllers/serverController.js.map +1 -1
- package/dist/dao/DaoFactory.js +3 -4
- package/dist/dao/DaoFactory.js.map +1 -1
- package/dist/dao/examples.js +1 -1
- package/dist/dao/examples.js.map +1 -1
- package/dist/db/connection.js +146 -1
- package/dist/db/connection.js.map +1 -1
- package/dist/db/repositories/BaseRepository.js +33 -9
- package/dist/db/repositories/BaseRepository.js.map +1 -1
- package/dist/db/repositories/BearerKeyRepository.js +41 -16
- package/dist/db/repositories/BearerKeyRepository.js.map +1 -1
- package/dist/db/repositories/OAuthTokenRepository.js +107 -68
- package/dist/db/repositories/OAuthTokenRepository.js.map +1 -1
- package/dist/db/repositories/UserRepository.js +45 -18
- package/dist/db/repositories/UserRepository.js.map +1 -1
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -1
- package/dist/routes/index.js +3 -3
- package/dist/routes/index.js.map +1 -1
- package/dist/server.js +39 -2
- package/dist/server.js.map +1 -1
- package/dist/services/mcpService.js +19 -1
- package/dist/services/mcpService.js.map +1 -1
- package/dist/services/proxy.js +0 -2
- package/dist/services/proxy.js.map +1 -1
- package/dist/services/sseService.js +25 -9
- package/dist/services/sseService.js.map +1 -1
- package/dist/services/vectorSearchService.js +74 -8
- package/dist/services/vectorSearchService.js.map +1 -1
- package/dist/utils/dbRetry.js +199 -0
- package/dist/utils/dbRetry.js.map +1 -0
- package/dist/utils/smartRouting.js +13 -0
- package/dist/utils/smartRouting.js.map +1 -1
- package/frontend/dist/assets/index-AkdLybCq.js +294 -0
- package/frontend/dist/assets/index-AkdLybCq.js.map +1 -0
- package/frontend/dist/assets/index-DkQ2UJF_.css +1 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +13 -9
- package/frontend/dist/assets/index-7Q7UOsR3.js +0 -289
- package/frontend/dist/assets/index-7Q7UOsR3.js.map +0 -1
- package/frontend/dist/assets/index-GOMK9Sm1.css +0 -1
package/README.fr.md
CHANGED
|
@@ -18,6 +18,7 @@ MCPHub facilite la gestion et la mise à l'échelle de plusieurs serveurs MCP (M
|
|
|
18
18
|
- **Routage intelligent** - Découverte d'outils propulsée par IA utilisant la recherche sémantique vectorielle ([En savoir plus](https://docs.mcphubx.com/features/smart-routing))
|
|
19
19
|
- **Configuration à chaud** - Ajoutez, supprimez ou mettez à jour les serveurs sans temps d'arrêt
|
|
20
20
|
- **Support OAuth 2.0** - Modes client et serveur pour une authentification sécurisée ([En savoir plus](https://docs.mcphubx.com/features/oauth))
|
|
21
|
+
- **Connexion Sociale** - Support de connexion GitHub et Google via Better Auth (nécessite le mode Base de données)
|
|
21
22
|
- **Mode Base de données** - Stockez la configuration dans PostgreSQL pour les environnements de production ([En savoir plus](https://docs.mcphubx.com/configuration/database-configuration))
|
|
22
23
|
- **Prêt pour Docker** - Déployez instantanément avec la configuration conteneurisée
|
|
23
24
|
|
|
@@ -67,8 +68,11 @@ http://localhost:3000/mcp # Tous les serveurs
|
|
|
67
68
|
http://localhost:3000/mcp/{group} # Groupe spécifique
|
|
68
69
|
http://localhost:3000/mcp/{server} # Serveur spécifique
|
|
69
70
|
http://localhost:3000/mcp/$smart # Routage intelligent
|
|
71
|
+
http://localhost:3000/mcp/$smart/{group} # Routage intelligent dans un groupe
|
|
70
72
|
```
|
|
71
73
|
|
|
74
|
+
> **Note de sécurité** : Les points de terminaison MCP nécessitent une authentification par défaut pour éviter toute exposition accidentelle. Pour autoriser l'accès MCP sans authentification, désactivez **Activer l'authentification Bearer** dans la section Clés. **Ignorer l'authentification** n'affecte que la connexion au tableau de bord. À utiliser uniquement dans des environnements de confiance.
|
|
75
|
+
|
|
72
76
|
📖 Consultez la [Référence API](https://docs.mcphubx.com/api-reference) pour la documentation détaillée des points de terminaison.
|
|
73
77
|
|
|
74
78
|
## 📚 Documentation
|
package/README.md
CHANGED
|
@@ -18,6 +18,7 @@ MCPHub makes it easy to manage and scale multiple MCP (Model Context Protocol) s
|
|
|
18
18
|
- **Smart Routing** - AI-powered tool discovery using vector semantic search ([Learn more](https://docs.mcphubx.com/features/smart-routing))
|
|
19
19
|
- **Hot-Swappable Config** - Add, remove, or update servers without downtime
|
|
20
20
|
- **OAuth 2.0 Support** - Both client and server modes for secure authentication ([Learn more](https://docs.mcphubx.com/features/oauth))
|
|
21
|
+
- **Social Login** - Seamless GitHub and Google login support with Better Auth integration (requires Database Mode)
|
|
21
22
|
- **Database Mode** - Store configuration in PostgreSQL for production environments ([Learn more](https://docs.mcphubx.com/configuration/database-configuration))
|
|
22
23
|
- **Docker-Ready** - Deploy instantly with containerized setup
|
|
23
24
|
|
|
@@ -67,8 +68,11 @@ http://localhost:3000/mcp # All servers
|
|
|
67
68
|
http://localhost:3000/mcp/{group} # Specific group
|
|
68
69
|
http://localhost:3000/mcp/{server} # Specific server
|
|
69
70
|
http://localhost:3000/mcp/$smart # Smart routing
|
|
71
|
+
http://localhost:3000/mcp/$smart/{group} # Smart routing within group
|
|
70
72
|
```
|
|
71
73
|
|
|
74
|
+
> **Security note**: MCP endpoints require authentication by default to prevent accidental exposure. To allow unauthenticated MCP access, disable **Enable Bearer Authentication** in the Keys section. **Skip Authentication** only affects dashboard login. Use these only in trusted environments.
|
|
75
|
+
|
|
72
76
|
📖 See [API Reference](https://docs.mcphubx.com/api-reference) for detailed endpoint documentation.
|
|
73
77
|
|
|
74
78
|
## 📚 Documentation
|
package/README.zh.md
CHANGED
|
@@ -18,6 +18,7 @@ MCPHub 通过将多个 MCP(Model Context Protocol)服务器组织为灵活
|
|
|
18
18
|
- **智能路由** - 基于向量语义搜索的 AI 工具发现 ([了解更多](https://docs.mcphubx.com/zh/features/smart-routing))
|
|
19
19
|
- **热插拔配置** - 无需停机即可添加、移除或更新服务器
|
|
20
20
|
- **OAuth 2.0 支持** - 客户端和服务端模式,实现安全认证 ([了解更多](https://docs.mcphubx.com/zh/features/oauth))
|
|
21
|
+
- **社交一键登录** - 通过 Better Auth 集成支持 GitHub 和 Google 快捷登录(需启用数据库模式)
|
|
21
22
|
- **数据库模式** - 将配置存储在 PostgreSQL 中,适用于生产环境 ([了解更多](https://docs.mcphubx.com/zh/configuration/database-configuration))
|
|
22
23
|
- **Docker 就绪** - 容器化部署,开箱即用
|
|
23
24
|
|
|
@@ -67,8 +68,11 @@ http://localhost:3000/mcp # 所有服务器
|
|
|
67
68
|
http://localhost:3000/mcp/{group} # 特定分组
|
|
68
69
|
http://localhost:3000/mcp/{server} # 特定服务器
|
|
69
70
|
http://localhost:3000/mcp/$smart # 智能路由
|
|
71
|
+
http://localhost:3000/mcp/$smart/{group} # 智能路由(特定分组)
|
|
70
72
|
```
|
|
71
73
|
|
|
74
|
+
> **安全提示**:MCP 端点默认需要身份验证,以避免意外暴露。若需对 MCP 端点开放匿名访问,请在密钥设置中关闭 **启用 Bearer 认证**。**免登录开关**仅影响仪表盘登录。仅建议在受信任环境中使用。
|
|
75
|
+
|
|
72
76
|
📖 查看 [API 参考](https://docs.mcphubx.com/zh/api-reference)了解详细的端点文档。
|
|
73
77
|
|
|
74
78
|
## 📚 文档
|
package/dist/betterAuth.js
CHANGED
|
@@ -45,10 +45,11 @@ const databaseUrl = process.env.DB_URL;
|
|
|
45
45
|
if (!databaseUrl) {
|
|
46
46
|
throw new Error('DB_URL is required for Better Auth PostgreSQL storage.');
|
|
47
47
|
}
|
|
48
|
+
const pool = new Pool({
|
|
49
|
+
connectionString: databaseUrl,
|
|
50
|
+
});
|
|
48
51
|
const database = new PostgresDialect({
|
|
49
|
-
pool
|
|
50
|
-
connectionString: databaseUrl,
|
|
51
|
-
}),
|
|
52
|
+
pool,
|
|
52
53
|
});
|
|
53
54
|
const authOptions = {
|
|
54
55
|
baseURL,
|
|
@@ -67,15 +68,73 @@ const authOptions = {
|
|
|
67
68
|
},
|
|
68
69
|
};
|
|
69
70
|
export const auth = betterAuth(authOptions);
|
|
71
|
+
const extractMigrationTableName = (entry) => {
|
|
72
|
+
if (typeof entry === 'string') {
|
|
73
|
+
return entry;
|
|
74
|
+
}
|
|
75
|
+
if (!entry || typeof entry !== 'object') {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const record = entry;
|
|
79
|
+
const candidate = record.tableName ?? record.table ?? record.name;
|
|
80
|
+
return typeof candidate === 'string' ? candidate : null;
|
|
81
|
+
};
|
|
82
|
+
const resolveCurrentSchema = async () => {
|
|
83
|
+
try {
|
|
84
|
+
const result = await pool.query('select current_schema() as schema');
|
|
85
|
+
return result.rows[0]?.schema || 'public';
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return 'public';
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
const listExistingTables = async (schema, tableNames) => {
|
|
92
|
+
if (!tableNames.length) {
|
|
93
|
+
return new Set();
|
|
94
|
+
}
|
|
95
|
+
const result = await pool.query('select table_name from information_schema.tables where table_schema = $1 and table_name = any($2)', [schema, tableNames]);
|
|
96
|
+
return new Set(result.rows.map((row) => row.table_name));
|
|
97
|
+
};
|
|
98
|
+
const isRelationAlreadyExistsError = (error) => {
|
|
99
|
+
if (!error || typeof error !== 'object') {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
const message = String(error.message ?? '');
|
|
103
|
+
return /relation\s+".*"\s+already\s+exists/i.test(message);
|
|
104
|
+
};
|
|
70
105
|
export const ensureBetterAuthSchema = async () => {
|
|
71
106
|
if (!getBetterAuthRuntimeConfig().enabled) {
|
|
72
107
|
return;
|
|
73
108
|
}
|
|
74
109
|
const { getMigrations } = await import('better-auth/db');
|
|
75
110
|
const { toBeCreated, toBeAdded, runMigrations } = await getMigrations(authOptions);
|
|
76
|
-
if (toBeCreated.length
|
|
111
|
+
if (!toBeCreated.length && !toBeAdded.length) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (toBeCreated.length) {
|
|
115
|
+
const tableNames = toBeCreated
|
|
116
|
+
.map((entry) => extractMigrationTableName(entry))
|
|
117
|
+
.filter((tableName) => Boolean(tableName));
|
|
118
|
+
if (tableNames.length === toBeCreated.length) {
|
|
119
|
+
const schema = await resolveCurrentSchema();
|
|
120
|
+
const existingTables = await listExistingTables(schema, tableNames);
|
|
121
|
+
const allTablesExist = tableNames.every((tableName) => existingTables.has(tableName));
|
|
122
|
+
if (allTablesExist && !toBeAdded.length) {
|
|
123
|
+
console.warn(`[better-auth] Detected existing tables in schema "${schema}"; skipping migrations.`);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
77
129
|
await runMigrations();
|
|
78
130
|
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
if (isRelationAlreadyExistsError(error)) {
|
|
133
|
+
console.warn('[better-auth] Migration skipped due to existing relations.', error);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
79
138
|
};
|
|
80
139
|
export { betterAuthRuntimeConfig };
|
|
81
140
|
//# sourceMappingURL=betterAuth.js.map
|
package/dist/betterAuth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"betterAuth.js","sourceRoot":"","sources":["../src/betterAuth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC1B,OAAO,aAAa,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,gCAAgC,CAAC;AAExC,MAAM,aAAa,GAAG,0BAA0B,EAAE,CAAC;AACnD,MAAM,eAAe,GAA+D,EAAE,CAAC;AACvF,IACE,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO;IACtC,OAAO,CAAC,GAAG,CAAC,gBAAgB;IAC5B,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAChC,CAAC;IACD,eAAe,CAAC,MAAM,GAAG;QACvB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB;QACtC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;KAC/C,CAAC;AACJ,CAAC;AACD,IACE,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO;IACtC,OAAO,CAAC,GAAG,CAAC,gBAAgB;IAC5B,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAChC,CAAC;IACD,eAAe,CAAC,MAAM,GAAG;QACvB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB;QACtC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;KAC/C,CAAC;AACJ,CAAC;AAED,MAAM,cAAc,GAAG,CAAC,OAAe,EAAE,QAAgB,EAAU,EAAE;IACnE,MAAM,cAAc,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC;IAC5E,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAC7B,IAAI,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;YAChD,GAAG,CAAC,QAAQ,GAAG,cAAc,CAAC;YAC9B,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;QACxB,CAAC;QACD,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAC1C,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;QACxB,CAAC;QACD,GAAG,CAAC,QAAQ,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,cAAc,EAAE,CAAC;QACtE,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAChD,OAAO,GAAG,WAAW,GAAG,cAAc,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,cAAc,CAC5B,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,oBAAoB,aAAa,CAAC,IAAI,GAAG,aAAa,CAAC,QAAQ,EAAE,EAChG,aAAa,CAAC,QAAQ,CACvB,CAAC;AAEF,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;AACvC,IAAI,CAAC,WAAW,EAAE,CAAC;IACjB,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,
|
|
1
|
+
{"version":3,"file":"betterAuth.js","sourceRoot":"","sources":["../src/betterAuth.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,7 +32,7 @@ export const getRuntimeConfig = (req, res) => {
|
|
|
32
32
|
};
|
|
33
33
|
/**
|
|
34
34
|
* Get public system configuration (only skipAuth setting)
|
|
35
|
-
* This endpoint doesn't require authentication to allow checking if
|
|
35
|
+
* This endpoint doesn't require authentication to allow checking if dashboard login should be skipped
|
|
36
36
|
*/
|
|
37
37
|
export const getPublicConfig = (req, res) => {
|
|
38
38
|
try {
|
|
@@ -1,138 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import AdmZip from 'adm-zip';
|
|
5
|
-
// Configure multer for file uploads
|
|
6
|
-
const storage = multer.diskStorage({
|
|
7
|
-
destination: (req, file, cb) => {
|
|
8
|
-
const uploadDir = path.join(process.cwd(), 'data/uploads/dxt');
|
|
9
|
-
if (!fs.existsSync(uploadDir)) {
|
|
10
|
-
fs.mkdirSync(uploadDir, { recursive: true });
|
|
11
|
-
}
|
|
12
|
-
cb(null, uploadDir);
|
|
13
|
-
},
|
|
14
|
-
filename: (req, file, cb) => {
|
|
15
|
-
const timestamp = Date.now();
|
|
16
|
-
const originalName = path.parse(file.originalname).name;
|
|
17
|
-
cb(null, `${originalName}-${timestamp}.dxt`);
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
const upload = multer({
|
|
21
|
-
storage,
|
|
22
|
-
fileFilter: (req, file, cb) => {
|
|
23
|
-
if (file.originalname.endsWith('.dxt')) {
|
|
24
|
-
cb(null, true);
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
cb(new Error('Only .dxt files are allowed'));
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
limits: {
|
|
31
|
-
fileSize: 500 * 1024 * 1024, // 500MB limit
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
export const uploadMiddleware = upload.single('dxtFile');
|
|
35
|
-
// Clean up old DXT server files when installing a new version
|
|
36
|
-
const cleanupOldDxtServer = (serverName) => {
|
|
37
|
-
try {
|
|
38
|
-
const uploadDir = path.join(process.cwd(), 'data/uploads/dxt');
|
|
39
|
-
const serverPattern = `server-${serverName}`;
|
|
40
|
-
if (fs.existsSync(uploadDir)) {
|
|
41
|
-
const files = fs.readdirSync(uploadDir);
|
|
42
|
-
files.forEach((file) => {
|
|
43
|
-
if (file.startsWith(serverPattern)) {
|
|
44
|
-
const filePath = path.join(uploadDir, file);
|
|
45
|
-
if (fs.statSync(filePath).isDirectory()) {
|
|
46
|
-
fs.rmSync(filePath, { recursive: true, force: true });
|
|
47
|
-
console.log(`Cleaned up old DXT server directory: ${filePath}`);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
catch (error) {
|
|
54
|
-
console.warn('Failed to cleanup old DXT server files:', error);
|
|
55
|
-
// Don't fail the installation if cleanup fails
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
export const uploadDxtFile = async (req, res) => {
|
|
59
|
-
try {
|
|
60
|
-
if (!req.file) {
|
|
61
|
-
res.status(400).json({
|
|
62
|
-
success: false,
|
|
63
|
-
message: 'No DXT file uploaded',
|
|
64
|
-
});
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
const dxtFilePath = req.file.path;
|
|
68
|
-
const timestamp = Date.now();
|
|
69
|
-
const tempExtractDir = path.join(path.dirname(dxtFilePath), `temp-extracted-${timestamp}`);
|
|
70
|
-
try {
|
|
71
|
-
// Extract the DXT file (which is a ZIP archive) to a temporary directory first
|
|
72
|
-
const zip = new AdmZip(dxtFilePath);
|
|
73
|
-
zip.extractAllTo(tempExtractDir, true);
|
|
74
|
-
// Read and validate the manifest.json
|
|
75
|
-
const manifestPath = path.join(tempExtractDir, 'manifest.json');
|
|
76
|
-
if (!fs.existsSync(manifestPath)) {
|
|
77
|
-
throw new Error('manifest.json not found in DXT file');
|
|
78
|
-
}
|
|
79
|
-
const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
|
|
80
|
-
const manifest = JSON.parse(manifestContent);
|
|
81
|
-
// Validate required fields in manifest
|
|
82
|
-
if (!manifest.dxt_version) {
|
|
83
|
-
throw new Error('Invalid manifest: missing dxt_version');
|
|
84
|
-
}
|
|
85
|
-
if (!manifest.name) {
|
|
86
|
-
throw new Error('Invalid manifest: missing name');
|
|
87
|
-
}
|
|
88
|
-
if (!manifest.version) {
|
|
89
|
-
throw new Error('Invalid manifest: missing version');
|
|
90
|
-
}
|
|
91
|
-
if (!manifest.server) {
|
|
92
|
-
throw new Error('Invalid manifest: missing server configuration');
|
|
93
|
-
}
|
|
94
|
-
// Use server name as the final extract directory for automatic version management
|
|
95
|
-
const finalExtractDir = path.join(path.dirname(dxtFilePath), `server-${manifest.name}`);
|
|
96
|
-
// Clean up any existing version of this server
|
|
97
|
-
cleanupOldDxtServer(manifest.name);
|
|
98
|
-
if (!fs.existsSync(finalExtractDir)) {
|
|
99
|
-
fs.mkdirSync(finalExtractDir, { recursive: true });
|
|
100
|
-
}
|
|
101
|
-
// Move the temporary directory to the final location
|
|
102
|
-
fs.renameSync(tempExtractDir, finalExtractDir);
|
|
103
|
-
console.log(`DXT server extracted to: ${finalExtractDir}`);
|
|
104
|
-
// Clean up the uploaded DXT file
|
|
105
|
-
fs.unlinkSync(dxtFilePath);
|
|
106
|
-
const response = {
|
|
107
|
-
success: true,
|
|
108
|
-
data: {
|
|
109
|
-
manifest,
|
|
110
|
-
extractDir: finalExtractDir,
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
|
-
res.json(response);
|
|
114
|
-
}
|
|
115
|
-
catch (extractError) {
|
|
116
|
-
// Clean up files on error
|
|
117
|
-
if (fs.existsSync(dxtFilePath)) {
|
|
118
|
-
fs.unlinkSync(dxtFilePath);
|
|
119
|
-
}
|
|
120
|
-
if (fs.existsSync(tempExtractDir)) {
|
|
121
|
-
fs.rmSync(tempExtractDir, { recursive: true, force: true });
|
|
122
|
-
}
|
|
123
|
-
throw extractError;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
catch (error) {
|
|
127
|
-
console.error('DXT upload error:', error);
|
|
128
|
-
let message = 'Failed to process DXT file';
|
|
129
|
-
if (error instanceof Error) {
|
|
130
|
-
message = error.message;
|
|
131
|
-
}
|
|
132
|
-
res.status(500).json({
|
|
133
|
-
success: false,
|
|
134
|
-
message,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
};
|
|
1
|
+
export { uploadMiddleware, uploadMcpbFile } from './mcpbController.js';
|
|
138
2
|
//# sourceMappingURL=dxtController.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dxtController.js","sourceRoot":"","sources":["../../src/controllers/dxtController.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dxtController.js","sourceRoot":"","sources":["../../src/controllers/dxtController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import multer from 'multer';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import AdmZip from 'adm-zip';
|
|
5
|
+
// Configure multer for file uploads
|
|
6
|
+
const storage = multer.diskStorage({
|
|
7
|
+
destination: (_req, _file, cb) => {
|
|
8
|
+
const uploadDir = path.join(process.cwd(), 'data/uploads/mcpb');
|
|
9
|
+
if (!fs.existsSync(uploadDir)) {
|
|
10
|
+
fs.mkdirSync(uploadDir, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
cb(null, uploadDir);
|
|
13
|
+
},
|
|
14
|
+
filename: (_req, file, cb) => {
|
|
15
|
+
const timestamp = Date.now();
|
|
16
|
+
const originalName = path.parse(file.originalname).name;
|
|
17
|
+
cb(null, `${originalName}-${timestamp}.mcpb`);
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
const upload = multer({
|
|
21
|
+
storage,
|
|
22
|
+
fileFilter: (_req, file, cb) => {
|
|
23
|
+
if (file.originalname.endsWith('.mcpb')) {
|
|
24
|
+
cb(null, true);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
cb(new Error('Only .mcpb files are allowed'));
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
limits: {
|
|
31
|
+
fileSize: 500 * 1024 * 1024, // 500MB limit
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
export const uploadMiddleware = upload.single('mcpbFile');
|
|
35
|
+
// Clean up old MCPB server files when installing a new version
|
|
36
|
+
const cleanupOldMcpbServer = (serverName) => {
|
|
37
|
+
try {
|
|
38
|
+
const uploadDir = path.join(process.cwd(), 'data/uploads/mcpb');
|
|
39
|
+
const serverPattern = `server-${serverName}`;
|
|
40
|
+
if (fs.existsSync(uploadDir)) {
|
|
41
|
+
const files = fs.readdirSync(uploadDir);
|
|
42
|
+
files.forEach((file) => {
|
|
43
|
+
if (file.startsWith(serverPattern)) {
|
|
44
|
+
const filePath = path.join(uploadDir, file);
|
|
45
|
+
if (fs.statSync(filePath).isDirectory()) {
|
|
46
|
+
fs.rmSync(filePath, { recursive: true, force: true });
|
|
47
|
+
console.log(`Cleaned up old MCPB server directory: ${filePath}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.warn('Failed to cleanup old MCPB server files:', error);
|
|
55
|
+
// Don't fail the installation if cleanup fails
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
export const uploadMcpbFile = async (req, res) => {
|
|
59
|
+
try {
|
|
60
|
+
if (!req.file) {
|
|
61
|
+
res.status(400).json({
|
|
62
|
+
success: false,
|
|
63
|
+
message: 'No MCPB file uploaded',
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const mcpbFilePath = req.file.path;
|
|
68
|
+
const timestamp = Date.now();
|
|
69
|
+
const tempExtractDir = path.join(path.dirname(mcpbFilePath), `temp-extracted-${timestamp}`);
|
|
70
|
+
try {
|
|
71
|
+
// Extract the MCPB file (which is a ZIP archive) to a temporary directory first
|
|
72
|
+
const zip = new AdmZip(mcpbFilePath);
|
|
73
|
+
zip.extractAllTo(tempExtractDir, true);
|
|
74
|
+
// Read and validate the manifest.json
|
|
75
|
+
const manifestPath = path.join(tempExtractDir, 'manifest.json');
|
|
76
|
+
if (!fs.existsSync(manifestPath)) {
|
|
77
|
+
throw new Error('manifest.json not found in MCPB file');
|
|
78
|
+
}
|
|
79
|
+
const manifestContent = fs.readFileSync(manifestPath, 'utf-8');
|
|
80
|
+
const manifest = JSON.parse(manifestContent);
|
|
81
|
+
// Validate required fields in manifest
|
|
82
|
+
if (!manifest.manifest_version) {
|
|
83
|
+
throw new Error('Invalid manifest: missing manifest_version');
|
|
84
|
+
}
|
|
85
|
+
if (!manifest.name) {
|
|
86
|
+
throw new Error('Invalid manifest: missing name');
|
|
87
|
+
}
|
|
88
|
+
if (!manifest.version) {
|
|
89
|
+
throw new Error('Invalid manifest: missing version');
|
|
90
|
+
}
|
|
91
|
+
if (!manifest.server) {
|
|
92
|
+
throw new Error('Invalid manifest: missing server configuration');
|
|
93
|
+
}
|
|
94
|
+
// Use server name as the final extract directory for automatic version management
|
|
95
|
+
const finalExtractDir = path.join(path.dirname(mcpbFilePath), `server-${manifest.name}`);
|
|
96
|
+
// Clean up any existing version of this server
|
|
97
|
+
cleanupOldMcpbServer(manifest.name);
|
|
98
|
+
if (!fs.existsSync(finalExtractDir)) {
|
|
99
|
+
fs.mkdirSync(finalExtractDir, { recursive: true });
|
|
100
|
+
}
|
|
101
|
+
// Move the temporary directory to the final location
|
|
102
|
+
fs.renameSync(tempExtractDir, finalExtractDir);
|
|
103
|
+
console.log(`MCPB server extracted to: ${finalExtractDir}`);
|
|
104
|
+
// Clean up the uploaded MCPB file
|
|
105
|
+
fs.unlinkSync(mcpbFilePath);
|
|
106
|
+
const response = {
|
|
107
|
+
success: true,
|
|
108
|
+
data: {
|
|
109
|
+
manifest,
|
|
110
|
+
extractDir: finalExtractDir,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
res.json(response);
|
|
114
|
+
}
|
|
115
|
+
catch (extractError) {
|
|
116
|
+
// Clean up files on error
|
|
117
|
+
if (fs.existsSync(mcpbFilePath)) {
|
|
118
|
+
fs.unlinkSync(mcpbFilePath);
|
|
119
|
+
}
|
|
120
|
+
if (fs.existsSync(tempExtractDir)) {
|
|
121
|
+
fs.rmSync(tempExtractDir, { recursive: true, force: true });
|
|
122
|
+
}
|
|
123
|
+
throw extractError;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
console.error('MCPB upload error:', error);
|
|
128
|
+
let message = 'Failed to process MCPB file';
|
|
129
|
+
if (error instanceof Error) {
|
|
130
|
+
message = error.message;
|
|
131
|
+
}
|
|
132
|
+
res.status(500).json({
|
|
133
|
+
success: false,
|
|
134
|
+
message,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
//# sourceMappingURL=mcpbController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcpbController.js","sourceRoot":"","sources":["../../src/controllers/mcpbController.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,MAAM,MAAM,SAAS,CAAC;AAG7B,oCAAoC;AACpC,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC;IACjC,WAAW,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,mBAAmB,CAAC,CAAC;QAChE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;QACD,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACtB,CAAC;IACD,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;QAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC;QACxD,EAAE,CAAC,IAAI,EAAE,GAAG,YAAY,IAAI,SAAS,OAAO,CAAC,CAAC;IAChD,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,MAAM,CAAC;IACpB,OAAO;IACP,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;QAC7B,IAAI,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACxC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjB,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IACD,MAAM,EAAE;QACN,QAAQ,EAAE,GAAG,GAAG,IAAI,GAAG,IAAI,EAAE,cAAc;KAC5C;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAE1D,+DAA+D;AAC/D,MAAM,oBAAoB,GAAG,CAAC,UAAkB,EAAQ,EAAE;IACxD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,mBAAmB,CAAC,CAAC;QAChE,MAAM,aAAa,GAAG,UAAU,UAAU,EAAE,CAAC;QAE7C,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;YACxC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;gBACrB,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;oBACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;oBAC5C,IAAI,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;wBACxC,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;wBACtD,OAAO,CAAC,GAAG,CAAC,yCAAyC,QAAQ,EAAE,CAAC,CAAC;oBACnE,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;QAChE,+CAA+C;IACjD,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,EAAE,GAAY,EAAE,GAAa,EAAiB,EAAE;IACjF,IAAI,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACd,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,uBAAuB;aACjC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;QACnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,kBAAkB,SAAS,EAAE,CAAC,CAAC;QAE5F,IAAI,CAAC;YACH,gFAAgF;YAChF,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC;YACrC,GAAG,CAAC,YAAY,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;YAEvC,sCAAsC;YACtC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;YAChE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;gBACjC,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAC1D,CAAC;YAED,MAAM,eAAe,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;YAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YAE7C,uCAAuC;YACvC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC;gBAC/B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAChE,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACnB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;YACpD,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACtB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvD,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;YACpE,CAAC;YAED,kFAAkF;YAClF,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,UAAU,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;YAEzF,+CAA+C;YAC/C,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;gBACpC,EAAE,CAAC,SAAS,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACrD,CAAC;YAED,qDAAqD;YACrD,EAAE,CAAC,UAAU,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;YAC/C,OAAO,CAAC,GAAG,CAAC,6BAA6B,eAAe,EAAE,CAAC,CAAC;YAE5D,kCAAkC;YAClC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;YAE5B,MAAM,QAAQ,GAAgB;gBAC5B,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE;oBACJ,QAAQ;oBACR,UAAU,EAAE,eAAe;iBAC5B;aACF,CAAC;YAEF,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,YAAY,EAAE,CAAC;YACtB,0BAA0B;YAC1B,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;gBAChC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;YAC9B,CAAC;YACD,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;gBAClC,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9D,CAAC;YACD,MAAM,YAAY,CAAC;QACrB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;QAE3C,IAAI,OAAO,GAAG,6BAA6B,CAAC;QAC5C,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC1B,CAAC;QAED,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,OAAO,EAAE,KAAK;YACd,OAAO;SACR,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -769,9 +769,14 @@ export const updateSystemConfig = async (req, res) => {
|
|
|
769
769
|
const hasSmartRoutingUpdate = smartRouting &&
|
|
770
770
|
(typeof smartRouting.enabled === 'boolean' ||
|
|
771
771
|
typeof smartRouting.dbUrl === 'string' ||
|
|
772
|
+
typeof smartRouting.embeddingProvider === 'string' ||
|
|
772
773
|
typeof smartRouting.openaiApiBaseUrl === 'string' ||
|
|
773
774
|
typeof smartRouting.openaiApiKey === 'string' ||
|
|
774
775
|
typeof smartRouting.openaiApiEmbeddingModel === 'string' ||
|
|
776
|
+
typeof smartRouting.azureOpenaiEndpoint === 'string' ||
|
|
777
|
+
typeof smartRouting.azureOpenaiApiKey === 'string' ||
|
|
778
|
+
typeof smartRouting.azureOpenaiApiVersion === 'string' ||
|
|
779
|
+
typeof smartRouting.azureOpenaiEmbeddingDeployment === 'string' ||
|
|
775
780
|
typeof smartRouting.progressiveDisclosure === 'boolean');
|
|
776
781
|
const hasMcpRouterUpdate = mcpRouter &&
|
|
777
782
|
(typeof mcpRouter.apiKey === 'string' ||
|
|
@@ -813,7 +818,7 @@ export const updateSystemConfig = async (req, res) => {
|
|
|
813
818
|
routing: {
|
|
814
819
|
enableGlobalRoute: true,
|
|
815
820
|
enableGroupNameRoute: true,
|
|
816
|
-
enableBearerAuth:
|
|
821
|
+
enableBearerAuth: true,
|
|
817
822
|
bearerAuthKey: '',
|
|
818
823
|
skipAuth: false,
|
|
819
824
|
},
|
|
@@ -825,9 +830,14 @@ export const updateSystemConfig = async (req, res) => {
|
|
|
825
830
|
smartRouting: {
|
|
826
831
|
enabled: false,
|
|
827
832
|
dbUrl: '',
|
|
833
|
+
embeddingProvider: 'openai',
|
|
828
834
|
openaiApiBaseUrl: '',
|
|
829
835
|
openaiApiKey: '',
|
|
830
836
|
openaiApiEmbeddingModel: '',
|
|
837
|
+
azureOpenaiEndpoint: '',
|
|
838
|
+
azureOpenaiApiKey: '',
|
|
839
|
+
azureOpenaiApiVersion: '',
|
|
840
|
+
azureOpenaiEmbeddingDeployment: '',
|
|
831
841
|
},
|
|
832
842
|
mcpRouter: {
|
|
833
843
|
apiKey: '',
|
|
@@ -842,7 +852,7 @@ export const updateSystemConfig = async (req, res) => {
|
|
|
842
852
|
systemConfig.routing = {
|
|
843
853
|
enableGlobalRoute: true,
|
|
844
854
|
enableGroupNameRoute: true,
|
|
845
|
-
enableBearerAuth:
|
|
855
|
+
enableBearerAuth: true,
|
|
846
856
|
bearerAuthKey: '',
|
|
847
857
|
skipAuth: false,
|
|
848
858
|
};
|
|
@@ -858,9 +868,14 @@ export const updateSystemConfig = async (req, res) => {
|
|
|
858
868
|
systemConfig.smartRouting = {
|
|
859
869
|
enabled: false,
|
|
860
870
|
dbUrl: '',
|
|
871
|
+
embeddingProvider: 'openai',
|
|
861
872
|
openaiApiBaseUrl: '',
|
|
862
873
|
openaiApiKey: '',
|
|
863
874
|
openaiApiEmbeddingModel: '',
|
|
875
|
+
azureOpenaiEndpoint: '',
|
|
876
|
+
azureOpenaiApiKey: '',
|
|
877
|
+
azureOpenaiApiVersion: '',
|
|
878
|
+
azureOpenaiEmbeddingDeployment: '',
|
|
864
879
|
};
|
|
865
880
|
}
|
|
866
881
|
if (!systemConfig.mcpRouter) {
|
|
@@ -924,23 +939,49 @@ export const updateSystemConfig = async (req, res) => {
|
|
|
924
939
|
const previousSmartRoutingConfig = { ...systemConfig.smartRouting };
|
|
925
940
|
let needsSync = false;
|
|
926
941
|
if (smartRouting) {
|
|
942
|
+
if (typeof smartRouting.embeddingProvider === 'string') {
|
|
943
|
+
const normalized = smartRouting.embeddingProvider.trim().toLowerCase();
|
|
944
|
+
systemConfig.smartRouting.embeddingProvider =
|
|
945
|
+
normalized === 'azure' || normalized === 'azure_openai' ? 'azure_openai' : 'openai';
|
|
946
|
+
}
|
|
927
947
|
if (typeof smartRouting.enabled === 'boolean') {
|
|
928
948
|
// If enabling Smart Routing, validate required fields
|
|
929
949
|
if (smartRouting.enabled) {
|
|
930
950
|
const currentDbUrl = process.env.DB_URL || smartRouting.dbUrl || systemConfig.smartRouting.dbUrl;
|
|
931
|
-
|
|
932
|
-
if (!currentDbUrl || !currentOpenaiApiKey) {
|
|
933
|
-
const missingFields = [];
|
|
934
|
-
if (!currentDbUrl)
|
|
935
|
-
missingFields.push('Database URL');
|
|
936
|
-
if (!currentOpenaiApiKey)
|
|
937
|
-
missingFields.push('OpenAI API Key');
|
|
951
|
+
if (!currentDbUrl) {
|
|
938
952
|
res.status(400).json({
|
|
939
|
-
|
|
940
|
-
message: `Smart Routing requires the following fields: ${missingFields.join(', ')}`,
|
|
953
|
+
message: 'Smart routing cannot be enabled without Database URL. Please provide DB URL.',
|
|
941
954
|
});
|
|
942
955
|
return;
|
|
943
956
|
}
|
|
957
|
+
const effectiveProvider = (typeof smartRouting.embeddingProvider === 'string'
|
|
958
|
+
? smartRouting.embeddingProvider
|
|
959
|
+
: systemConfig.smartRouting.embeddingProvider) || 'openai';
|
|
960
|
+
if (effectiveProvider === 'azure_openai') {
|
|
961
|
+
const currentAzureEndpoint = smartRouting.azureOpenaiEndpoint || systemConfig.smartRouting.azureOpenaiEndpoint;
|
|
962
|
+
const currentAzureKey = smartRouting.azureOpenaiApiKey || systemConfig.smartRouting.azureOpenaiApiKey;
|
|
963
|
+
const currentAzureDeployment = smartRouting.azureOpenaiEmbeddingDeployment ||
|
|
964
|
+
systemConfig.smartRouting.azureOpenaiEmbeddingDeployment;
|
|
965
|
+
const currentAzureApiVersion = smartRouting.azureOpenaiApiVersion || systemConfig.smartRouting.azureOpenaiApiVersion;
|
|
966
|
+
if (!currentAzureEndpoint ||
|
|
967
|
+
!currentAzureKey ||
|
|
968
|
+
!currentAzureApiVersion ||
|
|
969
|
+
!currentAzureDeployment) {
|
|
970
|
+
res.status(400).json({
|
|
971
|
+
message: 'Smart routing cannot be enabled without Azure OpenAI configuration. Please provide endpoint, API key, embedding deployment, and API version.',
|
|
972
|
+
});
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
const currentOpenAiKey = smartRouting.openaiApiKey || systemConfig.smartRouting.openaiApiKey;
|
|
978
|
+
if (!currentOpenAiKey) {
|
|
979
|
+
res.status(400).json({
|
|
980
|
+
message: 'Smart routing cannot be enabled without OpenAI API key. Please provide an OpenAI API key.',
|
|
981
|
+
});
|
|
982
|
+
return;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
944
985
|
}
|
|
945
986
|
systemConfig.smartRouting.enabled = smartRouting.enabled;
|
|
946
987
|
}
|
|
@@ -956,17 +997,40 @@ export const updateSystemConfig = async (req, res) => {
|
|
|
956
997
|
if (typeof smartRouting.openaiApiEmbeddingModel === 'string') {
|
|
957
998
|
systemConfig.smartRouting.openaiApiEmbeddingModel = smartRouting.openaiApiEmbeddingModel;
|
|
958
999
|
}
|
|
1000
|
+
if (typeof smartRouting.azureOpenaiEndpoint === 'string') {
|
|
1001
|
+
systemConfig.smartRouting.azureOpenaiEndpoint = smartRouting.azureOpenaiEndpoint;
|
|
1002
|
+
}
|
|
1003
|
+
if (typeof smartRouting.azureOpenaiApiKey === 'string') {
|
|
1004
|
+
systemConfig.smartRouting.azureOpenaiApiKey = smartRouting.azureOpenaiApiKey;
|
|
1005
|
+
}
|
|
1006
|
+
if (typeof smartRouting.azureOpenaiApiVersion === 'string') {
|
|
1007
|
+
systemConfig.smartRouting.azureOpenaiApiVersion = smartRouting.azureOpenaiApiVersion;
|
|
1008
|
+
}
|
|
1009
|
+
if (typeof smartRouting.azureOpenaiEmbeddingDeployment === 'string') {
|
|
1010
|
+
systemConfig.smartRouting.azureOpenaiEmbeddingDeployment =
|
|
1011
|
+
smartRouting.azureOpenaiEmbeddingDeployment;
|
|
1012
|
+
}
|
|
959
1013
|
if (typeof smartRouting.progressiveDisclosure === 'boolean') {
|
|
960
1014
|
systemConfig.smartRouting.progressiveDisclosure = smartRouting.progressiveDisclosure;
|
|
961
1015
|
}
|
|
962
1016
|
// Check if we need to sync embeddings
|
|
963
1017
|
const isNowEnabled = systemConfig.smartRouting.enabled || false;
|
|
964
1018
|
const hasConfigChanged = previousSmartRoutingConfig.dbUrl !== systemConfig.smartRouting.dbUrl ||
|
|
1019
|
+
previousSmartRoutingConfig.embeddingProvider !==
|
|
1020
|
+
systemConfig.smartRouting.embeddingProvider ||
|
|
965
1021
|
previousSmartRoutingConfig.openaiApiBaseUrl !==
|
|
966
1022
|
systemConfig.smartRouting.openaiApiBaseUrl ||
|
|
967
1023
|
previousSmartRoutingConfig.openaiApiKey !== systemConfig.smartRouting.openaiApiKey ||
|
|
968
1024
|
previousSmartRoutingConfig.openaiApiEmbeddingModel !==
|
|
969
|
-
systemConfig.smartRouting.openaiApiEmbeddingModel
|
|
1025
|
+
systemConfig.smartRouting.openaiApiEmbeddingModel ||
|
|
1026
|
+
previousSmartRoutingConfig.azureOpenaiEndpoint !==
|
|
1027
|
+
systemConfig.smartRouting.azureOpenaiEndpoint ||
|
|
1028
|
+
previousSmartRoutingConfig.azureOpenaiApiKey !==
|
|
1029
|
+
systemConfig.smartRouting.azureOpenaiApiKey ||
|
|
1030
|
+
previousSmartRoutingConfig.azureOpenaiApiVersion !==
|
|
1031
|
+
systemConfig.smartRouting.azureOpenaiApiVersion ||
|
|
1032
|
+
previousSmartRoutingConfig.azureOpenaiEmbeddingDeployment !==
|
|
1033
|
+
systemConfig.smartRouting.azureOpenaiEmbeddingDeployment;
|
|
970
1034
|
// Sync if: first time enabling OR smart routing is enabled and any config changed
|
|
971
1035
|
needsSync = (!wasSmartRoutingEnabled && isNowEnabled) || (isNowEnabled && hasConfigChanged);
|
|
972
1036
|
}
|