@toolplex/client 0.1.34 → 0.1.35

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.
@@ -46,6 +46,15 @@ export declare class PolicyEnforcer {
46
46
  * @returns Filtered list with blocked servers removed
47
47
  */
48
48
  filterBlockedMcpServers<T>(servers: T[], getServerId: (item: T) => string): T[];
49
+ /**
50
+ * Applies both blocked and allowed server filtering.
51
+ * First removes blocked servers, then filters to allowed servers (if set).
52
+ *
53
+ * @param servers List of objects containing server IDs
54
+ * @param getServerId Function that extracts the server ID from an object
55
+ * @returns Filtered list with policy applied
56
+ */
57
+ filterServersByPolicy<T>(servers: T[], getServerId: (item: T) => string): T[];
49
58
  /**
50
59
  * Get a reference to the CallToolObserver instance.
51
60
  */
@@ -84,6 +84,20 @@ export class PolicyEnforcer {
84
84
  }
85
85
  return this.serverPolicy.filterBlockedMcpServers(servers, getServerId);
86
86
  }
87
+ /**
88
+ * Applies both blocked and allowed server filtering.
89
+ * First removes blocked servers, then filters to allowed servers (if set).
90
+ *
91
+ * @param servers List of objects containing server IDs
92
+ * @param getServerId Function that extracts the server ID from an object
93
+ * @returns Filtered list with policy applied
94
+ */
95
+ filterServersByPolicy(servers, getServerId) {
96
+ if (!this.serverPolicy) {
97
+ throw new Error("PolicyEnforcer not initialized");
98
+ }
99
+ return this.serverPolicy.filterServersByPolicy(servers, getServerId);
100
+ }
87
101
  /**
88
102
  * Get a reference to the CallToolObserver instance.
89
103
  */
@@ -11,6 +11,8 @@ export declare class ServerPolicy {
11
11
  enforceBlockedServerPolicy(serverId: string): void;
12
12
  /**
13
13
  * Validates that a server is allowed.
14
+ * - For org users: if allowlist is empty/null, NO servers are allowed
15
+ * - For non-org users: if allowlist is empty/null, all servers are allowed
14
16
  *
15
17
  * @throws Error if attempting to use a server not in the allowed list
16
18
  */
@@ -36,4 +38,23 @@ export declare class ServerPolicy {
36
38
  * @returns Filtered list with blocked servers removed
37
39
  */
38
40
  filterBlockedMcpServers<T>(servers: T[], getServerId: (item: T) => string): T[];
41
+ /**
42
+ * Filters servers to only include allowed servers (if allowlist is set).
43
+ * - For org users: if allowlist is empty/null, return NO servers (admin hasn't approved any)
44
+ * - For non-org users: if allowlist is empty/null, return all servers (no restrictions)
45
+ *
46
+ * @param servers List of objects containing server IDs
47
+ * @param getServerId Function that extracts the server ID from an object
48
+ * @returns Filtered list with only allowed servers
49
+ */
50
+ filterToAllowedServers<T>(servers: T[], getServerId: (item: T) => string): T[];
51
+ /**
52
+ * Applies both blocked and allowed server filtering.
53
+ * First removes blocked servers, then filters to allowed servers (if set).
54
+ *
55
+ * @param servers List of objects containing server IDs
56
+ * @param getServerId Function that extracts the server ID from an object
57
+ * @returns Filtered list with policy applied
58
+ */
59
+ filterServersByPolicy<T>(servers: T[], getServerId: (item: T) => string): T[];
39
60
  }
@@ -15,14 +15,24 @@ export class ServerPolicy {
15
15
  }
16
16
  /**
17
17
  * Validates that a server is allowed.
18
+ * - For org users: if allowlist is empty/null, NO servers are allowed
19
+ * - For non-org users: if allowlist is empty/null, all servers are allowed
18
20
  *
19
21
  * @throws Error if attempting to use a server not in the allowed list
20
22
  */
21
23
  enforceAllowedServerPolicy(serverId) {
22
24
  const allowedServers = this.clientContext.permissions.allowed_mcp_servers;
23
- if (allowedServers &&
24
- allowedServers.length > 0 &&
25
- !allowedServers.includes(serverId)) {
25
+ // If allowlist is empty/null
26
+ if (!allowedServers || allowedServers.length === 0) {
27
+ // For org users: empty allowlist means NO servers approved
28
+ if (this.clientContext.isOrgUser) {
29
+ throw new Error(`No tools have been approved for your organization yet. Please contact your admin to approve tools on the ToolPlex Dashboard.`);
30
+ }
31
+ // For non-org users: no restrictions
32
+ return;
33
+ }
34
+ // Check if server is in the allowlist
35
+ if (!allowedServers.includes(serverId)) {
26
36
  throw new Error(`Server "${serverId}" is not allowed for your account. Please adjust the Allowed MCP Servers permissions on the ToolPlex Dashboard if this is a mistake.`);
27
37
  }
28
38
  }
@@ -60,4 +70,39 @@ export class ServerPolicy {
60
70
  filterBlockedMcpServers(servers, getServerId) {
61
71
  return servers.filter((server) => !this.blockedMcpServersSet.has(getServerId(server)));
62
72
  }
73
+ /**
74
+ * Filters servers to only include allowed servers (if allowlist is set).
75
+ * - For org users: if allowlist is empty/null, return NO servers (admin hasn't approved any)
76
+ * - For non-org users: if allowlist is empty/null, return all servers (no restrictions)
77
+ *
78
+ * @param servers List of objects containing server IDs
79
+ * @param getServerId Function that extracts the server ID from an object
80
+ * @returns Filtered list with only allowed servers
81
+ */
82
+ filterToAllowedServers(servers, getServerId) {
83
+ const allowedServers = this.clientContext.permissions.allowed_mcp_servers;
84
+ // If no allowlist configured
85
+ if (!allowedServers || allowedServers.length === 0) {
86
+ // For org users: empty allowlist means NO servers approved yet
87
+ if (this.clientContext.isOrgUser) {
88
+ return [];
89
+ }
90
+ // For non-org users: no restrictions, return all
91
+ return servers;
92
+ }
93
+ const allowedSet = new Set(allowedServers);
94
+ return servers.filter((server) => allowedSet.has(getServerId(server)));
95
+ }
96
+ /**
97
+ * Applies both blocked and allowed server filtering.
98
+ * First removes blocked servers, then filters to allowed servers (if set).
99
+ *
100
+ * @param servers List of objects containing server IDs
101
+ * @param getServerId Function that extracts the server ID from an object
102
+ * @returns Filtered list with policy applied
103
+ */
104
+ filterServersByPolicy(servers, getServerId) {
105
+ const withoutBlocked = this.filterBlockedMcpServers(servers, getServerId);
106
+ return this.filterToAllowedServers(withoutBlocked, getServerId);
107
+ }
63
108
  }
@@ -115,8 +115,13 @@ export async function handleInitialize(params) {
115
115
  else {
116
116
  await logger.debug("No session resume history provided (new session)");
117
117
  }
118
- const allSucceeded = serverManagerInitResults.succeeded;
119
- const allFailures = serverManagerInitResults.failures;
118
+ // Filter servers by policy (blocked + allowed)
119
+ const allSucceeded = policyEnforcer.filterServersByPolicy(serverManagerInitResults.succeeded, (s) => s.server_id);
120
+ // Also filter failures by policy
121
+ const failureEntries = Object.entries(serverManagerInitResults.failures);
122
+ const filteredFailureEntries = policyEnforcer.filterServersByPolicy(failureEntries, ([serverId]) => serverId);
123
+ const allFailures = Object.fromEntries(filteredFailureEntries);
124
+ await logger.info(`Filtered to ${allSucceeded.length} servers (policy enforced)`);
120
125
  // Initialize the serversCache with the succeeded servers
121
126
  serversCache.init(allSucceeded);
122
127
  await logger.debug(`Total successes: ${allSucceeded.length}, Total failures: ${Object.keys(allFailures).length}`);
@@ -24,8 +24,8 @@ export async function handleListServers() {
24
24
  continue;
25
25
  }
26
26
  if (parsed.data.servers && parsed.data.servers.length > 0) {
27
- // Filter out blocked servers
28
- const filteredServers = policyEnforcer.filterBlockedMcpServers(parsed.data.servers, (server) => server.server_id);
27
+ // Filter servers by policy (blocked + allowed)
28
+ const filteredServers = policyEnforcer.filterServersByPolicy(parsed.data.servers, (server) => server.server_id);
29
29
  filteredServers.forEach((server) => {
30
30
  // Add to allServers for cache update and structured response
31
31
  allServers.push({
@@ -68,9 +68,9 @@ export async function handleListTools(params) {
68
68
  await logger.error(`Invalid response from server manager: ${parsed.error}, runtime: ${runtime}`);
69
69
  continue;
70
70
  }
71
- // Filter out blocked servers
71
+ // Filter servers by policy (blocked + allowed)
72
72
  const serverEntries = Object.entries(parsed.data.tools);
73
- const filteredEntries = policyEnforcer.filterBlockedMcpServers(serverEntries, ([serverId]) => serverId);
73
+ const filteredEntries = policyEnforcer.filterServersByPolicy(serverEntries, ([serverId]) => serverId);
74
74
  for (const [serverId, serverTools] of filteredEntries) {
75
75
  if (serverTools && serverTools.length > 0) {
76
76
  allServerTools.push({
@@ -84,6 +84,20 @@ export class PolicyEnforcer {
84
84
  }
85
85
  return this.serverPolicy.filterBlockedMcpServers(servers, getServerId);
86
86
  }
87
+ /**
88
+ * Applies both blocked and allowed server filtering.
89
+ * First removes blocked servers, then filters to allowed servers (if set).
90
+ *
91
+ * @param servers List of objects containing server IDs
92
+ * @param getServerId Function that extracts the server ID from an object
93
+ * @returns Filtered list with policy applied
94
+ */
95
+ filterServersByPolicy(servers, getServerId) {
96
+ if (!this.serverPolicy) {
97
+ throw new Error("PolicyEnforcer not initialized");
98
+ }
99
+ return this.serverPolicy.filterServersByPolicy(servers, getServerId);
100
+ }
87
101
  /**
88
102
  * Get a reference to the CallToolObserver instance.
89
103
  */
@@ -15,14 +15,24 @@ export class ServerPolicy {
15
15
  }
16
16
  /**
17
17
  * Validates that a server is allowed.
18
+ * - For org users: if allowlist is empty/null, NO servers are allowed
19
+ * - For non-org users: if allowlist is empty/null, all servers are allowed
18
20
  *
19
21
  * @throws Error if attempting to use a server not in the allowed list
20
22
  */
21
23
  enforceAllowedServerPolicy(serverId) {
22
24
  const allowedServers = this.clientContext.permissions.allowed_mcp_servers;
23
- if (allowedServers &&
24
- allowedServers.length > 0 &&
25
- !allowedServers.includes(serverId)) {
25
+ // If allowlist is empty/null
26
+ if (!allowedServers || allowedServers.length === 0) {
27
+ // For org users: empty allowlist means NO servers approved
28
+ if (this.clientContext.isOrgUser) {
29
+ throw new Error(`No tools have been approved for your organization yet. Please contact your admin to approve tools on the ToolPlex Dashboard.`);
30
+ }
31
+ // For non-org users: no restrictions
32
+ return;
33
+ }
34
+ // Check if server is in the allowlist
35
+ if (!allowedServers.includes(serverId)) {
26
36
  throw new Error(`Server "${serverId}" is not allowed for your account. Please adjust the Allowed MCP Servers permissions on the ToolPlex Dashboard if this is a mistake.`);
27
37
  }
28
38
  }
@@ -60,4 +70,39 @@ export class ServerPolicy {
60
70
  filterBlockedMcpServers(servers, getServerId) {
61
71
  return servers.filter((server) => !this.blockedMcpServersSet.has(getServerId(server)));
62
72
  }
73
+ /**
74
+ * Filters servers to only include allowed servers (if allowlist is set).
75
+ * - For org users: if allowlist is empty/null, return NO servers (admin hasn't approved any)
76
+ * - For non-org users: if allowlist is empty/null, return all servers (no restrictions)
77
+ *
78
+ * @param servers List of objects containing server IDs
79
+ * @param getServerId Function that extracts the server ID from an object
80
+ * @returns Filtered list with only allowed servers
81
+ */
82
+ filterToAllowedServers(servers, getServerId) {
83
+ const allowedServers = this.clientContext.permissions.allowed_mcp_servers;
84
+ // If no allowlist configured
85
+ if (!allowedServers || allowedServers.length === 0) {
86
+ // For org users: empty allowlist means NO servers approved yet
87
+ if (this.clientContext.isOrgUser) {
88
+ return [];
89
+ }
90
+ // For non-org users: no restrictions, return all
91
+ return servers;
92
+ }
93
+ const allowedSet = new Set(allowedServers);
94
+ return servers.filter((server) => allowedSet.has(getServerId(server)));
95
+ }
96
+ /**
97
+ * Applies both blocked and allowed server filtering.
98
+ * First removes blocked servers, then filters to allowed servers (if set).
99
+ *
100
+ * @param servers List of objects containing server IDs
101
+ * @param getServerId Function that extracts the server ID from an object
102
+ * @returns Filtered list with policy applied
103
+ */
104
+ filterServersByPolicy(servers, getServerId) {
105
+ const withoutBlocked = this.filterBlockedMcpServers(servers, getServerId);
106
+ return this.filterToAllowedServers(withoutBlocked, getServerId);
107
+ }
63
108
  }
@@ -115,8 +115,13 @@ export async function handleInitialize(params) {
115
115
  else {
116
116
  await logger.debug("No session resume history provided (new session)");
117
117
  }
118
- const allSucceeded = serverManagerInitResults.succeeded;
119
- const allFailures = serverManagerInitResults.failures;
118
+ // Filter servers by policy (blocked + allowed)
119
+ const allSucceeded = policyEnforcer.filterServersByPolicy(serverManagerInitResults.succeeded, (s) => s.server_id);
120
+ // Also filter failures by policy
121
+ const failureEntries = Object.entries(serverManagerInitResults.failures);
122
+ const filteredFailureEntries = policyEnforcer.filterServersByPolicy(failureEntries, ([serverId]) => serverId);
123
+ const allFailures = Object.fromEntries(filteredFailureEntries);
124
+ await logger.info(`Filtered to ${allSucceeded.length} servers (policy enforced)`);
120
125
  // Initialize the serversCache with the succeeded servers
121
126
  serversCache.init(allSucceeded);
122
127
  await logger.debug(`Total successes: ${allSucceeded.length}, Total failures: ${Object.keys(allFailures).length}`);
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "0.1.34";
1
+ export declare const version = "0.1.35";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '0.1.34';
1
+ export const version = '0.1.35';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolplex/client",
3
- "version": "0.1.34",
3
+ "version": "0.1.35",
4
4
  "author": "ToolPlex LLC",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "description": "The official ToolPlex client for AI agent tool discovery and execution",