@centrali-io/centrali-mcp 5.1.2 → 5.3.0

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.md CHANGED
@@ -101,6 +101,7 @@ After connecting, call `describe_centrali` first — it returns the full capabil
101
101
  | `describe_navigation` | Navigation configuration reference |
102
102
  | `describe_auth_providers` | Auth provider reference (BYOT setup, claim mappings) |
103
103
  | `describe_service_accounts` | Service account & IAM reference (SA setup, roles, groups, permissions) |
104
+ | `describe_webhooks` | Outbound webhook reference (subscription shape, signature, retry/replay) |
104
105
 
105
106
  ### Collections
106
107
  | Tool | Description |
@@ -254,6 +255,20 @@ After connecting, call `describe_centrali` first — it returns the full capabil
254
255
  | `update_group` | Update a group |
255
256
  | `delete_group` | Delete a group |
256
257
 
258
+ ### Webhook Subscriptions
259
+ | Tool | Description |
260
+ |------|-------------|
261
+ | `list_webhook_subscriptions` | List all outbound webhook subscriptions |
262
+ | `get_webhook_subscription` | Get a subscription by ID (secret not included) |
263
+ | `create_webhook_subscription` | Create a subscription — response returns the `whsec_` signing secret once |
264
+ | `update_webhook_subscription` | Update name, URL, events, recordSlugs, or active flag |
265
+ | `delete_webhook_subscription` | Delete a subscription (delivery history retained) |
266
+ | `rotate_webhook_subscription_secret` | Regenerate the signing secret (immediate cutover) |
267
+ | `list_webhook_deliveries` | List delivery history for a subscription (trimmed rows) |
268
+ | `get_webhook_delivery` | Get a single delivery with full payload and response body |
269
+ | `retry_webhook_delivery` | Replay a delivery — reuses the original payload and signature |
270
+ | `cancel_webhook_delivery` | Cancel a retrying delivery (flips to failed with distinctive marker) |
271
+
257
272
  ### Publishable Keys (Frontend)
258
273
  | Tool | Description |
259
274
  |------|-------------|
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ const pages_js_1 = require("./tools/pages.js");
25
25
  const describe_js_1 = require("./tools/describe.js");
26
26
  const auth_providers_js_1 = require("./tools/auth-providers.js");
27
27
  const service_accounts_js_1 = require("./tools/service-accounts.js");
28
+ const webhook_subscriptions_js_1 = require("./tools/webhook-subscriptions.js");
28
29
  const structures_js_2 = require("./resources/structures.js");
29
30
  function getRequiredEnv(name) {
30
31
  const value = process.env[name];
@@ -82,6 +83,7 @@ function main() {
82
83
  clientId,
83
84
  isServiceAccount: true,
84
85
  });
86
+ (0, webhook_subscriptions_js_1.registerWebhookSubscriptionTools)(server, sdk);
85
87
  (0, describe_js_1.registerDescribeTools)(server);
86
88
  // Register resources
87
89
  (0, structures_js_2.registerCollectionResources)(server, sdk);
@@ -0,0 +1,24 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ZodRawShape } from "zod";
3
+ export type ToolResult = {
4
+ content: Array<{
5
+ type: "text";
6
+ text: string;
7
+ }>;
8
+ isError?: boolean;
9
+ };
10
+ /**
11
+ * Thin wrapper around `server.tool(...)` that severs the MCP SDK's deep
12
+ * Zod-shape → handler-arg type inference. Each direct call to `server.tool()`
13
+ * forces TypeScript to elaborate a ~10M-instantiation type graph (MCP SDK
14
+ * `ShapeOutput` generics over Zod raw shapes), which OOMs tsc at ~4 GB.
15
+ *
16
+ * This helper casts the schema and handler at the MCP boundary, so tsc never
17
+ * walks that graph. Runtime behavior is identical — the MCP SDK still
18
+ * validates the payload against the Zod schema before invoking the handler.
19
+ *
20
+ * Call sites annotate the arg shape explicitly via the `Args` generic so the
21
+ * handler body stays fully type-safe.
22
+ */
23
+ export declare function registerTool<Args>(server: McpServer, name: string, description: string, schema: ZodRawShape, handler: (args: Args) => Promise<ToolResult>): void;
24
+ export declare function formatError(error: unknown, context: string): string;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerTool = registerTool;
4
+ exports.formatError = formatError;
5
+ /**
6
+ * Thin wrapper around `server.tool(...)` that severs the MCP SDK's deep
7
+ * Zod-shape → handler-arg type inference. Each direct call to `server.tool()`
8
+ * forces TypeScript to elaborate a ~10M-instantiation type graph (MCP SDK
9
+ * `ShapeOutput` generics over Zod raw shapes), which OOMs tsc at ~4 GB.
10
+ *
11
+ * This helper casts the schema and handler at the MCP boundary, so tsc never
12
+ * walks that graph. Runtime behavior is identical — the MCP SDK still
13
+ * validates the payload against the Zod schema before invoking the handler.
14
+ *
15
+ * Call sites annotate the arg shape explicitly via the `Args` generic so the
16
+ * handler body stays fully type-safe.
17
+ */
18
+ function registerTool(server, name, description, schema, handler) {
19
+ server.tool(name, description, schema, handler);
20
+ }
21
+ function formatError(error, context) {
22
+ var _a, _b;
23
+ if (error && typeof error === "object") {
24
+ const e = error;
25
+ if ("message" in e) {
26
+ let msg = `Error ${context}`;
27
+ if ("code" in e || "status" in e) {
28
+ msg += `: [${(_b = (_a = e.code) !== null && _a !== void 0 ? _a : e.status) !== null && _b !== void 0 ? _b : "ERROR"}] ${e.message}`;
29
+ }
30
+ else {
31
+ msg += `: ${e.message}`;
32
+ }
33
+ if (Array.isArray(e.fieldErrors) && e.fieldErrors.length > 0) {
34
+ msg +=
35
+ "\nField errors:\n" +
36
+ e.fieldErrors
37
+ .map((f) => ` ${f.field}: ${f.message}`)
38
+ .join("\n");
39
+ }
40
+ return msg;
41
+ }
42
+ }
43
+ return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
44
+ }
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.registerAuthProviderTools = registerAuthProviderTools;
16
16
  const axios_1 = __importDefault(require("axios"));
17
17
  const zod_1 = require("zod");
18
+ const _register_js_1 = require("./_register.js");
18
19
  /**
19
20
  * Ensures the SDK has a valid token by making a lightweight SDK call if needed.
20
21
  */
@@ -69,22 +70,6 @@ function createIamClient(sdk, centraliUrl, workspaceId) {
69
70
  }));
70
71
  return client;
71
72
  }
72
- function formatError(error, context) {
73
- var _a, _b, _c, _d, _e, _f, _g, _h;
74
- if (error && typeof error === "object") {
75
- const e = error;
76
- if ((_a = e.response) === null || _a === void 0 ? void 0 : _a.data) {
77
- const d = e.response.data;
78
- const code = (_e = (_d = (_b = d.code) !== null && _b !== void 0 ? _b : (_c = d.error) === null || _c === void 0 ? void 0 : _c.code) !== null && _d !== void 0 ? _d : e.response.status) !== null && _e !== void 0 ? _e : "ERROR";
79
- const message = (_h = (_f = d.message) !== null && _f !== void 0 ? _f : (_g = d.error) === null || _g === void 0 ? void 0 : _g.message) !== null && _h !== void 0 ? _h : JSON.stringify(d);
80
- return `Error ${context}: [${code}] ${message}`;
81
- }
82
- if ("message" in e) {
83
- return `Error ${context}: ${e.message}`;
84
- }
85
- }
86
- return `Error ${context}: ${error instanceof Error ? error.message : String(error)}`;
87
- }
88
73
  const ClaimMappingZod = zod_1.z.object({
89
74
  attribute: zod_1.z.string().describe("Attribute name used in policies (automatically prefixed with ext_). Must start with a letter, alphanumeric + underscores only. Example: 'role' becomes ext_role in policies."),
90
75
  jwtPath: zod_1.z.string().describe("Dot-notation path to extract from the JWT payload. Examples: 'org_role', 'metadata.plan', 'organization.role'"),
@@ -95,7 +80,7 @@ const ClaimMappingZod = zod_1.z.object({
95
80
  function registerAuthProviderTools(server, sdk, centraliUrl, workspaceId) {
96
81
  const getClient = () => createIamClient(sdk, centraliUrl, workspaceId);
97
82
  // ── List ──────────────────────────────────────────────────────────
98
- server.tool("list_auth_providers", "List external auth providers configured in the workspace. These are identity providers (Clerk, Auth0, Okta, etc.) that can issue JWTs accepted by Centrali for BYOT (Bring Your Own Token) authorization.", {
83
+ (0, _register_js_1.registerTool)(server, "list_auth_providers", "List external auth providers configured in the workspace. These are identity providers (Clerk, Auth0, Okta, etc.) that can issue JWTs accepted by Centrali for BYOT (Bring Your Own Token) authorization.", {
99
84
  includeInactive: zod_1.z.boolean().optional().describe("Include inactive providers (default: false)"),
100
85
  }, (_a) => __awaiter(this, [_a], void 0, function* ({ includeInactive }) {
101
86
  try {
@@ -109,13 +94,13 @@ function registerAuthProviderTools(server, sdk, centraliUrl, workspaceId) {
109
94
  }
110
95
  catch (error) {
111
96
  return {
112
- content: [{ type: "text", text: formatError(error, "listing auth providers") }],
97
+ content: [{ type: "text", text: (0, _register_js_1.formatError)(error, "listing auth providers") }],
113
98
  isError: true,
114
99
  };
115
100
  }
116
101
  }));
117
102
  // ── Get ───────────────────────────────────────────────────────────
118
- server.tool("get_auth_provider", "Get details of an external auth provider by ID, including claim mappings and JWKS configuration.", {
103
+ (0, _register_js_1.registerTool)(server, "get_auth_provider", "Get details of an external auth provider by ID, including claim mappings and JWKS configuration.", {
119
104
  providerId: zod_1.z.string().describe("The provider ID (UUID)"),
120
105
  }, (_a) => __awaiter(this, [_a], void 0, function* ({ providerId }) {
121
106
  try {
@@ -126,13 +111,13 @@ function registerAuthProviderTools(server, sdk, centraliUrl, workspaceId) {
126
111
  }
127
112
  catch (error) {
128
113
  return {
129
- content: [{ type: "text", text: formatError(error, `getting auth provider '${providerId}'`) }],
114
+ content: [{ type: "text", text: (0, _register_js_1.formatError)(error, `getting auth provider '${providerId}'`) }],
130
115
  isError: true,
131
116
  };
132
117
  }
133
118
  }));
134
119
  // ── Create ────────────────────────────────────────────────────────
135
- server.tool("create_auth_provider", "Create an external auth provider for BYOT (Bring Your Own Token). This lets your app's users authenticate with Clerk, Auth0, Okta, or any OIDC provider, and Centrali validates their JWTs and extracts claims for authorization policies. Call describe_auth_providers for the full setup guide.", {
120
+ (0, _register_js_1.registerTool)(server, "create_auth_provider", "Create an external auth provider for BYOT (Bring Your Own Token). This lets your app's users authenticate with Clerk, Auth0, Okta, or any OIDC provider, and Centrali validates their JWTs and extracts claims for authorization policies. Call describe_auth_providers for the full setup guide.", {
136
121
  name: zod_1.z.string().describe("Display name (e.g., 'Production Clerk')"),
137
122
  slug: zod_1.z.string().describe("URL-safe unique slug (lowercase, hyphens allowed, e.g., 'production-clerk')"),
138
123
  providerType: zod_1.z.enum(["oidc", "clerk", "auth0", "keycloak", "okta", "custom"]).describe("Identity provider type. Use 'clerk', 'auth0', 'okta', or 'keycloak' for built-in support, 'oidc' for any OIDC-compliant provider, or 'custom' for a custom JWT issuer."),
@@ -165,13 +150,13 @@ function registerAuthProviderTools(server, sdk, centraliUrl, workspaceId) {
165
150
  }
166
151
  catch (error) {
167
152
  return {
168
- content: [{ type: "text", text: formatError(error, `creating auth provider '${name}'`) }],
153
+ content: [{ type: "text", text: (0, _register_js_1.formatError)(error, `creating auth provider '${name}'`) }],
169
154
  isError: true,
170
155
  };
171
156
  }
172
157
  }));
173
158
  // ── Update ────────────────────────────────────────────────────────
174
- server.tool("update_auth_provider", "Update an external auth provider. Only include the fields you want to change. Use this to update claim mappings, allowed audiences, or deactivate a provider.", {
159
+ (0, _register_js_1.registerTool)(server, "update_auth_provider", "Update an external auth provider. Only include the fields you want to change. Use this to update claim mappings, allowed audiences, or deactivate a provider.", {
175
160
  providerId: zod_1.z.string().describe("The provider ID (UUID) to update"),
176
161
  name: zod_1.z.string().optional().describe("Updated display name"),
177
162
  jwksUrl: zod_1.z.string().optional().describe("Updated JWKS URL"),
@@ -207,13 +192,13 @@ function registerAuthProviderTools(server, sdk, centraliUrl, workspaceId) {
207
192
  }
208
193
  catch (error) {
209
194
  return {
210
- content: [{ type: "text", text: formatError(error, `updating auth provider '${providerId}'`) }],
195
+ content: [{ type: "text", text: (0, _register_js_1.formatError)(error, `updating auth provider '${providerId}'`) }],
211
196
  isError: true,
212
197
  };
213
198
  }
214
199
  }));
215
200
  // ── Delete ────────────────────────────────────────────────────────
216
- server.tool("delete_auth_provider", "Delete an external auth provider. Tokens from this provider will no longer be accepted.", {
201
+ (0, _register_js_1.registerTool)(server, "delete_auth_provider", "Delete an external auth provider. Tokens from this provider will no longer be accepted.", {
217
202
  providerId: zod_1.z.string().describe("The provider ID (UUID) to delete"),
218
203
  }, (_a) => __awaiter(this, [_a], void 0, function* ({ providerId }) {
219
204
  try {
@@ -224,13 +209,13 @@ function registerAuthProviderTools(server, sdk, centraliUrl, workspaceId) {
224
209
  }
225
210
  catch (error) {
226
211
  return {
227
- content: [{ type: "text", text: formatError(error, `deleting auth provider '${providerId}'`) }],
212
+ content: [{ type: "text", text: (0, _register_js_1.formatError)(error, `deleting auth provider '${providerId}'`) }],
228
213
  isError: true,
229
214
  };
230
215
  }
231
216
  }));
232
217
  // ── Test Claim Extraction ─────────────────────────────────────────
233
- server.tool("test_auth_provider", "Test claim extraction for an auth provider by passing a sample JWT. Decodes the token (without signature verification) and shows which claims would be extracted using the provider's configured mappings. Use this to validate your claim mappings before deploying.", {
218
+ (0, _register_js_1.registerTool)(server, "test_auth_provider", "Test claim extraction for an auth provider by passing a sample JWT. Decodes the token (without signature verification) and shows which claims would be extracted using the provider's configured mappings. Use this to validate your claim mappings before deploying.", {
234
219
  providerId: zod_1.z.string().describe("The provider ID (UUID) to test against"),
235
220
  token: zod_1.z.string().describe("A sample JWT token from your identity provider"),
236
221
  }, (_a) => __awaiter(this, [_a], void 0, function* ({ providerId, token }) {
@@ -242,13 +227,13 @@ function registerAuthProviderTools(server, sdk, centraliUrl, workspaceId) {
242
227
  }
243
228
  catch (error) {
244
229
  return {
245
- content: [{ type: "text", text: formatError(error, `testing auth provider '${providerId}'`) }],
230
+ content: [{ type: "text", text: (0, _register_js_1.formatError)(error, `testing auth provider '${providerId}'`) }],
246
231
  isError: true,
247
232
  };
248
233
  }
249
234
  }));
250
235
  // ── Refresh JWKS ──────────────────────────────────────────────────
251
- server.tool("refresh_auth_provider_jwks", "Force refresh the cached JWKS (JSON Web Key Set) for an auth provider. Use this after your identity provider rotates its signing keys.", {
236
+ (0, _register_js_1.registerTool)(server, "refresh_auth_provider_jwks", "Force refresh the cached JWKS (JSON Web Key Set) for an auth provider. Use this after your identity provider rotates its signing keys.", {
252
237
  providerId: zod_1.z.string().describe("The provider ID (UUID)"),
253
238
  }, (_a) => __awaiter(this, [_a], void 0, function* ({ providerId }) {
254
239
  try {
@@ -259,7 +244,7 @@ function registerAuthProviderTools(server, sdk, centraliUrl, workspaceId) {
259
244
  }
260
245
  catch (error) {
261
246
  return {
262
- content: [{ type: "text", text: formatError(error, `refreshing JWKS for auth provider '${providerId}'`) }],
247
+ content: [{ type: "text", text: (0, _register_js_1.formatError)(error, `refreshing JWKS for auth provider '${providerId}'`) }],
263
248
  isError: true,
264
249
  };
265
250
  }