@samanhappy/mcphub 1.0.36 → 1.0.38
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 +47 -17
- package/README.md +44 -36
- package/README.zh.md +45 -35
- package/dist/constants/oauthServerDefaults.js +1 -0
- package/dist/constants/oauthServerDefaults.js.map +1 -1
- package/dist/controllers/groupController.js +63 -14
- package/dist/controllers/groupController.js.map +1 -1
- package/dist/controllers/oauthDynamicRegistrationController.js +6 -32
- package/dist/controllers/oauthDynamicRegistrationController.js.map +1 -1
- package/dist/controllers/serverController.js +46 -3
- package/dist/controllers/serverController.js.map +1 -1
- package/dist/dao/GroupDaoDbImpl.js +18 -0
- package/dist/dao/GroupDaoDbImpl.js.map +1 -1
- package/dist/dao/OAuthClientDaoDbImpl.js +3 -0
- package/dist/dao/OAuthClientDaoDbImpl.js.map +1 -1
- package/dist/db/connection.js +3 -2
- package/dist/db/connection.js.map +1 -1
- package/dist/db/entities/Group.js +9 -1
- package/dist/db/entities/Group.js.map +1 -1
- package/dist/db/entities/OAuthClient.js +4 -0
- package/dist/db/entities/OAuthClient.js.map +1 -1
- package/dist/db/groupSchema.js +29 -0
- package/dist/db/groupSchema.js.map +1 -0
- package/dist/models/OAuth.js +98 -1
- package/dist/models/OAuth.js.map +1 -1
- package/dist/routes/index.js +4 -3
- package/dist/routes/index.js.map +1 -1
- package/dist/services/groupService.js +57 -23
- package/dist/services/groupService.js.map +1 -1
- package/dist/services/logService.js +11 -2
- package/dist/services/logService.js.map +1 -1
- package/dist/services/mcpService.js +177 -17
- package/dist/services/mcpService.js.map +1 -1
- package/dist/services/oauthClientRegistration.js +22 -7
- package/dist/services/oauthClientRegistration.js.map +1 -1
- package/dist/services/oauthSettingsStore.js +3 -0
- package/dist/services/oauthSettingsStore.js.map +1 -1
- package/dist/services/sseService.js +63 -7
- package/dist/services/sseService.js.map +1 -1
- package/dist/utils/cacheUtils.js +133 -5
- package/dist/utils/cacheUtils.js.map +1 -1
- package/dist/utils/groupAccess.js +17 -0
- package/dist/utils/groupAccess.js.map +1 -0
- package/dist/utils/migration.js +3 -0
- package/dist/utils/migration.js.map +1 -1
- package/dist/utils/rateLimit.js +85 -18
- package/dist/utils/rateLimit.js.map +1 -1
- package/dist/utils/smartRouting.js +1 -1
- package/dist/utils/smartRouting.js.map +1 -1
- package/frontend/dist/assets/{ActivityPage-ZRx6b9hm.js → ActivityPage-BZNq-eGE.js} +2 -2
- package/frontend/dist/assets/{ActivityPage-ZRx6b9hm.js.map → ActivityPage-BZNq-eGE.js.map} +1 -1
- package/frontend/dist/assets/{CredentialsPage-C9vnh01H.js → CredentialsPage-7kyDJLsX.js} +2 -2
- package/frontend/dist/assets/{CredentialsPage-C9vnh01H.js.map → CredentialsPage-7kyDJLsX.js.map} +1 -1
- package/frontend/dist/assets/{Dashboard-BDGDQNz1.js → Dashboard-CElNx820.js} +2 -2
- package/frontend/dist/assets/{Dashboard-BDGDQNz1.js.map → Dashboard-CElNx820.js.map} +1 -1
- package/frontend/dist/assets/{EndpointCopy-BY51t0Ks.js → EndpointCopy-8jW5Xtka.js} +2 -2
- package/frontend/dist/assets/{EndpointCopy-BY51t0Ks.js.map → EndpointCopy-8jW5Xtka.js.map} +1 -1
- package/frontend/dist/assets/GroupsPage-dUkvX_iB.js +33 -0
- package/frontend/dist/assets/GroupsPage-dUkvX_iB.js.map +1 -0
- package/frontend/dist/assets/{LoginPage-CZOKlkR_.js → LoginPage-D23s7oM0.js} +2 -2
- package/frontend/dist/assets/{LoginPage-CZOKlkR_.js.map → LoginPage-D23s7oM0.js.map} +1 -1
- package/frontend/dist/assets/{LogsPage-FDWOOIPg.js → LogsPage-BuQMkmV-.js} +2 -2
- package/frontend/dist/assets/{LogsPage-FDWOOIPg.js.map → LogsPage-BuQMkmV-.js.map} +1 -1
- package/frontend/dist/assets/{MarketPage-DKfZgoIs.js → MarketPage-g9vEYzIq.js} +2 -2
- package/frontend/dist/assets/{MarketPage-DKfZgoIs.js.map → MarketPage-g9vEYzIq.js.map} +1 -1
- package/frontend/dist/assets/{OAuthConsentPage-Hk_DJ0dW.js → OAuthConsentPage-BiX1lpJR.js} +2 -2
- package/frontend/dist/assets/{OAuthConsentPage-Hk_DJ0dW.js.map → OAuthConsentPage-BiX1lpJR.js.map} +1 -1
- package/frontend/dist/assets/{PromptsPage-CT0C0_BI.js → PromptsPage-g8SRFY6s.js} +2 -2
- package/frontend/dist/assets/{PromptsPage-CT0C0_BI.js.map → PromptsPage-g8SRFY6s.js.map} +1 -1
- package/frontend/dist/assets/{ResourcesPage-CBgu-N5m.js → ResourcesPage-Ddhxi9Sf.js} +2 -2
- package/frontend/dist/assets/{ResourcesPage-CBgu-N5m.js.map → ResourcesPage-Ddhxi9Sf.js.map} +1 -1
- package/frontend/dist/assets/{ServersPage-CvcP8LFv.js → ServersPage-DAmKvrPV.js} +8 -8
- package/frontend/dist/assets/ServersPage-DAmKvrPV.js.map +1 -0
- package/frontend/dist/assets/SettingsPage-DZXjQZXS.js +12 -0
- package/frontend/dist/assets/SettingsPage-DZXjQZXS.js.map +1 -0
- package/frontend/dist/assets/{StatusDot-uIIW4IuH.js → StatusDot-CdzMqjTi.js} +2 -2
- package/frontend/dist/assets/{StatusDot-uIIW4IuH.js.map → StatusDot-CdzMqjTi.js.map} +1 -1
- package/frontend/dist/assets/{ToggleGroup-BToroeZy.js → ToggleGroup-CJd8X_31.js} +2 -2
- package/frontend/dist/assets/{ToggleGroup-BToroeZy.js.map → ToggleGroup-CJd8X_31.js.map} +1 -1
- package/frontend/dist/assets/{UsersPage-BjgJjf6L.js → UsersPage-CkP_x9Rt.js} +2 -2
- package/frontend/dist/assets/{UsersPage-BjgJjf6L.js.map → UsersPage-CkP_x9Rt.js.map} +1 -1
- package/frontend/dist/assets/index-Bu4XuAH4.js +3 -0
- package/frontend/dist/assets/index-Bu4XuAH4.js.map +1 -0
- package/frontend/dist/assets/{resourceService-sD9dxx3E.js → resourceService-w-cZ31FD.js} +2 -2
- package/frontend/dist/assets/{resourceService-sD9dxx3E.js.map → resourceService-w-cZ31FD.js.map} +1 -1
- package/frontend/dist/assets/{useCostData-QoPbsqyD.js → useCostData-C72NC0PQ.js} +2 -2
- package/frontend/dist/assets/{useCostData-QoPbsqyD.js.map → useCostData-C72NC0PQ.js.map} +1 -1
- package/frontend/dist/assets/useSettingsData-JTEMu74D.js +2 -0
- package/frontend/dist/assets/{useSettingsData-C4JrLqDh.js.map → useSettingsData-JTEMu74D.js.map} +1 -1
- package/frontend/dist/assets/{variableDetection-iFAhGAKs.js → variableDetection-DfhNyFy-.js} +2 -2
- package/frontend/dist/assets/{variableDetection-iFAhGAKs.js.map → variableDetection-DfhNyFy-.js.map} +1 -1
- package/frontend/dist/index.html +1 -1
- package/mcp_settings.json +2 -1
- package/package.json +1 -1
- package/frontend/dist/assets/GroupsPage-DyHyW7NW.js +0 -33
- package/frontend/dist/assets/GroupsPage-DyHyW7NW.js.map +0 -1
- package/frontend/dist/assets/ServersPage-CvcP8LFv.js.map +0 -1
- package/frontend/dist/assets/SettingsPage-DDSVt_xk.js +0 -12
- package/frontend/dist/assets/SettingsPage-DDSVt_xk.js.map +0 -1
- package/frontend/dist/assets/index-DjNOC0Ov.js +0 -3
- package/frontend/dist/assets/index-DjNOC0Ov.js.map +0 -1
- package/frontend/dist/assets/useSettingsData-C4JrLqDh.js +0 -2
package/README.fr.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
> Une passerelle et un plan de contrôle MCP open source et auto-hébergés pour connecter, contrôler et exploiter des serveurs MCP.
|
|
4
4
|
|
|
5
|
+
[](https://github.com/samanhappy/mcphub/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/@samanhappy/mcphub)
|
|
7
|
+
[](https://hub.docker.com/r/samanhappy/mcphub)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://discord.gg/2BJehJZVH5)
|
|
10
|
+
[](https://github.com/samanhappy/mcphub/stargazers)
|
|
11
|
+
|
|
5
12
|
[English](README.md) | Français | [中文版](README.zh.md)
|
|
6
13
|
|
|
7
14
|
MCPHub offre une manière unifiée de connecter et de gérer plusieurs serveurs MCP, de les organiser en groupes, de contrôler les accès et d'exposer des points de terminaison MCP stables aux clients tels que Claude Code, Cursor, Cherry Studio, OpenWebUI et autres applications compatibles MCP.
|
|
@@ -10,33 +17,59 @@ MCPHub offre une manière unifiée de connecter et de gérer plusieurs serveurs
|
|
|
10
17
|
|
|
11
18
|
## 🌐 Démo en direct et Documentation
|
|
12
19
|
|
|
13
|
-
- **
|
|
20
|
+
- **Site web** : [mcphub.app](https://www.mcphub.app/)
|
|
14
21
|
- **Documentation** : [docs.mcphub.app](https://docs.mcphub.app/)
|
|
15
22
|
- **Environnement de démo** : [demo.mcphub.app](https://demo.mcphub.app/)
|
|
16
23
|
|
|
17
24
|
## 🚀 Fonctionnalités
|
|
18
25
|
|
|
26
|
+
### Connecter une fois, exposer partout
|
|
27
|
+
|
|
28
|
+
- **Routage intelligent** ⭐ - Découverte d'outils propulsée par IA utilisant la recherche sémantique vectorielle ([En savoir plus](https://docs.mcphub.app/features/smart-routing))
|
|
19
29
|
- **Passerelle MCP unifiée** - Exposez tous les serveurs connectés via des points de terminaison MCP stables, avec des routes pour les groupes et les serveurs individuels
|
|
20
|
-
- **
|
|
30
|
+
- **Alias et routage des serveurs** - Définissez des alias et routez les clients vers tous les serveurs, des groupes, un serveur individuel ou le routage intelligent
|
|
21
31
|
- **Prise en charge SSE / Streamable HTTP / stdio** - Connectez des serveurs MCP locaux et distants via les transports pris en charge
|
|
32
|
+
- **Configuration à chaud** - Ajoutez, supprimez ou mettez à jour les serveurs sans temps d'arrêt
|
|
33
|
+
|
|
34
|
+
### Contrôler les accès et les identifiants
|
|
35
|
+
|
|
36
|
+
- **Identifiants personnels** ⭐ - Associez une clé par utilisateur à un serveur partagé, avec stockage chiffré et processus stdio isolés ([En savoir plus](docs/features/per-user-credentials.mdx))
|
|
22
37
|
- **Authentification et contrôle d'accès** - Utilisez OAuth 2.0, des bearer keys et la visibilité des serveurs ou groupes pour gérer les accès
|
|
23
|
-
- **
|
|
38
|
+
- **Support OAuth 2.0** ⭐ - Modes client et serveur pour une authentification sécurisée ([En savoir plus](https://docs.mcphub.app/features/oauth))
|
|
39
|
+
- **Connexion sociale** - Support de connexion GitHub et Google via Better Auth (nécessite le mode Base de données)
|
|
40
|
+
- **Gestion des serveurs et des groupes** - Organisez les serveurs en groupes, gérez leur visibilité et contrôlez l'exposition des Tools, Prompts et Resources
|
|
41
|
+
|
|
42
|
+
### Exploiter en confiance
|
|
43
|
+
|
|
24
44
|
- **Journaux et observabilité** - Consultez l'activité des appels d'outils, l'état des requêtes, la latence et les journaux des serveurs
|
|
25
45
|
- **Vérifications de santé** - Surveillez la santé des connexions et l'état des serveurs depuis un même endroit
|
|
26
46
|
- **Tableau de bord Web** - Gérez la configuration et le fonctionnement des serveurs depuis un navigateur
|
|
27
|
-
- **Routage intelligent** - Découverte d'outils propulsée par IA utilisant la recherche sémantique vectorielle ([En savoir plus](https://docs.mcphub.app/features/smart-routing))
|
|
28
47
|
- **Compression des résultats d'outils** - Réduisez automatiquement les grands résultats texte avant qu'ils n'atteignent les clients
|
|
29
|
-
- **Configuration à chaud** - Ajoutez, supprimez ou mettez à jour les serveurs sans temps d'arrêt
|
|
30
|
-
- **Support OAuth 2.0** - Modes client et serveur pour une authentification sécurisée ([En savoir plus](https://docs.mcphub.app/features/oauth))
|
|
31
|
-
- **Connexion Sociale** - Support de connexion GitHub et Google via Better Auth (nécessite le mode Base de données)
|
|
32
48
|
- **Mode Base de données** - Stockez la configuration dans PostgreSQL pour les environnements de production ([En savoir plus](https://docs.mcphub.app/configuration/database-configuration))
|
|
33
49
|
- **Prêt pour Docker** - Déployez instantanément avec la configuration conteneurisée
|
|
34
50
|
|
|
35
51
|
## 🔧 Démarrage rapide
|
|
36
52
|
|
|
53
|
+
### Prérequis
|
|
54
|
+
|
|
55
|
+
- **Docker** (recommandé) — le moyen le plus rapide d'exécuter MCPHub ; toutes les commandes ci-dessous l'utilisent
|
|
56
|
+
- **Node.js** `^18.0.0 || >=20.0.0` et **pnpm** `10.12.4` — uniquement pour exécuter depuis les sources ou développer localement (voir [Développement local](#développement-local))
|
|
57
|
+
|
|
58
|
+
### Démarrer avec Docker
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
docker run -p 3000:3000 -v ./data:/app/data samanhappy/mcphub
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Ouvrez `http://localhost:3000` et connectez-vous avec le nom d'utilisateur `admin`. Au premier lancement, si la variable d'environnement `ADMIN_PASSWORD` n'est pas définie, un mot de passe aléatoire est généré et affiché dans les logs du serveur.
|
|
65
|
+
|
|
66
|
+
La configuration, les utilisateurs et les identifiants persistent dans `./data` par défaut.
|
|
67
|
+
|
|
68
|
+
Avec vos propres serveurs ? Avant le premier lancement, créez `data/mcp_settings.json` (voir [Configuration](#configuration)). Ensuite, ajoutez des serveurs dans le tableau de bord ou modifiez le fichier existant et redémarrez MCPHub.
|
|
69
|
+
|
|
37
70
|
### Configuration
|
|
38
71
|
|
|
39
|
-
|
|
72
|
+
Avant le premier lancement, créez `data/mcp_settings.json` :
|
|
40
73
|
|
|
41
74
|
```json
|
|
42
75
|
{
|
|
@@ -57,13 +90,7 @@ Créez un fichier `mcp_settings.json` :
|
|
|
57
90
|
|
|
58
91
|
### Déploiement avec Docker
|
|
59
92
|
|
|
60
|
-
|
|
61
|
-
# Exécutez avec une configuration personnalisée (recommandé)
|
|
62
|
-
docker run -p 3000:3000 -v ./mcp_settings.json:/app/mcp_settings.json -v ./data:/app/data samanhappy/mcphub
|
|
63
|
-
|
|
64
|
-
# Ou exécutez avec les paramètres par défaut (montez ./data pour préserver l'état entre redémarrages)
|
|
65
|
-
docker run -p 3000:3000 -v ./data:/app/data samanhappy/mcphub
|
|
66
|
-
```
|
|
93
|
+
Voir [Démarrer avec Docker](#démarrer-avec-docker) pour la commande prête à copier. Gardez `./data` monté pour conserver la configuration, les utilisateurs et les identifiants après la recréation du conteneur.
|
|
67
94
|
|
|
68
95
|
Deux variantes d'image sont publiées sous `samanhappy/mcphub` :
|
|
69
96
|
|
|
@@ -74,11 +101,11 @@ Voir [Configuration Docker](https://docs.mcphub.app/configuration/docker-setup)
|
|
|
74
101
|
|
|
75
102
|
### Accéder au tableau de bord
|
|
76
103
|
|
|
77
|
-
Ouvrez `http://localhost:3000`
|
|
104
|
+
Ouvrez `http://localhost:3000` (voir [Démarrer avec Docker](#démarrer-avec-docker) pour la connexion). Vous pouvez également prédéfinir le mot de passe :
|
|
78
105
|
|
|
79
106
|
```bash
|
|
80
107
|
# Docker : définir le mot de passe admin via une variable d'environnement
|
|
81
|
-
docker run -p 3000:3000 -e ADMIN_PASSWORD=your-secure-password samanhappy/mcphub
|
|
108
|
+
docker run -p 3000:3000 -v ./data:/app/data -e ADMIN_PASSWORD=your-secure-password samanhappy/mcphub
|
|
82
109
|
```
|
|
83
110
|
|
|
84
111
|
> **Conseil :** Changez le mot de passe admin après la première connexion pour plus de sécurité.
|
|
@@ -110,6 +137,7 @@ http://localhost:3000/mcp/$smart/{group} # Routage intelligent dans un groupe
|
|
|
110
137
|
| [Mode Base de données](https://docs.mcphub.app/configuration/database-configuration) | Configuration PostgreSQL pour la production |
|
|
111
138
|
| [OAuth](https://docs.mcphub.app/features/oauth) | Configuration client et serveur OAuth 2.0 |
|
|
112
139
|
| [Routage intelligent](https://docs.mcphub.app/features/smart-routing) | Découverte d'outils propulsée par IA |
|
|
140
|
+
| [Guide CLI](https://docs.mcphub.app/features/cli) | Gérer et appeler le hub depuis un terminal |
|
|
113
141
|
| [Configuration Docker](https://docs.mcphub.app/configuration/docker-setup) | Guide de déploiement Docker |
|
|
114
142
|
|
|
115
143
|
## 🧑💻 Développement local
|
|
@@ -143,6 +171,8 @@ Les contributions sont les bienvenues ! Rejoignez notre [communauté Discord](ht
|
|
|
143
171
|
|
|
144
172
|
[](https://ko-fi.com/samanhappy)
|
|
145
173
|
|
|
174
|
+
Les utilisateurs en Chine peuvent aussi soutenir via WeChat Pay — voir [中文版](README.zh.md).
|
|
175
|
+
|
|
146
176
|
## 🌟 Historique des étoiles
|
|
147
177
|
|
|
148
178
|
[](https://star-history.dera.page/#samanhappy/mcphub&Date)
|
package/README.md
CHANGED
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
> An open-source, self-hosted MCP gateway and control plane for connecting, controlling, and operating MCP servers.
|
|
4
4
|
|
|
5
|
-
[](https://github.com/samanhappy/mcphub/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/@samanhappy/mcphub)
|
|
7
|
+
[](https://hub.docker.com/r/samanhappy/mcphub)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://discord.gg/2BJehJZVH5)
|
|
10
|
+
[](https://github.com/samanhappy/mcphub/stargazers)
|
|
6
11
|
|
|
7
12
|
English | [Français](README.fr.md) | [中文版](README.zh.md)
|
|
8
13
|
|
|
@@ -20,29 +25,54 @@ It works with MCP clients such as Claude Code, Cursor, Cherry Studio, OpenWebUI,
|
|
|
20
25
|
|
|
21
26
|
## 🚀 Features
|
|
22
27
|
|
|
28
|
+
### Connect once, expose everywhere
|
|
29
|
+
|
|
30
|
+
- **Smart Routing** ⭐ - AI-powered tool discovery using vector semantic search ([Learn more](https://docs.mcphub.app/features/smart-routing))
|
|
23
31
|
- **Unified MCP Gateway** - Expose all connected servers through stable MCP endpoints, including routes for groups and individual servers
|
|
32
|
+
- **Server Aliases and Routing** - Define aliases and route clients to all servers, specific groups, individual servers, or smart routing
|
|
33
|
+
- **SSE / Streamable HTTP / stdio Support** - Connect local and remote MCP servers over the supported transports
|
|
34
|
+
- **Hot-Swappable Config** - Add, remove, or update servers without downtime
|
|
35
|
+
|
|
36
|
+
### Control access and credentials
|
|
37
|
+
|
|
38
|
+
- **Per-user Credentials** ⭐ - Bind personal keys to one shared server, with encrypted storage and isolated stdio runtimes ([Learn more](docs/features/per-user-credentials.mdx))
|
|
24
39
|
- **Authentication and Access Control** - Use OAuth 2.0, bearer keys, and server or group visibility controls to manage access
|
|
25
|
-
- **
|
|
40
|
+
- **OAuth 2.0 Support** ⭐ - Both client and server modes for secure authentication ([Learn more](https://docs.mcphub.app/features/oauth))
|
|
41
|
+
- **Social Login** - Seamless GitHub and Google login support with Better Auth integration (requires Database Mode)
|
|
26
42
|
- **Server and Group Management** - Organize servers into groups, manage visibility, and control Tool, Prompt, and Resource exposure
|
|
27
|
-
|
|
28
|
-
|
|
43
|
+
|
|
44
|
+
### Operate with confidence
|
|
45
|
+
|
|
29
46
|
- **Logs and Observability** - Inspect tool-call activity, request status, latency, and server logs
|
|
30
47
|
- **Health Checks** - Monitor connection health and server status from one place
|
|
31
48
|
- **Web Dashboard** - Manage server configuration and runtime operations from a browser
|
|
32
|
-
- **Smart Routing** - AI-powered tool discovery using vector semantic search ([Learn more](https://docs.mcphub.app/features/smart-routing))
|
|
33
49
|
- **MCP Apps Proxy** - Transparently forward interactive MCP Apps on single-server routes ([Learn more](https://docs.mcphub.app/features/mcp-apps))
|
|
34
50
|
- **Tool Result Compression** - Transparently reduce large text tool outputs before they reach clients
|
|
35
|
-
- **Hot-Swappable Config** - Add, remove, or update servers without downtime
|
|
36
|
-
- **OAuth 2.0 Support** - Both client and server modes for secure authentication ([Learn more](https://docs.mcphub.app/features/oauth))
|
|
37
|
-
- **Social Login** - Seamless GitHub and Google login support with Better Auth integration (requires Database Mode)
|
|
38
51
|
- **Database Mode** - Store configuration in PostgreSQL for production environments ([Learn more](https://docs.mcphub.app/configuration/database-configuration))
|
|
39
52
|
- **Docker-Ready** - Deploy instantly with containerized setup
|
|
40
53
|
|
|
41
54
|
## 🔧 Quick Start
|
|
42
55
|
|
|
56
|
+
### Prerequisites
|
|
57
|
+
|
|
58
|
+
- **Docker** (recommended) — the fastest way to run MCPHub; all commands below use it
|
|
59
|
+
- **Node.js** `^18.0.0 || >=20.0.0` and **pnpm** `10.12.4` — only needed to run from source or develop locally (see [Local Development](#local-development))
|
|
60
|
+
|
|
61
|
+
### Start with Docker
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
docker run -p 3000:3000 -v ./data:/app/data samanhappy/mcphub
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Open `http://localhost:3000` and log in with username `admin`. On first launch, if no `ADMIN_PASSWORD` environment variable is set, a random password is generated and printed to the server logs.
|
|
68
|
+
|
|
69
|
+
Settings, users, and credential bindings persist in `./data` by default.
|
|
70
|
+
|
|
71
|
+
Want your own servers? Before the first launch, create `data/mcp_settings.json` (see [Configuration](#configuration)). After launch, add servers in the dashboard or edit the existing file and restart MCPHub.
|
|
72
|
+
|
|
43
73
|
### Configuration
|
|
44
74
|
|
|
45
|
-
Create
|
|
75
|
+
Create `data/mcp_settings.json` before the first launch:
|
|
46
76
|
|
|
47
77
|
```json
|
|
48
78
|
{
|
|
@@ -63,13 +93,7 @@ Create a `mcp_settings.json` file:
|
|
|
63
93
|
|
|
64
94
|
### Docker Deployment
|
|
65
95
|
|
|
66
|
-
|
|
67
|
-
# Run with custom config (recommended)
|
|
68
|
-
docker run -p 3000:3000 -v ./mcp_settings.json:/app/mcp_settings.json -v ./data:/app/data samanhappy/mcphub
|
|
69
|
-
|
|
70
|
-
# Or run with default settings (also mount ./data so credentials and state survive restarts)
|
|
71
|
-
docker run -p 3000:3000 -v ./data:/app/data samanhappy/mcphub
|
|
72
|
-
```
|
|
96
|
+
See [Start with Docker](#start-with-docker) for the copy-paste command. Keep `./data` mounted so settings, users, and credential bindings survive container recreation.
|
|
73
97
|
|
|
74
98
|
Two image variants are published under `samanhappy/mcphub`:
|
|
75
99
|
|
|
@@ -80,11 +104,11 @@ See [Docker Setup](https://docs.mcphub.app/configuration/docker-setup) for build
|
|
|
80
104
|
|
|
81
105
|
### Access Dashboard
|
|
82
106
|
|
|
83
|
-
Open `http://localhost:3000`
|
|
107
|
+
Open `http://localhost:3000` (see [Start with Docker](#start-with-docker) for login details). You can also pre-set the password:
|
|
84
108
|
|
|
85
109
|
```bash
|
|
86
110
|
# Docker: set admin password via environment variable
|
|
87
|
-
docker run -p 3000:3000 -e ADMIN_PASSWORD=your-secure-password samanhappy/mcphub
|
|
111
|
+
docker run -p 3000:3000 -v ./data:/app/data -e ADMIN_PASSWORD=your-secure-password samanhappy/mcphub
|
|
88
112
|
```
|
|
89
113
|
|
|
90
114
|
> **Tip:** Change the admin password after first login for security.
|
|
@@ -107,24 +131,6 @@ http://localhost:3000/mcp/$smart/{group} # Smart routing within group
|
|
|
107
131
|
|
|
108
132
|
📖 See [API Reference](https://docs.mcphub.app/api-reference) for detailed endpoint documentation.
|
|
109
133
|
|
|
110
|
-
### Manage From the Terminal
|
|
111
|
-
|
|
112
|
-
The same `mcphub` binary doubles as a CLI for the running hub — no extra install needed.
|
|
113
|
-
|
|
114
|
-
```bash
|
|
115
|
-
mcphub login --url http://localhost:3000 --username admin
|
|
116
|
-
mcphub servers list
|
|
117
|
-
mcphub servers add fetch --type stdio --command uvx --arg mcp-server-fetch
|
|
118
|
-
mcphub tools list # discover what tools are available
|
|
119
|
-
mcphub tools get fetch_url # see required params + sample command
|
|
120
|
-
mcphub call fetch_url url=https://example.com --json
|
|
121
|
-
mcphub keys create --name ci --access-type all
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
It also speaks the public marketplace API (`mcphub discover`, `mcphub install ...`) so server lookup and one-command install work against any hub with discovery enabled.
|
|
125
|
-
|
|
126
|
-
📖 See [CLI Guide](https://docs.mcphub.app/features/cli) for every subcommand, profiles, and CI usage.
|
|
127
|
-
|
|
128
134
|
## 📚 Documentation
|
|
129
135
|
|
|
130
136
|
| Topic | Description |
|
|
@@ -178,6 +184,8 @@ Contributions welcome! See our [Discord community](https://discord.gg/2BJehJZVH5
|
|
|
178
184
|
|
|
179
185
|
[](https://ko-fi.com/samanhappy)
|
|
180
186
|
|
|
187
|
+
Chinese users can also support via WeChat Pay — see [中文版](README.zh.md).
|
|
188
|
+
|
|
181
189
|
## 🌟 Star History
|
|
182
190
|
|
|
183
191
|
[](https://star-history.dera.page/#samanhappy/mcphub&Date)
|
package/README.zh.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
> 开源、自托管的 MCP 网关与控制平面,用于连接、控制和运行 MCP 服务器。
|
|
4
4
|
|
|
5
|
+
[](https://github.com/samanhappy/mcphub/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/@samanhappy/mcphub)
|
|
7
|
+
[](https://hub.docker.com/r/samanhappy/mcphub)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://discord.gg/2BJehJZVH5)
|
|
10
|
+
[](https://github.com/samanhappy/mcphub/stargazers)
|
|
11
|
+
|
|
5
12
|
[English](README.md) | [Français](README.fr.md) | 中文版
|
|
6
13
|
|
|
7
14
|
MCPHub 是 AI 客户端与 MCP 服务器之间的统一控制点。一次连接本地和远程 MCP 服务器,通过稳定端点组织和路由其能力,借助身份认证、限定作用域的凭据和用户级可见性控制访问,并通过集中日志、活动追踪和健康监控统一运行与管理。
|
|
@@ -18,28 +25,53 @@ MCPHub 是 AI 客户端与 MCP 服务器之间的统一控制点。一次连接
|
|
|
18
25
|
|
|
19
26
|
## 🚀 功能亮点
|
|
20
27
|
|
|
28
|
+
### 一次连接,随处暴露
|
|
29
|
+
|
|
30
|
+
- **智能路由** ⭐ - 基于向量语义搜索的 AI 工具发现 ([了解更多](https://docs.mcphub.app/zh/features/smart-routing))
|
|
21
31
|
- **统一 MCP 网关** - 通过稳定的 MCP 端点暴露所有已连接的服务器,也支持分组和单服务器路由
|
|
32
|
+
- **服务器别名与路由** - 设置别名,并将客户端路由到所有服务器、指定分组、单个服务器或智能路由
|
|
33
|
+
- **SSE / Streamable HTTP / stdio 支持** - 通过支持的传输方式连接本地和远程 MCP 服务器
|
|
34
|
+
- **热插拔配置** - 无需停机即可添加、移除或更新服务器
|
|
35
|
+
|
|
36
|
+
### 管控访问与凭据
|
|
37
|
+
|
|
38
|
+
- **个人凭据** ⭐ - 一个共享服务器支持每位用户独立绑定密钥,加密保存并隔离 stdio 运行进程([了解更多](docs/zh/features/per-user-credentials.mdx))
|
|
22
39
|
- **身份认证与访问控制** - 使用 OAuth 2.0、Bearer Key 以及服务器或分组可见性控制访问权限
|
|
23
|
-
-
|
|
40
|
+
- **OAuth 2.0 支持** ⭐ - 客户端和服务端模式,实现安全认证 ([了解更多](https://docs.mcphub.app/zh/features/oauth))
|
|
41
|
+
- **社交一键登录** - 通过 Better Auth 集成支持 GitHub 和 Google 快捷登录(需启用数据库模式)
|
|
24
42
|
- **服务器与分组管理** - 组织服务器分组,管理可见性,并控制 Tool、Prompt 与 Resource 的暴露范围
|
|
25
|
-
|
|
26
|
-
|
|
43
|
+
|
|
44
|
+
### 稳定运行
|
|
45
|
+
|
|
27
46
|
- **日志与可观测性** - 查看工具调用活动、请求状态、延迟和服务器日志
|
|
28
47
|
- **健康检查** - 在一个地方监控连接健康状况和服务器状态
|
|
29
48
|
- **Web 控制台** - 通过浏览器管理服务器配置和运行状态
|
|
30
|
-
- **智能路由** - 基于向量语义搜索的 AI 工具发现 ([了解更多](https://docs.mcphub.app/zh/features/smart-routing))
|
|
31
49
|
- **工具结果压缩** - 在返回客户端前透明压缩大型文本工具输出
|
|
32
|
-
- **热插拔配置** - 无需停机即可添加、移除或更新服务器
|
|
33
|
-
- **OAuth 2.0 支持** - 客户端和服务端模式,实现安全认证 ([了解更多](https://docs.mcphub.app/zh/features/oauth))
|
|
34
|
-
- **社交一键登录** - 通过 Better Auth 集成支持 GitHub 和 Google 快捷登录(需启用数据库模式)
|
|
35
50
|
- **数据库模式** - 将配置存储在 PostgreSQL 中,适用于生产环境 ([了解更多](https://docs.mcphub.app/zh/configuration/database-configuration))
|
|
36
51
|
- **Docker 就绪** - 容器化部署,开箱即用
|
|
37
52
|
|
|
38
53
|
## 🔧 快速开始
|
|
39
54
|
|
|
55
|
+
### 前置条件
|
|
56
|
+
|
|
57
|
+
- **Docker**(推荐)—— 运行 MCPHub 最快的方式,下面的命令都基于它
|
|
58
|
+
- **Node.js** `^18.0.0 || >=20.0.0` 和 **pnpm** `10.12.4` —— 仅从源码运行或参与本地开发时需要(见[本地开发](#本地开发))
|
|
59
|
+
|
|
60
|
+
### 使用 Docker 启动
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
docker run -p 3000:3000 -v ./data:/app/data samanhappy/mcphub
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
打开 `http://localhost:3000`,使用用户名 `admin` 登录。首次启动时,如果未设置 `ADMIN_PASSWORD` 环境变量,系统将自动生成随机密码并输出到服务器日志中。
|
|
67
|
+
|
|
68
|
+
配置、用户和凭据绑定默认持久化到 `./data`。
|
|
69
|
+
|
|
70
|
+
想用自己的服务器?首次启动前,创建 `data/mcp_settings.json`(见[配置](#配置))。启动后,可在控制台添加服务器,或编辑现有配置文件并重启 MCPHub。
|
|
71
|
+
|
|
40
72
|
### 配置
|
|
41
73
|
|
|
42
|
-
|
|
74
|
+
首次启动前,创建 `data/mcp_settings.json` 文件:
|
|
43
75
|
|
|
44
76
|
```json
|
|
45
77
|
{
|
|
@@ -60,13 +92,7 @@ MCPHub 是 AI 客户端与 MCP 服务器之间的统一控制点。一次连接
|
|
|
60
92
|
|
|
61
93
|
### Docker 部署
|
|
62
94
|
|
|
63
|
-
|
|
64
|
-
# 挂载自定义配置运行(推荐)
|
|
65
|
-
docker run -p 3000:3000 -v ./mcp_settings.json:/app/mcp_settings.json -v ./data:/app/data samanhappy/mcphub
|
|
66
|
-
|
|
67
|
-
# 或使用默认配置运行(仍建议挂载 ./data,避免容器删除后数据丢失)
|
|
68
|
-
docker run -p 3000:3000 -v ./data:/app/data samanhappy/mcphub
|
|
69
|
-
```
|
|
95
|
+
可复制的命令见[使用 Docker 启动](#使用-docker-启动)。请保持挂载 `./data`,这样配置、用户和凭据绑定在容器重建后不会丢失。
|
|
70
96
|
|
|
71
97
|
`samanhappy/mcphub` 提供两种镜像变体:
|
|
72
98
|
|
|
@@ -77,11 +103,11 @@ docker run -p 3000:3000 -v ./data:/app/data samanhappy/mcphub
|
|
|
77
103
|
|
|
78
104
|
### 访问控制台
|
|
79
105
|
|
|
80
|
-
打开 `http://localhost:3000
|
|
106
|
+
打开 `http://localhost:3000`(登录方式见[使用 Docker 启动](#使用-docker-启动))。也可以预先设置密码:
|
|
81
107
|
|
|
82
108
|
```bash
|
|
83
109
|
# Docker:通过环境变量设置管理员密码
|
|
84
|
-
docker run -p 3000:3000 -e ADMIN_PASSWORD=your-secure-password samanhappy/mcphub
|
|
110
|
+
docker run -p 3000:3000 -v ./data:/app/data -e ADMIN_PASSWORD=your-secure-password samanhappy/mcphub
|
|
85
111
|
```
|
|
86
112
|
|
|
87
113
|
> **提示:** 首次登录后请及时修改管理员密码以确保安全。
|
|
@@ -104,24 +130,6 @@ http://localhost:3000/mcp/$smart/{group} # 智能路由(特定分组)
|
|
|
104
130
|
|
|
105
131
|
📖 查看 [API 参考](https://docs.mcphub.app/zh/api-reference)了解详细的端点文档。
|
|
106
132
|
|
|
107
|
-
### 终端管理
|
|
108
|
-
|
|
109
|
-
`mcphub` 同一个二进制兼任 CLI,无需额外安装。
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
mcphub login --url http://localhost:3000 --username admin
|
|
113
|
-
mcphub servers list
|
|
114
|
-
mcphub servers add fetch --type stdio --command uvx --arg mcp-server-fetch
|
|
115
|
-
mcphub tools list # 看有哪些 tool 可调
|
|
116
|
-
mcphub tools get fetch_url # 看必填参数和样例命令
|
|
117
|
-
mcphub call fetch_url url=https://example.com --json
|
|
118
|
-
mcphub keys create --name ci --access-type all
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
CLI 同样对接公共市场接口(`mcphub discover`、`mcphub install ...`),可对任意开启了 discovery 的 hub 做检索与一键安装。
|
|
122
|
-
|
|
123
|
-
📖 查看 [CLI 指南](https://docs.mcphub.app/zh/features/cli)了解全部子命令、profile 管理与 CI 用法。
|
|
124
|
-
|
|
125
133
|
## 📚 文档
|
|
126
134
|
|
|
127
135
|
| 主题 | 描述 |
|
|
@@ -176,6 +184,8 @@ pnpm dev
|
|
|
176
184
|
|
|
177
185
|
<img src="assets/reward.png" width="350">
|
|
178
186
|
|
|
187
|
+
海外用户可通过 [ko-fi](https://ko-fi.com/samanhappy) 支持。
|
|
188
|
+
|
|
179
189
|
## 致谢
|
|
180
190
|
|
|
181
191
|
感谢以下朋友的赞赏:小白、唐秀川、琛、孔、黄祥取、兰军飞、无名之辈、Kyle,以及其他匿名支持者。
|
|
@@ -10,6 +10,7 @@ export const DEFAULT_OAUTH_SERVER_CONFIG = {
|
|
|
10
10
|
enabled: true,
|
|
11
11
|
allowedGrantTypes: ['authorization_code', 'refresh_token'],
|
|
12
12
|
requiresAuthentication: false,
|
|
13
|
+
clientTtl: 2592000, // 30 days: reap idle dynamically-registered clients with no live tokens
|
|
13
14
|
},
|
|
14
15
|
clientIdMetadata: {
|
|
15
16
|
enabled: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauthServerDefaults.js","sourceRoot":"","sources":["../../src/constants/oauthServerDefaults.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,2BAA2B,GAAsB;IAC5D,OAAO,EAAE,IAAI;IACb,mBAAmB,EAAE,IAAI;IACzB,oBAAoB,EAAE,OAAO;IAC7B,yBAAyB,EAAE,GAAG;IAC9B,mBAAmB,EAAE,KAAK;IAC1B,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;IAChC,YAAY,EAAE,KAAK;IACnB,mBAAmB,EAAE;QACnB,OAAO,EAAE,IAAI;QACb,iBAAiB,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;QAC1D,sBAAsB,EAAE,KAAK;
|
|
1
|
+
{"version":3,"file":"oauthServerDefaults.js","sourceRoot":"","sources":["../../src/constants/oauthServerDefaults.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,2BAA2B,GAAsB;IAC5D,OAAO,EAAE,IAAI;IACb,mBAAmB,EAAE,IAAI;IACzB,oBAAoB,EAAE,OAAO;IAC7B,yBAAyB,EAAE,GAAG;IAC9B,mBAAmB,EAAE,KAAK;IAC1B,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;IAChC,YAAY,EAAE,KAAK;IACnB,mBAAmB,EAAE;QACnB,OAAO,EAAE,IAAI;QACb,iBAAiB,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;QAC1D,sBAAsB,EAAE,KAAK;QAC7B,SAAS,EAAE,OAAO,EAAE,wEAAwE;KAC7F;IACD,gBAAgB,EAAE;QAChB,OAAO,EAAE,KAAK;QACd,UAAU,EAAE,OAAS;KACtB;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAsB,EAAE;IACnE,MAAM,aAAa,GAAG,2BAA2B,CAAC,aAAa;QAC7D,CAAC,CAAC,CAAC,GAAG,2BAA2B,CAAC,aAAa,CAAC;QAChD,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,uBAAuB,GAAG,2BAA2B,CAAC,mBAAmB,IAAI;QACjF,OAAO,EAAE,KAAK;QACd,iBAAiB,EAAE,EAAE;QACrB,sBAAsB,EAAE,KAAK;KAC9B,CAAC;IAEF,MAAM,mBAAmB,GAAG;QAC1B,GAAG,uBAAuB;QAC1B,iBAAiB,EAAE,uBAAuB,CAAC,iBAAiB;YAC1D,CAAC,CAAC,CAAC,GAAG,uBAAuB,CAAC,iBAAiB,CAAC;YAChD,CAAC,CAAC,EAAE;KACP,CAAC;IAEF,OAAO;QACL,GAAG,2BAA2B;QAC9B,aAAa;QACb,mBAAmB;QACnB,gBAAgB,EAAE,EAAE,GAAG,2BAA2B,CAAC,gBAAgB,EAAE;KACtE,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { getGroupDao, getUserDao } from '../dao/index.js';
|
|
2
|
+
import { validateGroupAccess } from '../utils/groupAccess.js';
|
|
1
3
|
import { logger } from '../utils/logger.js';
|
|
2
|
-
import { getAllGroups, getGroupByIdOrName, createGroup, updateGroup, updateGroupServers, deleteGroup, addServerToGroup, removeServerFromGroup, getServerConfigInGroup, getServerConfigsInGroup, updateServerToolsInGroup, } from '../services/groupService.js';
|
|
4
|
+
import { getAllGroups, presentGroup, canMutateGroup, getGroupByIdOrName, createGroup, updateGroup, updateGroupServers, deleteGroup, addServerToGroup, removeServerFromGroup, getServerConfigInGroup, getServerConfigsInGroup, updateServerToolsInGroup, } from '../services/groupService.js';
|
|
3
5
|
const isValidCapabilitySelection = (value) => {
|
|
4
6
|
return (value === undefined ||
|
|
5
7
|
value === 'all' ||
|
|
@@ -89,7 +91,12 @@ export const getGroup = async (req, res) => {
|
|
|
89
91
|
// Create a new group
|
|
90
92
|
export const createNewGroup = async (req, res) => {
|
|
91
93
|
try {
|
|
92
|
-
const { name, description, servers } = req.body;
|
|
94
|
+
const { name, description, servers, visibility, sharedWithUsers } = req.body;
|
|
95
|
+
const accessError = validateGroupAccess({ visibility, sharedWithUsers });
|
|
96
|
+
if (accessError) {
|
|
97
|
+
res.status(400).json({ success: false, message: accessError });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
93
100
|
if (!name) {
|
|
94
101
|
res.status(400).json({
|
|
95
102
|
success: false,
|
|
@@ -109,7 +116,10 @@ export const createNewGroup = async (req, res) => {
|
|
|
109
116
|
// Set owner property - use current user's username, default to 'admin'
|
|
110
117
|
const currentUser = req.user;
|
|
111
118
|
const owner = currentUser?.username || 'admin';
|
|
112
|
-
const newGroup = await createGroup(name, description, serverList, owner
|
|
119
|
+
const newGroup = await createGroup(name, description, serverList, owner, {
|
|
120
|
+
visibility,
|
|
121
|
+
sharedWithUsers,
|
|
122
|
+
});
|
|
113
123
|
if (!newGroup) {
|
|
114
124
|
res.status(400).json({
|
|
115
125
|
success: false,
|
|
@@ -119,7 +129,7 @@ export const createNewGroup = async (req, res) => {
|
|
|
119
129
|
}
|
|
120
130
|
const response = {
|
|
121
131
|
success: true,
|
|
122
|
-
data: newGroup,
|
|
132
|
+
data: await presentGroup(newGroup),
|
|
123
133
|
message: 'Group created successfully',
|
|
124
134
|
};
|
|
125
135
|
res.status(201).json(response);
|
|
@@ -198,9 +208,12 @@ export const batchCreateGroups = async (req, res) => {
|
|
|
198
208
|
const currentUser = req.user;
|
|
199
209
|
const defaultOwner = currentUser?.username || 'admin';
|
|
200
210
|
for (const groupData of groups) {
|
|
201
|
-
const { name, description, servers } = groupData;
|
|
211
|
+
const { name, description, servers, visibility, sharedWithUsers } = groupData;
|
|
202
212
|
// Validate group configuration
|
|
203
|
-
const
|
|
213
|
+
const accessError = validateGroupAccess(groupData);
|
|
214
|
+
const validation = accessError
|
|
215
|
+
? { valid: false, message: accessError }
|
|
216
|
+
: validateGroupConfig(groupData);
|
|
204
217
|
if (!validation.valid) {
|
|
205
218
|
results.push({
|
|
206
219
|
name: name || 'unknown',
|
|
@@ -212,7 +225,10 @@ export const batchCreateGroups = async (req, res) => {
|
|
|
212
225
|
}
|
|
213
226
|
try {
|
|
214
227
|
const serverList = Array.isArray(servers) ? servers : [];
|
|
215
|
-
const newGroup = await createGroup(name, description, serverList, defaultOwner
|
|
228
|
+
const newGroup = await createGroup(name, description, serverList, defaultOwner, {
|
|
229
|
+
visibility,
|
|
230
|
+
sharedWithUsers,
|
|
231
|
+
});
|
|
216
232
|
if (newGroup) {
|
|
217
233
|
results.push({
|
|
218
234
|
name,
|
|
@@ -262,7 +278,12 @@ export const batchCreateGroups = async (req, res) => {
|
|
|
262
278
|
export const updateExistingGroup = async (req, res) => {
|
|
263
279
|
try {
|
|
264
280
|
const { id } = req.params;
|
|
265
|
-
const { name, description, servers } = req.body;
|
|
281
|
+
const { name, description, servers, visibility, sharedWithUsers } = req.body;
|
|
282
|
+
const accessError = validateGroupAccess({ visibility, sharedWithUsers });
|
|
283
|
+
if (accessError) {
|
|
284
|
+
res.status(400).json({ success: false, message: accessError });
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
266
287
|
if (!id) {
|
|
267
288
|
res.status(400).json({
|
|
268
289
|
success: false,
|
|
@@ -272,6 +293,12 @@ export const updateExistingGroup = async (req, res) => {
|
|
|
272
293
|
}
|
|
273
294
|
// Allow updating servers along with other fields
|
|
274
295
|
const updateData = {};
|
|
296
|
+
if (visibility !== undefined)
|
|
297
|
+
updateData.visibility = visibility;
|
|
298
|
+
if (sharedWithUsers !== undefined)
|
|
299
|
+
updateData.sharedWithUsers = [
|
|
300
|
+
...new Set(sharedWithUsers.map((name) => name.trim())),
|
|
301
|
+
];
|
|
275
302
|
if (name !== undefined)
|
|
276
303
|
updateData.name = name;
|
|
277
304
|
if (description !== undefined)
|
|
@@ -290,7 +317,7 @@ export const updateExistingGroup = async (req, res) => {
|
|
|
290
317
|
if (Object.keys(updateData).length === 0) {
|
|
291
318
|
res.status(400).json({
|
|
292
319
|
success: false,
|
|
293
|
-
message: 'At least one field (name, description, or
|
|
320
|
+
message: 'At least one field (name, description, servers, visibility, or sharedWithUsers) is required to update',
|
|
294
321
|
});
|
|
295
322
|
return;
|
|
296
323
|
}
|
|
@@ -304,7 +331,7 @@ export const updateExistingGroup = async (req, res) => {
|
|
|
304
331
|
}
|
|
305
332
|
const response = {
|
|
306
333
|
success: true,
|
|
307
|
-
data: updatedGroup,
|
|
334
|
+
data: await presentGroup(updatedGroup),
|
|
308
335
|
message: 'Group updated successfully',
|
|
309
336
|
};
|
|
310
337
|
res.json(response);
|
|
@@ -373,7 +400,7 @@ export const updateGroupServersBatch = async (req, res) => {
|
|
|
373
400
|
}
|
|
374
401
|
const response = {
|
|
375
402
|
success: true,
|
|
376
|
-
data: updatedGroup,
|
|
403
|
+
data: await presentGroup(updatedGroup),
|
|
377
404
|
message: 'Group servers updated successfully',
|
|
378
405
|
};
|
|
379
406
|
res.json(response);
|
|
@@ -445,7 +472,7 @@ export const addServerToExistingGroup = async (req, res) => {
|
|
|
445
472
|
}
|
|
446
473
|
const response = {
|
|
447
474
|
success: true,
|
|
448
|
-
data: updatedGroup,
|
|
475
|
+
data: await presentGroup(updatedGroup),
|
|
449
476
|
message: 'Server added to group successfully',
|
|
450
477
|
};
|
|
451
478
|
res.json(response);
|
|
@@ -478,7 +505,7 @@ export const removeServerFromExistingGroup = async (req, res) => {
|
|
|
478
505
|
}
|
|
479
506
|
const response = {
|
|
480
507
|
success: true,
|
|
481
|
-
data: updatedGroup,
|
|
508
|
+
data: await presentGroup(updatedGroup),
|
|
482
509
|
message: 'Server removed from group successfully',
|
|
483
510
|
};
|
|
484
511
|
res.json(response);
|
|
@@ -610,7 +637,7 @@ export const updateGroupServerTools = async (req, res) => {
|
|
|
610
637
|
}
|
|
611
638
|
const response = {
|
|
612
639
|
success: true,
|
|
613
|
-
data: updatedGroup,
|
|
640
|
+
data: await presentGroup(updatedGroup),
|
|
614
641
|
message: 'Server tools updated successfully',
|
|
615
642
|
};
|
|
616
643
|
res.json(response);
|
|
@@ -622,4 +649,26 @@ export const updateGroupServerTools = async (req, res) => {
|
|
|
622
649
|
});
|
|
623
650
|
}
|
|
624
651
|
};
|
|
652
|
+
// Username-only candidates are restricted to the group owner/admin, like server sharing.
|
|
653
|
+
export const getGroupShareCandidates = async (req, res) => {
|
|
654
|
+
try {
|
|
655
|
+
const group = await getGroupDao().findById(req.params.id);
|
|
656
|
+
if (!group || !canMutateGroup(group)) {
|
|
657
|
+
res.status(404).json({ success: false, message: 'Group not found' });
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
const users = await getUserDao().findAll();
|
|
661
|
+
res.json({
|
|
662
|
+
success: true,
|
|
663
|
+
data: users
|
|
664
|
+
.map((user) => user.username)
|
|
665
|
+
.filter((username) => username !== group.owner)
|
|
666
|
+
.sort((a, b) => a.localeCompare(b)),
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
catch (error) {
|
|
670
|
+
logger.error('Failed to get group share candidates:', error);
|
|
671
|
+
res.status(500).json({ success: false, message: 'Failed to get group share candidates' });
|
|
672
|
+
}
|
|
673
|
+
};
|
|
625
674
|
//# sourceMappingURL=groupController.js.map
|