@samanhappy/mcphub 1.0.36 → 1.0.37
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/controllers/groupController.js +63 -14
- package/dist/controllers/groupController.js.map +1 -1
- package/dist/controllers/serverController.js +18 -0
- 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/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/groupSchema.js +29 -0
- package/dist/db/groupSchema.js.map +1 -0
- 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 +49 -12
- 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/groupAccess.js +17 -0
- package/dist/utils/groupAccess.js.map +1 -0
- package/dist/utils/migration.js +2 -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/frontend/dist/assets/{ActivityPage-ZRx6b9hm.js → ActivityPage-Bx5-Jrxq.js} +2 -2
- package/frontend/dist/assets/{ActivityPage-ZRx6b9hm.js.map → ActivityPage-Bx5-Jrxq.js.map} +1 -1
- package/frontend/dist/assets/{CredentialsPage-C9vnh01H.js → CredentialsPage-BGbk_kBx.js} +2 -2
- package/frontend/dist/assets/{CredentialsPage-C9vnh01H.js.map → CredentialsPage-BGbk_kBx.js.map} +1 -1
- package/frontend/dist/assets/{Dashboard-BDGDQNz1.js → Dashboard-gHeXLPEn.js} +2 -2
- package/frontend/dist/assets/{Dashboard-BDGDQNz1.js.map → Dashboard-gHeXLPEn.js.map} +1 -1
- package/frontend/dist/assets/{EndpointCopy-BY51t0Ks.js → EndpointCopy-BRwX7Dpv.js} +2 -2
- package/frontend/dist/assets/{EndpointCopy-BY51t0Ks.js.map → EndpointCopy-BRwX7Dpv.js.map} +1 -1
- package/frontend/dist/assets/GroupsPage-grCAx55k.js +33 -0
- package/frontend/dist/assets/GroupsPage-grCAx55k.js.map +1 -0
- package/frontend/dist/assets/{LoginPage-CZOKlkR_.js → LoginPage-C7-m2jmB.js} +2 -2
- package/frontend/dist/assets/{LoginPage-CZOKlkR_.js.map → LoginPage-C7-m2jmB.js.map} +1 -1
- package/frontend/dist/assets/{LogsPage-FDWOOIPg.js → LogsPage-B00XTokA.js} +2 -2
- package/frontend/dist/assets/{LogsPage-FDWOOIPg.js.map → LogsPage-B00XTokA.js.map} +1 -1
- package/frontend/dist/assets/{MarketPage-DKfZgoIs.js → MarketPage-CVJMdSDD.js} +2 -2
- package/frontend/dist/assets/{MarketPage-DKfZgoIs.js.map → MarketPage-CVJMdSDD.js.map} +1 -1
- package/frontend/dist/assets/{OAuthConsentPage-Hk_DJ0dW.js → OAuthConsentPage-znW3HtpR.js} +2 -2
- package/frontend/dist/assets/{OAuthConsentPage-Hk_DJ0dW.js.map → OAuthConsentPage-znW3HtpR.js.map} +1 -1
- package/frontend/dist/assets/{PromptsPage-CT0C0_BI.js → PromptsPage-DGcNS3fO.js} +2 -2
- package/frontend/dist/assets/{PromptsPage-CT0C0_BI.js.map → PromptsPage-DGcNS3fO.js.map} +1 -1
- package/frontend/dist/assets/{ResourcesPage-CBgu-N5m.js → ResourcesPage-CfyZoadu.js} +2 -2
- package/frontend/dist/assets/{ResourcesPage-CBgu-N5m.js.map → ResourcesPage-CfyZoadu.js.map} +1 -1
- package/frontend/dist/assets/{ServersPage-CvcP8LFv.js → ServersPage-BlC0RdIu.js} +4 -4
- package/frontend/dist/assets/{ServersPage-CvcP8LFv.js.map → ServersPage-BlC0RdIu.js.map} +1 -1
- package/frontend/dist/assets/{SettingsPage-DDSVt_xk.js → SettingsPage-CiVNDyr_.js} +2 -2
- package/frontend/dist/assets/{SettingsPage-DDSVt_xk.js.map → SettingsPage-CiVNDyr_.js.map} +1 -1
- package/frontend/dist/assets/{StatusDot-uIIW4IuH.js → StatusDot-DYO56shE.js} +2 -2
- package/frontend/dist/assets/{StatusDot-uIIW4IuH.js.map → StatusDot-DYO56shE.js.map} +1 -1
- package/frontend/dist/assets/{ToggleGroup-BToroeZy.js → ToggleGroup-r8yGt_Fq.js} +2 -2
- package/frontend/dist/assets/{ToggleGroup-BToroeZy.js.map → ToggleGroup-r8yGt_Fq.js.map} +1 -1
- package/frontend/dist/assets/{UsersPage-BjgJjf6L.js → UsersPage-B3muXE90.js} +2 -2
- package/frontend/dist/assets/{UsersPage-BjgJjf6L.js.map → UsersPage-B3muXE90.js.map} +1 -1
- package/frontend/dist/assets/index-B-aT0HW5.js +3 -0
- package/frontend/dist/assets/index-B-aT0HW5.js.map +1 -0
- package/frontend/dist/assets/{resourceService-sD9dxx3E.js → resourceService-CSXOSi7M.js} +2 -2
- package/frontend/dist/assets/{resourceService-sD9dxx3E.js.map → resourceService-CSXOSi7M.js.map} +1 -1
- package/frontend/dist/assets/{useCostData-QoPbsqyD.js → useCostData-BOxUFQAH.js} +2 -2
- package/frontend/dist/assets/{useCostData-QoPbsqyD.js.map → useCostData-BOxUFQAH.js.map} +1 -1
- package/frontend/dist/assets/useSettingsData-DmpLlRI6.js +2 -0
- package/frontend/dist/assets/{useSettingsData-C4JrLqDh.js.map → useSettingsData-DmpLlRI6.js.map} +1 -1
- package/frontend/dist/assets/{variableDetection-iFAhGAKs.js → variableDetection-cmwwuSWB.js} +2 -2
- package/frontend/dist/assets/{variableDetection-iFAhGAKs.js.map → variableDetection-cmwwuSWB.js.map} +1 -1
- package/frontend/dist/index.html +1 -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/index-DjNOC0Ov.js +0 -3
- package/frontend/dist/assets/index-DjNOC0Ov.js.map +0 -1
- package/frontend/dist/assets/useSettingsData-C4JrLqDh.js +0 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { canAccessGroupRoute } from '../utils/groupAccess.js';
|
|
2
3
|
import { PrincipalRuntimeService } from './principalRuntimeService.js';
|
|
3
4
|
import { UserContextService } from './userContextService.js';
|
|
4
5
|
import { deleteCredentialBindings, missingCredentialError } from './credentialBindingService.js';
|
|
@@ -1734,9 +1735,14 @@ export const getServersInfo = async (page, limit, user) => {
|
|
|
1734
1735
|
const enabled = serverConfig ? serverConfig.enabled !== false : true;
|
|
1735
1736
|
const resolvedType = inferServerType(serverConfig);
|
|
1736
1737
|
const oauthConnected = Boolean(serverConfig?.oauth?.accessToken || serverConfig?.oauth?.refreshToken);
|
|
1737
|
-
// Add enabled status and custom description to each tool
|
|
1738
|
+
// Add enabled status and custom description to each tool.
|
|
1739
|
+
// toggleTool stores under whatever key the caller passed (prefixed,
|
|
1740
|
+
// as the dashboard sends, or bare, as a direct API call may) with no
|
|
1741
|
+
// normalization — check both so the dashboard reflects a disable set
|
|
1742
|
+
// either way instead of always showing enabled:true for one of them.
|
|
1738
1743
|
const toolsWithEnabled = tools.map((tool) => {
|
|
1739
|
-
const
|
|
1744
|
+
const bareToolName = normalizeToolNameForServer(name, tool.name);
|
|
1745
|
+
const toolConfig = serverConfig?.tools?.[tool.name] ?? serverConfig?.tools?.[bareToolName];
|
|
1740
1746
|
return buildToolWithDescriptionMetadata(tool, toolConfig);
|
|
1741
1747
|
});
|
|
1742
1748
|
const promptsWithEnabled = prompts.map((prompt) => {
|
|
@@ -1890,7 +1896,11 @@ const filterToolsByConfig = async (serverName, tools) => {
|
|
|
1890
1896
|
return tools;
|
|
1891
1897
|
}
|
|
1892
1898
|
return tools.filter((tool) => {
|
|
1893
|
-
|
|
1899
|
+
// toggleTool stores the disable under whatever key string the caller used
|
|
1900
|
+
// (bare upstream name or server-prefixed name, never normalized) — check
|
|
1901
|
+
// both, same as findToolOnServer's execution-time gate.
|
|
1902
|
+
const bareToolName = normalizeToolNameForServer(serverName, tool.name);
|
|
1903
|
+
const toolConfig = serverConfig.tools?.[tool.name] ?? serverConfig.tools?.[bareToolName];
|
|
1894
1904
|
// If tool is not in config, it's enabled by default
|
|
1895
1905
|
return toolConfig?.enabled !== false;
|
|
1896
1906
|
});
|
|
@@ -2482,8 +2492,36 @@ const resolveNameFromGroup = (name, serverName, serverConfig) => {
|
|
|
2482
2492
|
return replacePrefixedServerName(name, getExposedServerName(serverName, serverConfig), serverName);
|
|
2483
2493
|
};
|
|
2484
2494
|
const findToolOnServer = (serverInfo, toolName, allowRawName) => {
|
|
2485
|
-
|
|
2495
|
+
const tool = serverInfo.tools.find((tool) => tool.name === toolName ||
|
|
2486
2496
|
(allowRawName && normalizeToolNameForServer(serverInfo.name, tool.name) === toolName));
|
|
2497
|
+
if (!tool) {
|
|
2498
|
+
return undefined;
|
|
2499
|
+
}
|
|
2500
|
+
// A tool disabled via POST /api/servers/:server/tools/:tool/toggle must be
|
|
2501
|
+
// unresolvable for execution, not just hidden from tools/list — otherwise a
|
|
2502
|
+
// caller who already knows the tool name can invoke it regardless of the
|
|
2503
|
+
// disabled flag.
|
|
2504
|
+
//
|
|
2505
|
+
// The runtime tool cache (serverInfo.tools, built by normalizeToolForCache)
|
|
2506
|
+
// never carries an `enabled` field — that field only exists on the
|
|
2507
|
+
// *projection* built for the dashboard/API (buildToolWithDescriptionMetadata),
|
|
2508
|
+
// which is a different object. So the persisted per-tool config must be
|
|
2509
|
+
// consulted directly here.
|
|
2510
|
+
//
|
|
2511
|
+
// toggleTool (serverController.ts) stores `tools[toolName] = ...` using
|
|
2512
|
+
// whatever string the caller passed as :toolName, with no normalization.
|
|
2513
|
+
// The dashboard sends the already-prefixed `tool.name`, matching what
|
|
2514
|
+
// getServersInfo's toolsWithEnabled already reads — but any other caller
|
|
2515
|
+
// (REST API used directly, scripts, docs examples) can just as validly
|
|
2516
|
+
// pass the bare upstream name, which then never matches a prefixed-only
|
|
2517
|
+
// lookup. Check both so a disable takes effect regardless of which form
|
|
2518
|
+
// was used to set it.
|
|
2519
|
+
const bareToolName = normalizeToolNameForServer(serverInfo.name, tool.name);
|
|
2520
|
+
const toolConfig = serverInfo.config?.tools?.[tool.name] ?? serverInfo.config?.tools?.[bareToolName];
|
|
2521
|
+
if (toolConfig && toolConfig.enabled === false) {
|
|
2522
|
+
return undefined;
|
|
2523
|
+
}
|
|
2524
|
+
return tool;
|
|
2487
2525
|
};
|
|
2488
2526
|
const assertToolAvailableForRoute = (tool, appsRouteContext) => {
|
|
2489
2527
|
if (isAppOnlyTool(tool) && !appsRouteContext.enabled) {
|
|
@@ -3593,13 +3631,8 @@ export const createMcpServer = (name, version, options) => {
|
|
|
3593
3631
|
return server;
|
|
3594
3632
|
};
|
|
3595
3633
|
export const getFilteredServerInfosForGroup = async (group, options) => {
|
|
3596
|
-
// Resolve
|
|
3597
|
-
|
|
3598
|
-
// and applies filterData on groups). Groups don't carry a visibility field,
|
|
3599
|
-
// so admin-owned groups would be filtered out for non-admin users even though
|
|
3600
|
-
// bearer-key auth already authorized access and individual servers inside the
|
|
3601
|
-
// group may be public. Server-level filterData below still enforces per-server
|
|
3602
|
-
// visibility. Fix for #914.
|
|
3634
|
+
// Resolve raw groups so legacy routing remains compatible, then enforce explicit visibility.
|
|
3635
|
+
let matchedGroup = false;
|
|
3603
3636
|
let serverConfigs = [];
|
|
3604
3637
|
if (group) {
|
|
3605
3638
|
const groupDao = getGroupDao();
|
|
@@ -3611,6 +3644,10 @@ export const getFilteredServerInfosForGroup = async (group, options) => {
|
|
|
3611
3644
|
}
|
|
3612
3645
|
}
|
|
3613
3646
|
if (foundGroup) {
|
|
3647
|
+
matchedGroup = true;
|
|
3648
|
+
if (!canAccessGroupRoute(foundGroup)) {
|
|
3649
|
+
return { filteredServerInfos: [], serverConfigsByName: new Map() };
|
|
3650
|
+
}
|
|
3614
3651
|
serverConfigs = normalizeGroupServers(foundGroup.servers || []);
|
|
3615
3652
|
}
|
|
3616
3653
|
}
|
|
@@ -3626,7 +3663,7 @@ export const getFilteredServerInfosForGroup = async (group, options) => {
|
|
|
3626
3663
|
filteredServerInfos.push(serverInfo);
|
|
3627
3664
|
continue;
|
|
3628
3665
|
}
|
|
3629
|
-
if (
|
|
3666
|
+
if (!matchedGroup) {
|
|
3630
3667
|
if (serverInfo.name === group) {
|
|
3631
3668
|
filteredServerInfos.push(serverInfo);
|
|
3632
3669
|
}
|