@centrali-io/centrali-mcp 4.4.4 → 4.4.6
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 +146 -14
- package/dist/index.js +5 -1
- package/dist/tools/auth-providers.d.ts +3 -0
- package/dist/tools/auth-providers.js +267 -0
- package/dist/tools/compute.d.ts +1 -1
- package/dist/tools/compute.js +131 -2
- package/dist/tools/describe.js +499 -5
- package/dist/tools/orchestrations.js +9 -9
- package/dist/tools/pages.js +31 -12
- package/dist/tools/service-accounts.d.ts +3 -0
- package/dist/tools/service-accounts.js +856 -0
- package/package.json +2 -2
- package/src/index.ts +5 -1
- package/src/tools/auth-providers.ts +290 -0
- package/src/tools/compute.ts +142 -2
- package/src/tools/describe.ts +521 -5
- package/src/tools/orchestrations.ts +9 -9
- package/src/tools/pages.ts +27 -9
- package/src/tools/service-accounts.ts +1051 -0
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# @centrali-io/centrali-mcp
|
|
2
2
|
|
|
3
|
-
MCP (Model Context Protocol) server for the Centrali platform. Lets AI assistants (Claude, Cursor, etc.) interact with Centrali workspaces — query data, manage records, search, trigger compute functions, and more.
|
|
3
|
+
MCP (Model Context Protocol) server for the Centrali platform. Lets AI assistants (Claude, Cursor, etc.) interact with Centrali workspaces — query data, manage records, search, trigger compute functions, inspect execution results, build orchestrations, and more.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> **Full documentation:** [docs.centrali.io](https://docs.centrali.io) — SDK guide, API reference, compute functions, orchestrations, and more.
|
|
6
|
+
|
|
7
|
+
Built on `@centrali-io/centrali-sdk` v4.4.6. Authenticates via service account client credentials.
|
|
6
8
|
|
|
7
9
|
## Setup
|
|
8
10
|
|
|
@@ -33,30 +35,53 @@ Add to your MCP client configuration (e.g., Claude Desktop, Cursor):
|
|
|
33
35
|
| `CENTRALI_CLIENT_ID` | Yes | Service account client ID |
|
|
34
36
|
| `CENTRALI_CLIENT_SECRET` | Yes | Service account client secret |
|
|
35
37
|
| `CENTRALI_WORKSPACE` | Yes | Workspace slug to operate in |
|
|
36
|
-
|
|
38
|
+
|
|
39
|
+
## Getting Started
|
|
40
|
+
|
|
41
|
+
After connecting, call `describe_centrali` first — it returns the full capability map, feature matrix, and SDK integration guidance. Then use the specific `describe_*` tools for deeper schema details on any domain.
|
|
37
42
|
|
|
38
43
|
## Available Tools
|
|
39
44
|
|
|
40
|
-
###
|
|
45
|
+
### Discovery (call these first)
|
|
41
46
|
| Tool | Description |
|
|
42
47
|
|------|-------------|
|
|
43
|
-
| `
|
|
44
|
-
| `
|
|
48
|
+
| `describe_centrali` | Platform overview, feature matrix, SDK integration guidance, and list of all tools |
|
|
49
|
+
| `describe_collections` | Schema reference for collections (data models, field types, constraints) |
|
|
50
|
+
| `describe_records` | Schema reference for record operations (filters, sorting, pagination, expand) |
|
|
51
|
+
| `describe_search` | Schema reference for full-text search |
|
|
52
|
+
| `describe_compute` | Compute function reference (input contract, secrets, async execution, api object) |
|
|
53
|
+
| `describe_smart_queries` | Smart query reference (parameterized queries, variables) |
|
|
54
|
+
| `describe_orchestrations` | Orchestration reference (multi-step workflows, encrypted params) |
|
|
55
|
+
| `describe_insights` | Anomaly insights reference |
|
|
56
|
+
| `describe_validation` | Data validation reference |
|
|
57
|
+
| `describe_pages` | Pages builder reference |
|
|
58
|
+
| `describe_page_definition` | Page definition schema (blocks, layouts) |
|
|
59
|
+
| `describe_page_blocks` | Available block types for pages |
|
|
60
|
+
| `describe_page_actions` | Page action system reference |
|
|
61
|
+
| `describe_navigation` | Navigation configuration reference |
|
|
62
|
+
| `describe_auth_providers` | Auth provider reference (BYOT setup, claim mappings) |
|
|
63
|
+
| `describe_service_accounts` | Service account & IAM reference (SA setup, roles, groups, permissions) |
|
|
45
64
|
|
|
46
|
-
###
|
|
65
|
+
### Collections
|
|
47
66
|
| Tool | Description |
|
|
48
67
|
|------|-------------|
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
68
|
+
| `list_collections` | List all data collections (schemas) in the workspace |
|
|
69
|
+
| `get_collection` | Get full schema for a collection by record slug |
|
|
70
|
+
| `create_collection` | Create a new collection with typed properties |
|
|
71
|
+
| `update_collection` | Update an existing collection |
|
|
72
|
+
| `delete_collection` | Delete a collection and all its records |
|
|
51
73
|
|
|
52
74
|
### Records
|
|
53
75
|
| Tool | Description |
|
|
54
76
|
|------|-------------|
|
|
55
77
|
| `query_records` | Query records with filters, sorting, pagination |
|
|
56
78
|
| `get_record` | Get a single record by ID |
|
|
79
|
+
| `get_records_by_ids` | Get multiple records by IDs |
|
|
57
80
|
| `create_record` | Create a new record |
|
|
58
81
|
| `update_record` | Update an existing record |
|
|
82
|
+
| `upsert_record` | Create or update a record |
|
|
59
83
|
| `delete_record` | Soft or hard delete a record |
|
|
84
|
+
| `restore_record` | Restore a soft-deleted record |
|
|
60
85
|
|
|
61
86
|
### Search
|
|
62
87
|
| Tool | Description |
|
|
@@ -67,14 +92,69 @@ Add to your MCP client configuration (e.g., Claude Desktop, Cursor):
|
|
|
67
92
|
| Tool | Description |
|
|
68
93
|
|------|-------------|
|
|
69
94
|
| `list_functions` | List compute functions |
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
95
|
+
| `get_function` | Get a function by ID (includes code) |
|
|
96
|
+
| `create_function` | Create a new compute function |
|
|
97
|
+
| `update_function` | Update a function (code, name, timeout) |
|
|
98
|
+
| `delete_function` | Delete a compute function |
|
|
99
|
+
| `test_function` | Test execute code without saving |
|
|
100
|
+
| `list_triggers` | List function triggers (on-demand, event-driven, scheduled, http-trigger) |
|
|
101
|
+
| `get_trigger` | Get a trigger by ID |
|
|
102
|
+
| `create_trigger` | Create a new trigger |
|
|
103
|
+
| `update_trigger` | Update a trigger |
|
|
104
|
+
| `delete_trigger` | Delete a trigger |
|
|
105
|
+
| `invoke_trigger` | Invoke an on-demand trigger (returns job ID — async) |
|
|
106
|
+
| `pause_trigger` | Pause a trigger |
|
|
107
|
+
| `resume_trigger` | Resume a paused trigger |
|
|
108
|
+
| `get_function_run` | Get execution result by run ID (status, output, errors) |
|
|
109
|
+
| `list_function_runs` | List runs by trigger or function ID (execution history) |
|
|
110
|
+
| `get_compute_job_status` | Check async job status by job ID (poll after invoke_trigger) |
|
|
111
|
+
| `list_allowed_domains` | List allowed domains for outbound HTTP |
|
|
112
|
+
| `add_allowed_domain` | Add a domain to the allowlist |
|
|
113
|
+
| `remove_allowed_domain` | Remove a domain from the allowlist |
|
|
72
114
|
|
|
73
115
|
### Smart Queries
|
|
74
116
|
| Tool | Description |
|
|
75
117
|
|------|-------------|
|
|
76
|
-
| `list_smart_queries` | List smart queries, optionally
|
|
118
|
+
| `list_smart_queries` | List smart queries, optionally by collection |
|
|
119
|
+
| `get_smart_query` | Get a smart query by ID |
|
|
120
|
+
| `create_smart_query` | Create a reusable parameterized query |
|
|
121
|
+
| `update_smart_query` | Update a smart query |
|
|
122
|
+
| `delete_smart_query` | Delete a smart query |
|
|
77
123
|
| `execute_smart_query` | Execute a smart query with optional variables |
|
|
124
|
+
| `test_smart_query` | Test a query definition without saving |
|
|
125
|
+
|
|
126
|
+
### Orchestrations
|
|
127
|
+
| Tool | Description |
|
|
128
|
+
|------|-------------|
|
|
129
|
+
| `list_orchestrations` | List all orchestrations in the workspace |
|
|
130
|
+
| `get_orchestration` | Get orchestration details including step definitions |
|
|
131
|
+
| `create_orchestration` | Create a multi-step workflow |
|
|
132
|
+
| `update_orchestration` | Update an orchestration (steps, triggers, encrypted params) |
|
|
133
|
+
| `delete_orchestration` | Delete an orchestration and its runs |
|
|
134
|
+
| `activate_orchestration` | Activate an orchestration (enable triggers) |
|
|
135
|
+
| `pause_orchestration` | Pause an orchestration (disable triggers) |
|
|
136
|
+
| `trigger_orchestration` | Trigger a run with optional input data |
|
|
137
|
+
| `list_orchestration_runs` | List runs for an orchestration |
|
|
138
|
+
| `get_orchestration_run` | Get run details (use includeSteps=true for step-by-step debugging) |
|
|
139
|
+
|
|
140
|
+
### Insights (Anomaly Detection)
|
|
141
|
+
| Tool | Description |
|
|
142
|
+
|------|-------------|
|
|
143
|
+
| `trigger_anomaly_analysis` | Start an anomaly detection scan |
|
|
144
|
+
| `list_insights` | List anomaly insights |
|
|
145
|
+
| `get_insight` | Get a single insight |
|
|
146
|
+
| `acknowledge_insight` | Mark an insight as reviewed |
|
|
147
|
+
| `dismiss_insight` | Dismiss an insight |
|
|
148
|
+
| `get_insights_summary` | Get insights summary counts |
|
|
149
|
+
|
|
150
|
+
### Validation (Data Quality)
|
|
151
|
+
| Tool | Description |
|
|
152
|
+
|------|-------------|
|
|
153
|
+
| `trigger_validation_scan` | Start a data quality scan |
|
|
154
|
+
| `list_validation_suggestions` | List validation suggestions |
|
|
155
|
+
| `accept_validation_suggestion` | Accept a fix (applies to record) |
|
|
156
|
+
| `reject_validation_suggestion` | Reject a suggestion |
|
|
157
|
+
| `get_validation_summary` | Get validation summary counts |
|
|
78
158
|
|
|
79
159
|
### Pages
|
|
80
160
|
| Tool | Description |
|
|
@@ -99,14 +179,66 @@ Add to your MCP client configuration (e.g., Claude Desktop, Cursor):
|
|
|
99
179
|
| `generate_starter_pages` | Generate page proposals from structure IDs |
|
|
100
180
|
| `accept_page_proposal` | Accept a generated proposal and create the page |
|
|
101
181
|
|
|
182
|
+
### Service Accounts & IAM
|
|
183
|
+
| Tool | Description |
|
|
184
|
+
|------|-------------|
|
|
185
|
+
| `list_service_accounts` | List all service accounts |
|
|
186
|
+
| `get_service_account` | Get service account details |
|
|
187
|
+
| `create_service_account` | Create a service account (returns clientId + clientSecret) |
|
|
188
|
+
| `update_service_account_name` | Update SA display name |
|
|
189
|
+
| `update_service_account_description` | Update SA description |
|
|
190
|
+
| `delete_service_account` | Permanently delete a service account |
|
|
191
|
+
| `rotate_service_account_secret` | Rotate client secret (old one immediately invalidated) |
|
|
192
|
+
| `revoke_service_account` | Permanently revoke a service account |
|
|
193
|
+
| `generate_dev_token` | Generate a short-lived dev token for testing |
|
|
194
|
+
| `scan_service_account_permissions` | Full access matrix audit (Allow/Deny per resource+action) |
|
|
195
|
+
| `simulate_service_account_permission` | Simulate an authorization check with evaluation trace |
|
|
196
|
+
| `generate_remediation` | Generate options to grant missing permissions (role, group, or new policy) |
|
|
197
|
+
| `preview_remediation` | Preview what changes a remediation option would make |
|
|
198
|
+
| `apply_remediation` | Apply a remediation option to grant access |
|
|
199
|
+
| `list_service_account_roles` | List roles assigned to a SA |
|
|
200
|
+
| `assign_role_to_service_account` | Assign a role to a SA |
|
|
201
|
+
| `remove_role_from_service_account` | Remove a role from a SA |
|
|
202
|
+
| `list_service_account_groups` | List groups a SA belongs to |
|
|
203
|
+
| `add_service_account_to_group` | Add SA to a group |
|
|
204
|
+
| `remove_service_account_from_group` | Remove SA from a group |
|
|
205
|
+
| `list_roles` | List all roles in the workspace |
|
|
206
|
+
| `get_role` | Get role details with permissions |
|
|
207
|
+
| `create_role` | Create a role with permissions |
|
|
208
|
+
| `update_role` | Update a role |
|
|
209
|
+
| `delete_role` | Delete a role |
|
|
210
|
+
| `list_groups` | List all groups |
|
|
211
|
+
| `get_group` | Get group details |
|
|
212
|
+
| `create_group` | Create a group |
|
|
213
|
+
| `update_group` | Update a group |
|
|
214
|
+
| `delete_group` | Delete a group |
|
|
215
|
+
|
|
216
|
+
### Publishable Keys (Frontend)
|
|
217
|
+
| Tool | Description |
|
|
218
|
+
|------|-------------|
|
|
219
|
+
| `list_publishable_keys` | List all publishable keys |
|
|
220
|
+
| `get_publishable_key` | Get key details with scopes |
|
|
221
|
+
| `create_publishable_key` | Create a scoped frontend key (pk_live_...) |
|
|
222
|
+
| `update_publishable_key` | Update label or scopes |
|
|
223
|
+
| `revoke_publishable_key` | Revoke a key (immediate, irreversible) |
|
|
224
|
+
|
|
225
|
+
### Identity
|
|
226
|
+
| Tool | Description |
|
|
227
|
+
|------|-------------|
|
|
228
|
+
| `get_current_identity` | Get the MCP's own service account ID and details |
|
|
229
|
+
|
|
230
|
+
### Structures (Deprecated)
|
|
231
|
+
| Tool | Description |
|
|
232
|
+
|------|-------------|
|
|
233
|
+
| `list_structures` | *Deprecated: use `list_collections`* |
|
|
234
|
+
| `get_structure` | *Deprecated: use `get_collection`* |
|
|
235
|
+
|
|
102
236
|
## Resources
|
|
103
237
|
|
|
104
238
|
| URI | Description |
|
|
105
239
|
|-----|-------------|
|
|
106
240
|
| `centrali://collections` | List of all collections with name, slug, description |
|
|
107
241
|
| `centrali://collections/{slug}` | Full schema for a specific collection |
|
|
108
|
-
| `centrali://structures` | *Deprecated: use `centrali://collections`* |
|
|
109
|
-
| `centrali://structures/{slug}` | *Deprecated: use `centrali://collections/{slug}`* |
|
|
110
242
|
|
|
111
243
|
## Development
|
|
112
244
|
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,8 @@ const insights_js_1 = require("./tools/insights.js");
|
|
|
23
23
|
const validation_js_1 = require("./tools/validation.js");
|
|
24
24
|
const pages_js_1 = require("./tools/pages.js");
|
|
25
25
|
const describe_js_1 = require("./tools/describe.js");
|
|
26
|
+
const auth_providers_js_1 = require("./tools/auth-providers.js");
|
|
27
|
+
const service_accounts_js_1 = require("./tools/service-accounts.js");
|
|
26
28
|
const structures_js_2 = require("./resources/structures.js");
|
|
27
29
|
function getRequiredEnv(name) {
|
|
28
30
|
const value = process.env[name];
|
|
@@ -53,12 +55,14 @@ function main() {
|
|
|
53
55
|
(0, structures_js_1.registerStructureTools)(server, sdk);
|
|
54
56
|
(0, records_js_1.registerRecordTools)(server, sdk);
|
|
55
57
|
(0, search_js_1.registerSearchTools)(server, sdk);
|
|
56
|
-
(0, compute_js_1.registerComputeTools)(server, sdk);
|
|
58
|
+
(0, compute_js_1.registerComputeTools)(server, sdk, baseUrl, workspaceId);
|
|
57
59
|
(0, smart_queries_js_1.registerSmartQueryTools)(server, sdk);
|
|
58
60
|
(0, orchestrations_js_1.registerOrchestrationTools)(server, sdk);
|
|
59
61
|
(0, insights_js_1.registerInsightTools)(server, sdk);
|
|
60
62
|
(0, validation_js_1.registerValidationTools)(server, sdk);
|
|
61
63
|
(0, pages_js_1.registerPageTools)(server, sdk, baseUrl, workspaceId);
|
|
64
|
+
(0, auth_providers_js_1.registerAuthProviderTools)(server, sdk, baseUrl, workspaceId);
|
|
65
|
+
(0, service_accounts_js_1.registerServiceAccountTools)(server, sdk, baseUrl, workspaceId, clientId);
|
|
62
66
|
(0, describe_js_1.registerDescribeTools)(server);
|
|
63
67
|
// Register resources
|
|
64
68
|
(0, structures_js_2.registerCollectionResources)(server, sdk);
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.registerAuthProviderTools = registerAuthProviderTools;
|
|
16
|
+
const axios_1 = __importDefault(require("axios"));
|
|
17
|
+
const zod_1 = require("zod");
|
|
18
|
+
/**
|
|
19
|
+
* Ensures the SDK has a valid token by making a lightweight SDK call if needed.
|
|
20
|
+
*/
|
|
21
|
+
function ensureToken(sdk) {
|
|
22
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
+
let token = sdk.getToken();
|
|
24
|
+
if (token)
|
|
25
|
+
return token;
|
|
26
|
+
try {
|
|
27
|
+
yield sdk.functions.list({ limit: 1 });
|
|
28
|
+
}
|
|
29
|
+
catch (_a) {
|
|
30
|
+
// Ignore — we only need the token refresh side effect
|
|
31
|
+
}
|
|
32
|
+
return sdk.getToken();
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates an axios instance for the IAM external auth provider API.
|
|
37
|
+
*/
|
|
38
|
+
function createIamClient(sdk, centraliUrl, workspaceId) {
|
|
39
|
+
const url = new URL(centraliUrl);
|
|
40
|
+
const hostname = url.hostname.startsWith("api.")
|
|
41
|
+
? url.hostname
|
|
42
|
+
: `api.${url.hostname}`;
|
|
43
|
+
const baseURL = `${url.protocol}//${hostname}/iam/workspace/${workspaceId}/api/v1/external-auth-providers`;
|
|
44
|
+
const client = axios_1.default.create({ baseURL });
|
|
45
|
+
client.interceptors.request.use((config) => __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
const token = yield ensureToken(sdk);
|
|
47
|
+
if (token) {
|
|
48
|
+
config.headers.Authorization = `Bearer ${token}`;
|
|
49
|
+
}
|
|
50
|
+
return config;
|
|
51
|
+
}));
|
|
52
|
+
client.interceptors.response.use((response) => response, (error) => __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
var _a, _b;
|
|
54
|
+
const originalRequest = error.config;
|
|
55
|
+
const isAuthError = ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 401 || ((_b = error.response) === null || _b === void 0 ? void 0 : _b.status) === 403;
|
|
56
|
+
if (isAuthError && !originalRequest._hasRetried) {
|
|
57
|
+
originalRequest._hasRetried = true;
|
|
58
|
+
try {
|
|
59
|
+
yield sdk.functions.list({ limit: 1 });
|
|
60
|
+
}
|
|
61
|
+
catch ( /* token refresh side effect */_c) { /* token refresh side effect */ }
|
|
62
|
+
const token = sdk.getToken();
|
|
63
|
+
if (token) {
|
|
64
|
+
originalRequest.headers.Authorization = `Bearer ${token}`;
|
|
65
|
+
return client.request(originalRequest);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return Promise.reject(error);
|
|
69
|
+
}));
|
|
70
|
+
return client;
|
|
71
|
+
}
|
|
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
|
+
const ClaimMappingZod = zod_1.z.object({
|
|
89
|
+
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
|
+
jwtPath: zod_1.z.string().describe("Dot-notation path to extract from the JWT payload. Examples: 'org_role', 'metadata.plan', 'organization.role'"),
|
|
91
|
+
required: zod_1.z.boolean().optional().describe("If true, token validation fails when this claim is missing (default: false)"),
|
|
92
|
+
defaultValue: zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.boolean(), zod_1.z.array(zod_1.z.string())]).optional().describe("Fallback value when claim is not present in the JWT"),
|
|
93
|
+
transform: zod_1.z.enum(["lowercase", "uppercase", "string", "boolean", "array"]).optional().describe("Transform applied to the extracted value before use in policies"),
|
|
94
|
+
});
|
|
95
|
+
function registerAuthProviderTools(server, sdk, centraliUrl, workspaceId) {
|
|
96
|
+
const getClient = () => createIamClient(sdk, centraliUrl, workspaceId);
|
|
97
|
+
// ── 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.", {
|
|
99
|
+
includeInactive: zod_1.z.boolean().optional().describe("Include inactive providers (default: false)"),
|
|
100
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ includeInactive }) {
|
|
101
|
+
try {
|
|
102
|
+
const params = {};
|
|
103
|
+
if (includeInactive)
|
|
104
|
+
params.includeInactive = true;
|
|
105
|
+
const result = yield getClient().get("/", { params });
|
|
106
|
+
return {
|
|
107
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
return {
|
|
112
|
+
content: [{ type: "text", text: formatError(error, "listing auth providers") }],
|
|
113
|
+
isError: true,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}));
|
|
117
|
+
// ── Get ───────────────────────────────────────────────────────────
|
|
118
|
+
server.tool("get_auth_provider", "Get details of an external auth provider by ID, including claim mappings and JWKS configuration.", {
|
|
119
|
+
providerId: zod_1.z.string().describe("The provider ID (UUID)"),
|
|
120
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ providerId }) {
|
|
121
|
+
try {
|
|
122
|
+
const result = yield getClient().get(`/${providerId}`);
|
|
123
|
+
return {
|
|
124
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
return {
|
|
129
|
+
content: [{ type: "text", text: formatError(error, `getting auth provider '${providerId}'`) }],
|
|
130
|
+
isError: true,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}));
|
|
134
|
+
// ── 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.", {
|
|
136
|
+
name: zod_1.z.string().describe("Display name (e.g., 'Production Clerk')"),
|
|
137
|
+
slug: zod_1.z.string().describe("URL-safe unique slug (lowercase, hyphens allowed, e.g., 'production-clerk')"),
|
|
138
|
+
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."),
|
|
139
|
+
issuer: zod_1.z.string().describe("The JWT issuer URL. Centrali auto-discovers JWKS from this. Examples: 'https://clerk.your-domain.com' for Clerk, 'https://your-tenant.auth0.com/' for Auth0, 'https://your-org.okta.com' for Okta."),
|
|
140
|
+
jwksUrl: zod_1.z.string().optional().describe("Override JWKS URL if auto-discovery doesn't work (usually not needed for standard providers)"),
|
|
141
|
+
allowedAudiences: zod_1.z.array(zod_1.z.string()).optional().describe("JWT audience values to accept. If set, tokens without a matching 'aud' claim are rejected."),
|
|
142
|
+
clockSkewSeconds: zod_1.z.number().optional().describe("Seconds of clock skew tolerance for token expiration (default: 60, max: 300)"),
|
|
143
|
+
allowedAlgorithms: zod_1.z.array(zod_1.z.enum(["RS256", "RS384", "RS512", "ES256", "ES384", "ES512"])).optional().describe("Accepted JWT signing algorithms (default: ['RS256'])"),
|
|
144
|
+
claimMappings: zod_1.z.array(ClaimMappingZod).optional().describe("Map JWT claims to policy attributes. Each mapping extracts a value from the JWT and makes it available as ext_<attribute> in authorization policies. Example: { attribute: 'role', jwtPath: 'org_role' } makes ext_role available."),
|
|
145
|
+
allowedOrigins: zod_1.z.array(zod_1.z.string()).optional().describe("CORS origins allowed for browser requests with this provider's tokens"),
|
|
146
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ name, slug, providerType, issuer, jwksUrl, allowedAudiences, clockSkewSeconds, allowedAlgorithms, claimMappings, allowedOrigins }) {
|
|
147
|
+
try {
|
|
148
|
+
const input = { name, slug, providerType, issuer };
|
|
149
|
+
if (jwksUrl !== undefined)
|
|
150
|
+
input.jwksUrl = jwksUrl;
|
|
151
|
+
if (allowedAudiences !== undefined)
|
|
152
|
+
input.allowedAudiences = allowedAudiences;
|
|
153
|
+
if (clockSkewSeconds !== undefined)
|
|
154
|
+
input.clockSkewSeconds = clockSkewSeconds;
|
|
155
|
+
if (allowedAlgorithms !== undefined)
|
|
156
|
+
input.allowedAlgorithms = allowedAlgorithms;
|
|
157
|
+
if (claimMappings !== undefined)
|
|
158
|
+
input.claimMappings = claimMappings;
|
|
159
|
+
if (allowedOrigins !== undefined)
|
|
160
|
+
input.allowedOrigins = allowedOrigins;
|
|
161
|
+
const result = yield getClient().post("/", input);
|
|
162
|
+
return {
|
|
163
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
return {
|
|
168
|
+
content: [{ type: "text", text: formatError(error, `creating auth provider '${name}'`) }],
|
|
169
|
+
isError: true,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}));
|
|
173
|
+
// ── 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.", {
|
|
175
|
+
providerId: zod_1.z.string().describe("The provider ID (UUID) to update"),
|
|
176
|
+
name: zod_1.z.string().optional().describe("Updated display name"),
|
|
177
|
+
jwksUrl: zod_1.z.string().optional().describe("Updated JWKS URL"),
|
|
178
|
+
allowedAudiences: zod_1.z.array(zod_1.z.string()).optional().describe("Updated allowed audiences"),
|
|
179
|
+
clockSkewSeconds: zod_1.z.number().optional().describe("Updated clock skew tolerance (0-300 seconds)"),
|
|
180
|
+
allowedAlgorithms: zod_1.z.array(zod_1.z.enum(["RS256", "RS384", "RS512", "ES256", "ES384", "ES512"])).optional().describe("Updated allowed algorithms"),
|
|
181
|
+
claimMappings: zod_1.z.array(ClaimMappingZod).optional().describe("Updated claim mappings (replaces all existing mappings)"),
|
|
182
|
+
allowedOrigins: zod_1.z.array(zod_1.z.string()).optional().describe("Updated CORS origins"),
|
|
183
|
+
isActive: zod_1.z.boolean().optional().describe("Set to false to deactivate the provider (tokens will be rejected)"),
|
|
184
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ providerId, name, jwksUrl, allowedAudiences, clockSkewSeconds, allowedAlgorithms, claimMappings, allowedOrigins, isActive }) {
|
|
185
|
+
try {
|
|
186
|
+
const input = {};
|
|
187
|
+
if (name !== undefined)
|
|
188
|
+
input.name = name;
|
|
189
|
+
if (jwksUrl !== undefined)
|
|
190
|
+
input.jwksUrl = jwksUrl;
|
|
191
|
+
if (allowedAudiences !== undefined)
|
|
192
|
+
input.allowedAudiences = allowedAudiences;
|
|
193
|
+
if (clockSkewSeconds !== undefined)
|
|
194
|
+
input.clockSkewSeconds = clockSkewSeconds;
|
|
195
|
+
if (allowedAlgorithms !== undefined)
|
|
196
|
+
input.allowedAlgorithms = allowedAlgorithms;
|
|
197
|
+
if (claimMappings !== undefined)
|
|
198
|
+
input.claimMappings = claimMappings;
|
|
199
|
+
if (allowedOrigins !== undefined)
|
|
200
|
+
input.allowedOrigins = allowedOrigins;
|
|
201
|
+
if (isActive !== undefined)
|
|
202
|
+
input.isActive = isActive;
|
|
203
|
+
const result = yield getClient().put(`/${providerId}`, input);
|
|
204
|
+
return {
|
|
205
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
return {
|
|
210
|
+
content: [{ type: "text", text: formatError(error, `updating auth provider '${providerId}'`) }],
|
|
211
|
+
isError: true,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}));
|
|
215
|
+
// ── Delete ────────────────────────────────────────────────────────
|
|
216
|
+
server.tool("delete_auth_provider", "Delete an external auth provider. Tokens from this provider will no longer be accepted.", {
|
|
217
|
+
providerId: zod_1.z.string().describe("The provider ID (UUID) to delete"),
|
|
218
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ providerId }) {
|
|
219
|
+
try {
|
|
220
|
+
yield getClient().delete(`/${providerId}`);
|
|
221
|
+
return {
|
|
222
|
+
content: [{ type: "text", text: `Auth provider '${providerId}' deleted successfully.` }],
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
return {
|
|
227
|
+
content: [{ type: "text", text: formatError(error, `deleting auth provider '${providerId}'`) }],
|
|
228
|
+
isError: true,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}));
|
|
232
|
+
// ── 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.", {
|
|
234
|
+
providerId: zod_1.z.string().describe("The provider ID (UUID) to test against"),
|
|
235
|
+
token: zod_1.z.string().describe("A sample JWT token from your identity provider"),
|
|
236
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ providerId, token }) {
|
|
237
|
+
try {
|
|
238
|
+
const result = yield getClient().post(`/${providerId}/test-extraction`, { token });
|
|
239
|
+
return {
|
|
240
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
return {
|
|
245
|
+
content: [{ type: "text", text: formatError(error, `testing auth provider '${providerId}'`) }],
|
|
246
|
+
isError: true,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}));
|
|
250
|
+
// ── 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.", {
|
|
252
|
+
providerId: zod_1.z.string().describe("The provider ID (UUID)"),
|
|
253
|
+
}, (_a) => __awaiter(this, [_a], void 0, function* ({ providerId }) {
|
|
254
|
+
try {
|
|
255
|
+
const result = yield getClient().post(`/${providerId}/refresh-jwks`);
|
|
256
|
+
return {
|
|
257
|
+
content: [{ type: "text", text: JSON.stringify(result.data, null, 2) }],
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
return {
|
|
262
|
+
content: [{ type: "text", text: formatError(error, `refreshing JWKS for auth provider '${providerId}'`) }],
|
|
263
|
+
isError: true,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
}));
|
|
267
|
+
}
|
package/dist/tools/compute.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { CentraliSDK } from "@centrali-io/centrali-sdk";
|
|
3
|
-
export declare function registerComputeTools(server: McpServer, sdk: CentraliSDK): void;
|
|
3
|
+
export declare function registerComputeTools(server: McpServer, sdk: CentraliSDK, centraliUrl: string, workspaceId: string): void;
|