pulsemcp-cms-admin-mcp-server 0.9.26 → 0.9.27

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.
@@ -24,7 +24,9 @@ export async function createApiKey(apiKey, baseUrl, params) {
24
24
  throw new Error('Invalid API key');
25
25
  }
26
26
  if (response.status === 403) {
27
- throw new Error('User lacks write privileges');
27
+ const errorData = (await response.json().catch(() => ({})));
28
+ const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
29
+ throw new Error(message);
28
30
  }
29
31
  if (response.status === 404) {
30
32
  const errorData = (await response.json());
@@ -13,7 +13,9 @@ export async function deleteApiKey(apiKey, baseUrl, id) {
13
13
  throw new Error('Invalid API key');
14
14
  }
15
15
  if (response.status === 403) {
16
- throw new Error('User lacks write privileges');
16
+ const errorData = (await response.json().catch(() => ({})));
17
+ const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
18
+ throw new Error(message);
17
19
  }
18
20
  if (response.status === 422) {
19
21
  const errorData = (await response.json().catch(() => ({})));
@@ -16,7 +16,9 @@ export async function deleteTenant(apiKey, baseUrl, params) {
16
16
  throw new Error('Invalid API key');
17
17
  }
18
18
  if (response.status === 403) {
19
- throw new Error('User lacks write privileges');
19
+ const errorData = (await response.json().catch(() => ({})));
20
+ const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
21
+ throw new Error(message);
20
22
  }
21
23
  if (response.status === 404) {
22
24
  throw new Error(`Tenant ${params.id_or_slug} not found`);
@@ -185,13 +185,14 @@ const ALL_TOOLS = [
185
185
  { factory: getTenant, groups: ['tenants'], isWriteOperation: false },
186
186
  { factory: createTenant, groups: ['tenants'], isWriteOperation: true },
187
187
  { factory: createApiKey, groups: ['tenants'], isWriteOperation: true },
188
- // revoke_api_key lives in the regular `tenants` group (not `tenants_destructive`) so
189
- // it's exposed to read-write tenant management workflows like sub-registry credential
190
- // re-issuance. The tool gates each call with MCP elicitation; if the connected client
191
- // supports neither native elicitation nor an HTTP fallback, the elicitation library
192
- // throws at runtime rather than silently destroying the key.
193
- { factory: revokeApiKey, groups: ['tenants'], isWriteOperation: true },
194
- // Destructive tenant tools opt-in only, NOT in BASE_TOOL_GROUPS
188
+ // Destructive tenant tools opt-in only, NOT in BASE_TOOL_GROUPS.
189
+ // revoke_api_key lives here (not in `tenants`) because it calls the same
190
+ // DELETE /api/api_keys/:id endpoint as delete_api_key and the Rails admin
191
+ // API gates that endpoint behind permission_level=all (full_access). The
192
+ // standard read-write admin credential cannot DELETE, so exposing
193
+ // revoke_api_key in the regular tenants group surfaced confusing 403s on
194
+ // workflows like sub-registry credential re-issuance.
195
+ { factory: revokeApiKey, groups: ['tenants_destructive'], isWriteOperation: true },
195
196
  { factory: deleteTenant, groups: ['tenants_destructive'], isWriteOperation: true },
196
197
  { factory: deleteApiKey, groups: ['tenants_destructive'], isWriteOperation: true },
197
198
  // Tenant -> recommended MCP server association tools
@@ -410,9 +411,9 @@ function shouldIncludeTool(toolDef, enabledGroups) {
410
411
  * - unofficial_mirrors: Unofficial mirror CRUD tools (read + write)
411
412
  * - unofficial_mirrors_readonly: Unofficial mirror tools (read only)
412
413
  * - official_mirrors_readonly: Official mirrors REST API tools (read only)
413
- * - tenants: Tenant management tools including API key provisioning + revoke_api_key (read + write). revoke_api_key is gated by MCP elicitation user approval before execution.
414
+ * - tenants: Tenant management tools including API key provisioning (read + write).
414
415
  * - tenants_readonly: Tenant tools (read only)
415
- * - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
416
+ * - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key, revoke_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
416
417
  * - mcp_jsons: MCP JSON configuration tools (read + write)
417
418
  * - mcp_jsons_readonly: MCP JSON tools (read only)
418
419
  * - mcp_servers: Unified MCP server tools with abstracted interface (read + write)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pulsemcp-cms-admin-mcp-server",
3
- "version": "0.9.26",
3
+ "version": "0.9.27",
4
4
  "description": "Local implementation of PulseMCP CMS Admin MCP server",
5
5
  "mcpName": "com.pulsemcp.servers/pulsemcp-cms-admin",
6
6
  "main": "build/index.js",
@@ -8,13 +8,13 @@ import { type ElicitationConfig } from '@pulsemcp/mcp-elicitation';
8
8
  * 3. Per-action override: PULSEMCP_CMS_ADMIN_ELICITATION_DESTRUCTIVE
9
9
  *
10
10
  * Destructive elicitation gates the `tenants_destructive` tool group only
11
- * (delete_tenant, delete_api_key). All other write tools in the server are
12
- * not gated by elicitation.
11
+ * (delete_tenant, delete_api_key, revoke_api_key). All other write tools in
12
+ * the server are not gated by elicitation.
13
13
  */
14
14
  export interface CmsAdminElicitationConfig {
15
15
  /** Base elicitation config from the shared library */
16
16
  base: ElicitationConfig;
17
- /** Whether to elicit confirmation for destructive operations (delete_tenant, delete_api_key) */
17
+ /** Whether to elicit confirmation for destructive operations (delete_tenant, delete_api_key, revoke_api_key) */
18
18
  destructiveElicitationEnabled: boolean;
19
19
  }
20
20
  /**
@@ -24,7 +24,9 @@ export async function createApiKey(apiKey, baseUrl, params) {
24
24
  throw new Error('Invalid API key');
25
25
  }
26
26
  if (response.status === 403) {
27
- throw new Error('User lacks write privileges');
27
+ const errorData = (await response.json().catch(() => ({})));
28
+ const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
29
+ throw new Error(message);
28
30
  }
29
31
  if (response.status === 404) {
30
32
  const errorData = (await response.json());
@@ -13,7 +13,9 @@ export async function deleteApiKey(apiKey, baseUrl, id) {
13
13
  throw new Error('Invalid API key');
14
14
  }
15
15
  if (response.status === 403) {
16
- throw new Error('User lacks write privileges');
16
+ const errorData = (await response.json().catch(() => ({})));
17
+ const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
18
+ throw new Error(message);
17
19
  }
18
20
  if (response.status === 422) {
19
21
  const errorData = (await response.json().catch(() => ({})));
@@ -16,7 +16,9 @@ export async function deleteTenant(apiKey, baseUrl, params) {
16
16
  throw new Error('Invalid API key');
17
17
  }
18
18
  if (response.status === 403) {
19
- throw new Error('User lacks write privileges');
19
+ const errorData = (await response.json().catch(() => ({})));
20
+ const message = errorData.errors?.join(', ') || errorData.error || `Forbidden: ${response.status}`;
21
+ throw new Error(message);
20
22
  }
21
23
  if (response.status === 404) {
22
24
  throw new Error(`Tenant ${params.id_or_slug} not found`);
package/shared/tools.d.ts CHANGED
@@ -18,8 +18,8 @@ import { ClientFactory } from './server.js';
18
18
  * - official_queue / official_queue_readonly: Official mirror queue tools (list, get, approve, reject, unlink)
19
19
  * - unofficial_mirrors / unofficial_mirrors_readonly: Unofficial mirror CRUD tools
20
20
  * - official_mirrors_readonly: Official mirrors read-only tools (REST API)
21
- * - tenants / tenants_readonly: Tenant management tools (CRUD + API key provisioning, including revoke_api_key for rolling keys after re-issuance)
22
- * - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key). NOT enabled by default — operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
21
+ * - tenants / tenants_readonly: Tenant management tools (CRUD + API key provisioning)
22
+ * - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key, revoke_api_key). NOT enabled by default — operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution. revoke_api_key lives here (not in `tenants`) because it calls the same DELETE /api/api_keys/:id endpoint as delete_api_key, which the Rails admin API gates behind permission_level=all.
23
23
  * - mcp_jsons / mcp_jsons_readonly: MCP JSON configuration tools
24
24
  * - mcp_servers / mcp_servers_readonly: Unified MCP server tools (abstracted interface)
25
25
  * - redirects / redirects_readonly: URL redirect management tools
@@ -61,9 +61,9 @@ export declare function parseEnabledToolGroups(enabledGroupsParam?: string): Too
61
61
  * - unofficial_mirrors: Unofficial mirror CRUD tools (read + write)
62
62
  * - unofficial_mirrors_readonly: Unofficial mirror tools (read only)
63
63
  * - official_mirrors_readonly: Official mirrors REST API tools (read only)
64
- * - tenants: Tenant management tools including API key provisioning + revoke_api_key (read + write). revoke_api_key is gated by MCP elicitation user approval before execution.
64
+ * - tenants: Tenant management tools including API key provisioning (read + write).
65
65
  * - tenants_readonly: Tenant tools (read only)
66
- * - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
66
+ * - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key, revoke_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
67
67
  * - mcp_jsons: MCP JSON configuration tools (read + write)
68
68
  * - mcp_jsons_readonly: MCP JSON tools (read only)
69
69
  * - mcp_servers: Unified MCP server tools with abstracted interface (read + write)
package/shared/tools.js CHANGED
@@ -185,13 +185,14 @@ const ALL_TOOLS = [
185
185
  { factory: getTenant, groups: ['tenants'], isWriteOperation: false },
186
186
  { factory: createTenant, groups: ['tenants'], isWriteOperation: true },
187
187
  { factory: createApiKey, groups: ['tenants'], isWriteOperation: true },
188
- // revoke_api_key lives in the regular `tenants` group (not `tenants_destructive`) so
189
- // it's exposed to read-write tenant management workflows like sub-registry credential
190
- // re-issuance. The tool gates each call with MCP elicitation; if the connected client
191
- // supports neither native elicitation nor an HTTP fallback, the elicitation library
192
- // throws at runtime rather than silently destroying the key.
193
- { factory: revokeApiKey, groups: ['tenants'], isWriteOperation: true },
194
- // Destructive tenant tools opt-in only, NOT in BASE_TOOL_GROUPS
188
+ // Destructive tenant tools opt-in only, NOT in BASE_TOOL_GROUPS.
189
+ // revoke_api_key lives here (not in `tenants`) because it calls the same
190
+ // DELETE /api/api_keys/:id endpoint as delete_api_key and the Rails admin
191
+ // API gates that endpoint behind permission_level=all (full_access). The
192
+ // standard read-write admin credential cannot DELETE, so exposing
193
+ // revoke_api_key in the regular tenants group surfaced confusing 403s on
194
+ // workflows like sub-registry credential re-issuance.
195
+ { factory: revokeApiKey, groups: ['tenants_destructive'], isWriteOperation: true },
195
196
  { factory: deleteTenant, groups: ['tenants_destructive'], isWriteOperation: true },
196
197
  { factory: deleteApiKey, groups: ['tenants_destructive'], isWriteOperation: true },
197
198
  // Tenant -> recommended MCP server association tools
@@ -410,9 +411,9 @@ function shouldIncludeTool(toolDef, enabledGroups) {
410
411
  * - unofficial_mirrors: Unofficial mirror CRUD tools (read + write)
411
412
  * - unofficial_mirrors_readonly: Unofficial mirror tools (read only)
412
413
  * - official_mirrors_readonly: Official mirrors REST API tools (read only)
413
- * - tenants: Tenant management tools including API key provisioning + revoke_api_key (read + write). revoke_api_key is gated by MCP elicitation user approval before execution.
414
+ * - tenants: Tenant management tools including API key provisioning (read + write).
414
415
  * - tenants_readonly: Tenant tools (read only)
415
- * - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
416
+ * - tenants_destructive: Destructive tenant tools (delete_tenant, delete_api_key, revoke_api_key). NOT enabled by default; operators must opt in via TOOL_GROUPS. Each tool requires MCP elicitation user approval before execution.
416
417
  * - mcp_jsons: MCP JSON configuration tools (read + write)
417
418
  * - mcp_jsons_readonly: MCP JSON tools (read only)
418
419
  * - mcp_servers: Unified MCP server tools with abstracted interface (read + write)