@rad-security/mcp-server 0.0.35 → 0.0.36-5.g3825a61
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 +222 -148
- package/dist/index.js +405 -370
- package/dist/index.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -45,6 +45,33 @@ function parseToolkitFilters() {
|
|
|
45
45
|
}
|
|
46
46
|
return result;
|
|
47
47
|
}
|
|
48
|
+
// Per-request toolkit selection via headers, so a single hosted endpoint can
|
|
49
|
+
// serve different agents a scoped subset. Falls back to the env filters when no
|
|
50
|
+
// toolkit header is present.
|
|
51
|
+
// X-Rad-Toolkits: comma-separated include list (only these enabled)
|
|
52
|
+
// X-Rad-Exclude-Toolkits: comma-separated exclude list (all others enabled)
|
|
53
|
+
// X-Rad-Readonly: true expose/allow only read-only tools (drops writes)
|
|
54
|
+
function toolkitFiltersForRequest(req) {
|
|
55
|
+
const header = (name) => {
|
|
56
|
+
const v = req.headers[name];
|
|
57
|
+
return Array.isArray(v) ? v[0] : v;
|
|
58
|
+
};
|
|
59
|
+
const parseList = (v) => {
|
|
60
|
+
const items = (v || "")
|
|
61
|
+
.split(",")
|
|
62
|
+
.map((s) => s.trim())
|
|
63
|
+
.filter(Boolean);
|
|
64
|
+
return items.length ? items : undefined;
|
|
65
|
+
};
|
|
66
|
+
const readonly = /^(1|true|yes)$/i.test((header("x-rad-readonly") || "").trim());
|
|
67
|
+
const include = parseList(header("x-rad-toolkits"));
|
|
68
|
+
const exclude = parseList(header("x-rad-exclude-toolkits"));
|
|
69
|
+
// A toolkit header, when present, overrides the env filters.
|
|
70
|
+
if (include || exclude) {
|
|
71
|
+
return { include, exclude, readonly };
|
|
72
|
+
}
|
|
73
|
+
return { ...parseToolkitFilters(), readonly };
|
|
74
|
+
}
|
|
48
75
|
// Toolkits that are disabled by default and must be explicitly included
|
|
49
76
|
const DISABLED_BY_DEFAULT_TOOLKITS = ["custom_workflows"];
|
|
50
77
|
// Check if a toolkit type should be enabled
|
|
@@ -64,8 +91,7 @@ function isToolkitEnabled(toolkitType, filters) {
|
|
|
64
91
|
// By default, all other toolkits are enabled
|
|
65
92
|
return true;
|
|
66
93
|
}
|
|
67
|
-
async function newServer(client) {
|
|
68
|
-
const toolkitFilters = parseToolkitFilters();
|
|
94
|
+
async function newServer(client, toolkitFilters) {
|
|
69
95
|
const server = new Server({
|
|
70
96
|
name: "RAD Security MCP Server",
|
|
71
97
|
version: VERSION,
|
|
@@ -76,298 +102,297 @@ async function newServer(client) {
|
|
|
76
102
|
tools: {},
|
|
77
103
|
},
|
|
78
104
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
description: `Execute RadQL queries for security investigations. Supports: list (filter/search), get_by_id (single item), stats (aggregations).
|
|
105
|
+
const allTools = [
|
|
106
|
+
// Container tools
|
|
107
|
+
...(isToolkitEnabled("containers", toolkitFilters)
|
|
108
|
+
? [
|
|
109
|
+
{
|
|
110
|
+
name: "list_containers",
|
|
111
|
+
annotations: { title: "List Containers", readOnlyHint: true },
|
|
112
|
+
description: "List containers secured by RAD Security with optional filtering by image name, image digest, namespace, cluster_id, or free text search",
|
|
113
|
+
inputSchema: zodToJsonSchema(containers.ListContainersSchema),
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "get_container_details",
|
|
117
|
+
annotations: { title: "Get Container Details", readOnlyHint: true },
|
|
118
|
+
description: "Get detailed information about a container secured by RAD Security",
|
|
119
|
+
inputSchema: zodToJsonSchema(containers.GetContainerDetailsSchema),
|
|
120
|
+
},
|
|
121
|
+
]
|
|
122
|
+
: []),
|
|
123
|
+
// Cluster tools
|
|
124
|
+
...(isToolkitEnabled("clusters", toolkitFilters)
|
|
125
|
+
? [
|
|
126
|
+
{
|
|
127
|
+
name: "list_clusters",
|
|
128
|
+
annotations: { title: "List Clusters", readOnlyHint: true },
|
|
129
|
+
description: "List Kubernetes clusters managed by RAD Security",
|
|
130
|
+
inputSchema: zodToJsonSchema(clusters.ListClustersSchema),
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "get_cluster_details",
|
|
134
|
+
annotations: { title: "Get Cluster Details", readOnlyHint: true },
|
|
135
|
+
description: "Get detailed information about a specific Kubernetes cluster managed by RAD Security",
|
|
136
|
+
inputSchema: zodToJsonSchema(clusters.GetClusterDetailsSchema),
|
|
137
|
+
},
|
|
138
|
+
]
|
|
139
|
+
: []),
|
|
140
|
+
// Audit tools
|
|
141
|
+
...(isToolkitEnabled("audit", toolkitFilters)
|
|
142
|
+
? [
|
|
143
|
+
{
|
|
144
|
+
name: "who_shelled_into_pod",
|
|
145
|
+
annotations: { title: "Who Shelled Into Pod", readOnlyHint: true },
|
|
146
|
+
description: "Get k8s audit logs with information about users who shelled into a pod",
|
|
147
|
+
inputSchema: zodToJsonSchema(audit.WhoShelledIntoPodSchema),
|
|
148
|
+
},
|
|
149
|
+
]
|
|
150
|
+
: []),
|
|
151
|
+
// Image tools
|
|
152
|
+
...(isToolkitEnabled("images", toolkitFilters)
|
|
153
|
+
? [
|
|
154
|
+
{
|
|
155
|
+
name: "list_images",
|
|
156
|
+
annotations: { title: "List Images", readOnlyHint: true },
|
|
157
|
+
description: "List container images with optional filtering by page, page size, sort, and search query",
|
|
158
|
+
inputSchema: zodToJsonSchema(images.ListImagesSchema),
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: "list_image_vulnerabilities",
|
|
162
|
+
annotations: { title: "List Image Vulnerabilities", readOnlyHint: true },
|
|
163
|
+
description: "List vulnerabilities in a container image with optional filtering by severity",
|
|
164
|
+
inputSchema: zodToJsonSchema(images.ListImageVulnerabilitiesSchema),
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "get_top_vulnerable_images",
|
|
168
|
+
annotations: { title: "Get Top Vulnerable Images", readOnlyHint: true },
|
|
169
|
+
description: "Get the most vulnerable images from your account",
|
|
170
|
+
inputSchema: zodToJsonSchema(z.object({})),
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "get_image_sbom",
|
|
174
|
+
annotations: { title: "Get Image SBOM", readOnlyHint: true },
|
|
175
|
+
description: "Get the SBOM of a container image",
|
|
176
|
+
inputSchema: zodToJsonSchema(images.GetImageSBOMSchema),
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
name: "ignore_cve",
|
|
180
|
+
annotations: { title: "Ignore CVE", readOnlyHint: false, destructiveHint: false },
|
|
181
|
+
description: "Ignore a CVE for this account so it no longer appears in vulnerability reporting. Use for confirmed false positives, accepted risks, or won't-fix decisions. Do NOT use for remediated CVEs — those drop off automatically on the next scan.",
|
|
182
|
+
inputSchema: zodToJsonSchema(cveDispositions.ignoreCveSchema),
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "unignore_cve",
|
|
186
|
+
annotations: { title: "Unignore CVE", readOnlyHint: false, destructiveHint: true },
|
|
187
|
+
description: "Remove an account-wide CVE disposition, restoring the CVE to vulnerability reporting.",
|
|
188
|
+
inputSchema: zodToJsonSchema(cveDispositions.unignoreCveSchema),
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: "list_cve_dispositions",
|
|
192
|
+
annotations: { title: "List CVE Dispositions", readOnlyHint: true },
|
|
193
|
+
description: "List active CVE dispositions (ignored / false positive) for this account, with reason and author.",
|
|
194
|
+
inputSchema: zodToJsonSchema(cveDispositions.listCveDispositionsSchema),
|
|
195
|
+
},
|
|
196
|
+
]
|
|
197
|
+
: []),
|
|
198
|
+
// Kubernetes Object tools
|
|
199
|
+
...(isToolkitEnabled("kubeobject", toolkitFilters)
|
|
200
|
+
? [
|
|
201
|
+
{
|
|
202
|
+
name: "get_k8s_resource_details",
|
|
203
|
+
annotations: { title: "Get Kubernetes Resource Details", readOnlyHint: true },
|
|
204
|
+
description: "Get the latest manifest of a Kubernetes resource",
|
|
205
|
+
inputSchema: zodToJsonSchema(kubeobject.GetKubernetesResourceDetailsSchema),
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: "list_k8s_resources",
|
|
209
|
+
annotations: { title: "List Kubernetes Resources", readOnlyHint: true },
|
|
210
|
+
description: "List Kubernetes resources with optional filtering by namespace, resource types, and cluster",
|
|
211
|
+
inputSchema: zodToJsonSchema(kubeobject.ListKubernetesResourcesSchema),
|
|
212
|
+
},
|
|
213
|
+
]
|
|
214
|
+
: []),
|
|
215
|
+
// Runtime tools
|
|
216
|
+
...(isToolkitEnabled("runtime", toolkitFilters)
|
|
217
|
+
? [
|
|
218
|
+
{
|
|
219
|
+
name: "get_containers_process_trees",
|
|
220
|
+
annotations: { title: "Get Container Process Trees", readOnlyHint: true },
|
|
221
|
+
description: "Get process trees for multiple containers",
|
|
222
|
+
inputSchema: zodToJsonSchema(runtime.GetContainersProcessTreesSchema),
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
name: "get_containers_baselines",
|
|
226
|
+
annotations: { title: "Get Container Baselines", readOnlyHint: true },
|
|
227
|
+
description: "Get runtime baselines for multiple containers",
|
|
228
|
+
inputSchema: zodToJsonSchema(runtime.GetContainersBaselinesSchema),
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: "get_container_llm_analysis",
|
|
232
|
+
annotations: { title: "Get Container LLM Analysis", readOnlyHint: true },
|
|
233
|
+
description: "Get LLM analysis of a container's process tree",
|
|
234
|
+
inputSchema: zodToJsonSchema(runtime.GetContainerLLMAnalysisSchema),
|
|
235
|
+
},
|
|
236
|
+
]
|
|
237
|
+
: []),
|
|
238
|
+
// Findings tools
|
|
239
|
+
...(isToolkitEnabled("findings", toolkitFilters)
|
|
240
|
+
? [
|
|
241
|
+
{
|
|
242
|
+
name: "list_security_findings",
|
|
243
|
+
annotations: { title: "List Security Findings", readOnlyHint: true },
|
|
244
|
+
description: "List security findings with optional filtering by types, severities, sources, and status",
|
|
245
|
+
inputSchema: zodToJsonSchema(findings.listFindingsSchema),
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: "update_security_finding_status",
|
|
249
|
+
annotations: { title: "Update Security Finding Status", readOnlyHint: false, destructiveHint: false },
|
|
250
|
+
description: "Update the status of a security finding",
|
|
251
|
+
inputSchema: zodToJsonSchema(findings.updateFindingStatusSchema),
|
|
252
|
+
},
|
|
253
|
+
]
|
|
254
|
+
: []),
|
|
255
|
+
// Inbox tools
|
|
256
|
+
...(isToolkitEnabled("inbox", toolkitFilters)
|
|
257
|
+
? [
|
|
258
|
+
{
|
|
259
|
+
name: "mark_inbox_item_as_false_positive",
|
|
260
|
+
annotations: { title: "Mark Inbox Item as False Positive", readOnlyHint: false, destructiveHint: false },
|
|
261
|
+
description: "Mark an inbox item as a false positive with a reason",
|
|
262
|
+
inputSchema: zodToJsonSchema(inbox.MarkInboxItemAsFalsePositiveSchema),
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
name: "list_inbox_items",
|
|
266
|
+
annotations: { title: "List Inbox Items", readOnlyHint: true },
|
|
267
|
+
description: "List inbox items with optional filtering by any field. Multiple filters can be combined eg. 'search:cve-2024-12345 and severity:high'",
|
|
268
|
+
inputSchema: zodToJsonSchema(inbox.ListInboxItemsSchema),
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
name: "get_inbox_item_details",
|
|
272
|
+
annotations: { title: "Get Inbox Item Details", readOnlyHint: true },
|
|
273
|
+
description: "Get detailed information about a specific inbox item",
|
|
274
|
+
inputSchema: zodToJsonSchema(inbox.GetInboxItemDetailsSchema),
|
|
275
|
+
},
|
|
276
|
+
]
|
|
277
|
+
: []),
|
|
278
|
+
// Workflows tools
|
|
279
|
+
...(isToolkitEnabled("workflows", toolkitFilters)
|
|
280
|
+
? [
|
|
281
|
+
{
|
|
282
|
+
name: "list_workflows",
|
|
283
|
+
annotations: { title: "List Workflows", readOnlyHint: true },
|
|
284
|
+
description: "List all workflows",
|
|
285
|
+
inputSchema: zodToJsonSchema(workflows.ListWorkflowsSchema),
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
name: "get_workflow",
|
|
289
|
+
annotations: { title: "Get Workflow", readOnlyHint: true },
|
|
290
|
+
description: "Get detailed information about a specific workflow by ID. It contains the workflow definition, default arguments, and schema how to run the workflow",
|
|
291
|
+
inputSchema: zodToJsonSchema(workflows.GetWorkflowSchema),
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
name: "list_workflow_runs",
|
|
295
|
+
annotations: { title: "List Workflow Runs", readOnlyHint: true },
|
|
296
|
+
description: "List workflow runs with optional filtering by workflow ID",
|
|
297
|
+
inputSchema: zodToJsonSchema(workflows.ListWorkflowRunsSchema),
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: "get_workflow_run",
|
|
301
|
+
annotations: { title: "Get Workflow Run", readOnlyHint: true },
|
|
302
|
+
description: "Get detailed information about a specific workflow run",
|
|
303
|
+
inputSchema: zodToJsonSchema(workflows.GetWorkflowRunSchema),
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
name: "run_workflow",
|
|
307
|
+
annotations: { title: "Run Workflow", readOnlyHint: false, destructiveHint: true },
|
|
308
|
+
description: "Run a workflow with optional argument overrides",
|
|
309
|
+
inputSchema: zodToJsonSchema(workflows.RunWorkflowSchema),
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
name: "list_workflow_schedules",
|
|
313
|
+
annotations: { title: "List Workflow Schedules", readOnlyHint: true },
|
|
314
|
+
description: "List workflow schedules with optional filtering by workflow ID",
|
|
315
|
+
inputSchema: zodToJsonSchema(workflows.ListWorkflowSchedulesSchema),
|
|
316
|
+
},
|
|
317
|
+
]
|
|
318
|
+
: []),
|
|
319
|
+
// Custom Workflows tools (disabled by default, enable via INCLUDE_TOOLKITS=custom_workflows)
|
|
320
|
+
...(isToolkitEnabled("custom_workflows", toolkitFilters)
|
|
321
|
+
? [
|
|
322
|
+
{
|
|
323
|
+
name: "create_custom_workflow",
|
|
324
|
+
annotations: { title: "Create Custom Workflow", readOnlyHint: false, destructiveHint: false },
|
|
325
|
+
description: "Create a new custom workflow from YAML definition. The YAML will be validated before deployment.",
|
|
326
|
+
inputSchema: zodToJsonSchema(customWorkflows.CreateCustomWorkflowSchema),
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
name: "update_custom_workflow",
|
|
330
|
+
annotations: { title: "Update Custom Workflow", readOnlyHint: false, destructiveHint: false },
|
|
331
|
+
description: "Update an existing custom workflow with new YAML. Only custom workflows (created via create_custom_workflow) can be updated.",
|
|
332
|
+
inputSchema: zodToJsonSchema(customWorkflows.UpdateCustomWorkflowSchema),
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
name: "add_workflow_schedule",
|
|
336
|
+
annotations: { title: "Add Workflow Schedule", readOnlyHint: false, destructiveHint: false },
|
|
337
|
+
description: "Add a cron-based schedule to a workflow. The schedule will trigger the workflow automatically at the specified times.",
|
|
338
|
+
inputSchema: zodToJsonSchema(customWorkflows.AddWorkflowScheduleSchema),
|
|
339
|
+
},
|
|
340
|
+
]
|
|
341
|
+
: []),
|
|
342
|
+
// Knowledge Base tools
|
|
343
|
+
...(isToolkitEnabled("knowledge_base", toolkitFilters)
|
|
344
|
+
? [
|
|
345
|
+
{
|
|
346
|
+
name: "search_knowledge_base",
|
|
347
|
+
annotations: { title: "Search Knowledge Base", readOnlyHint: true },
|
|
348
|
+
description: "Search your organization's knowledge base to find relevant uploaded documents, procedures, reports, and other content using natural language queries",
|
|
349
|
+
inputSchema: zodToJsonSchema(knowledgeBase.SearchKnowledgeBaseSchema),
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
name: "list_knowledge_base_collections",
|
|
353
|
+
annotations: { title: "List Knowledge Base Collections", readOnlyHint: true },
|
|
354
|
+
description: "List all collections in your organization's knowledge base. Collections are used to organize and categorize documents",
|
|
355
|
+
inputSchema: zodToJsonSchema(knowledgeBase.ListCollectionsSchema),
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
name: "list_knowledge_base_documents",
|
|
359
|
+
annotations: { title: "List Knowledge Base Documents", readOnlyHint: true },
|
|
360
|
+
description: "List documents in your organization's knowledge base with optional filtering by collections, file type, or status",
|
|
361
|
+
inputSchema: zodToJsonSchema(knowledgeBase.ListDocumentsSchema),
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: "query_knowledge_base_document",
|
|
365
|
+
annotations: { title: "Query Knowledge Base Document", readOnlyHint: true },
|
|
366
|
+
description: "Query a CSV document from the knowledge base using natural language. IMPORTANT: This tool ONLY works with CSV documents. Use list_knowledge_base_documents with filters='file_type:csv' to find CSV document IDs (search_knowledge_base results also contain document IDs). Results are returned as a markdown table",
|
|
367
|
+
inputSchema: zodToJsonSchema(knowledgeBase.StructuredQueryDocumentSchema),
|
|
368
|
+
},
|
|
369
|
+
]
|
|
370
|
+
: []),
|
|
371
|
+
// RadQL tools
|
|
372
|
+
...(isToolkitEnabled("radql", toolkitFilters)
|
|
373
|
+
? [
|
|
374
|
+
{
|
|
375
|
+
name: "radql_list_data_types",
|
|
376
|
+
annotations: { title: "RadQL: List Data Types", readOnlyHint: true },
|
|
377
|
+
description: "List all available RadQL data types (discovery). ALWAYS call this FIRST before using other RadQL tools to discover what data is available to query. Returns data types like 'containers', 'kubernetes_resources', 'inbox_items', 'cloud_resources', 'cloud_benchmarks', 'cloud_benchmark_summaries', etc. with descriptions.",
|
|
378
|
+
inputSchema: zodToJsonSchema(radql.RadQLListDataTypesSchema),
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
name: "radql_get_type_metadata",
|
|
382
|
+
annotations: { title: "RadQL: Get Type Metadata", readOnlyHint: true },
|
|
383
|
+
description: "Get schema/metadata for a specific RadQL data type. Shows available fields, data types, which fields can be filtered/searched, and provides query examples. Call this AFTER radql_list_data_types to understand how to query a specific data type.",
|
|
384
|
+
inputSchema: zodToJsonSchema(radql.RadQLGetTypeMetadataSchema),
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
name: "radql_list_filter_values",
|
|
388
|
+
annotations: { title: "RadQL: List Filter Values", readOnlyHint: true },
|
|
389
|
+
description: "List possible values for a filter field (e.g., namespace list, cluster list, severity values). Useful for building dynamic filters when you need to know available enum-like values. Call this when constructing filters that need specific values.",
|
|
390
|
+
inputSchema: zodToJsonSchema(radql.RadQLListFilterValuesSchema),
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
name: "radql_query",
|
|
394
|
+
annotations: { title: "RadQL: Query", readOnlyHint: true },
|
|
395
|
+
description: `Execute RadQL queries for security investigations. Supports: list (filter/search), get_by_id (single item), stats (aggregations).
|
|
371
396
|
|
|
372
397
|
WORKFLOW: radql_list_data_types -> radql_get_type_metadata -> radql_query
|
|
373
398
|
|
|
@@ -411,83 +436,90 @@ OK to leave unquoted:
|
|
|
411
436
|
- Simple wildcards: name:nginx*
|
|
412
437
|
|
|
413
438
|
For complete schema: call radql_get_type_metadata with target data_type`,
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
439
|
+
inputSchema: zodToJsonSchema(radql.RadQLQuerySchema),
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
name: "radql_query_builder",
|
|
443
|
+
annotations: { title: "RadQL: Query Builder", readOnlyHint: true },
|
|
444
|
+
description: "Helper tool to build RadQL queries programmatically from structured conditions. Useful when you need to construct complex filter or stats queries from structured inputs.",
|
|
445
|
+
inputSchema: zodToJsonSchema(radql.RadQLQueryBuilderSchema),
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
name: "radql_batch_query",
|
|
449
|
+
annotations: { title: "RadQL: Batch Query", readOnlyHint: true },
|
|
450
|
+
description: "Execute multiple RadQL queries in parallel for efficiency. Useful for fetching related data from different data types simultaneously (e.g., container details + vulnerabilities + network connections).",
|
|
451
|
+
inputSchema: zodToJsonSchema(radql.RadQLBatchQuerySchema),
|
|
452
|
+
},
|
|
453
|
+
]
|
|
454
|
+
: []),
|
|
455
|
+
// Dashboards tools
|
|
456
|
+
...(isToolkitEnabled("dashboards", toolkitFilters)
|
|
457
|
+
? [
|
|
458
|
+
{
|
|
459
|
+
name: "list_widget_templates",
|
|
460
|
+
annotations: { title: "List Widget Templates", readOnlyHint: true },
|
|
461
|
+
description: "List widget templates with optional filtering by visualization type and category",
|
|
462
|
+
inputSchema: zodToJsonSchema(dashboards.ListWidgetTemplatesSchema),
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
name: "get_widget_template",
|
|
466
|
+
annotations: { title: "Get Widget Template", readOnlyHint: true },
|
|
467
|
+
description: "Get detailed information about a specific widget template",
|
|
468
|
+
inputSchema: zodToJsonSchema(dashboards.GetWidgetTemplateSchema),
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
name: "list_dashboard_templates",
|
|
472
|
+
annotations: { title: "List Dashboard Templates", readOnlyHint: true },
|
|
473
|
+
description: "List dashboard templates with optional filtering by category",
|
|
474
|
+
inputSchema: zodToJsonSchema(dashboards.ListDashboardTemplatesSchema),
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
name: "get_dashboard_template",
|
|
478
|
+
annotations: { title: "Get Dashboard Template", readOnlyHint: true },
|
|
479
|
+
description: "Get detailed information about a specific dashboard template",
|
|
480
|
+
inputSchema: zodToJsonSchema(dashboards.GetDashboardTemplateSchema),
|
|
481
|
+
},
|
|
482
|
+
{
|
|
483
|
+
name: "list_dashboards",
|
|
484
|
+
annotations: { title: "List Dashboards", readOnlyHint: true },
|
|
485
|
+
description: "List dashboards for the account",
|
|
486
|
+
inputSchema: zodToJsonSchema(dashboards.ListDashboardsSchema),
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
name: "get_dashboard",
|
|
490
|
+
annotations: { title: "Get Dashboard", readOnlyHint: true },
|
|
491
|
+
description: "Get detailed information about a specific dashboard",
|
|
492
|
+
inputSchema: zodToJsonSchema(dashboards.GetDashboardSchema),
|
|
493
|
+
},
|
|
494
|
+
]
|
|
495
|
+
: []),
|
|
496
|
+
// Integrations tools
|
|
497
|
+
...(isToolkitEnabled("integrations", toolkitFilters)
|
|
498
|
+
? [
|
|
499
|
+
{
|
|
500
|
+
name: "list_external_integrations",
|
|
501
|
+
annotations: { title: "List External Integrations", readOnlyHint: true },
|
|
502
|
+
description: "List external integrations configured for the tenant (e.g., Slack, AWS CloudTrail, Okta). Returns integration details including capabilities, configuration, mcp support and sync status.",
|
|
503
|
+
inputSchema: zodToJsonSchema(integrations.ListExternalIntegrationsSchema),
|
|
504
|
+
},
|
|
505
|
+
]
|
|
506
|
+
: []),
|
|
507
|
+
];
|
|
508
|
+
// In read-only mode, expose only tools whose readOnlyHint is true.
|
|
509
|
+
const tools = toolkitFilters.readonly
|
|
510
|
+
? allTools.filter((t) => t.annotations
|
|
511
|
+
?.readOnlyHint === true)
|
|
512
|
+
: allTools;
|
|
513
|
+
// The advertised set is also the allowed set — CallTool enforces it below.
|
|
514
|
+
const enabledToolNames = new Set(tools.map((t) => t.name));
|
|
515
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
487
516
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
488
517
|
const startTime = Date.now();
|
|
489
518
|
const toolName = request.params.name;
|
|
490
519
|
try {
|
|
520
|
+
if (!enabledToolNames.has(toolName)) {
|
|
521
|
+
throw new Error(`Tool "${toolName}" is not enabled for this session`);
|
|
522
|
+
}
|
|
491
523
|
if (!request.params.arguments) {
|
|
492
524
|
throw new Error("Arguments are required");
|
|
493
525
|
}
|
|
@@ -1032,7 +1064,7 @@ async function main() {
|
|
|
1032
1064
|
}
|
|
1033
1065
|
if (transportType === "stdio") {
|
|
1034
1066
|
const transport = new StdioServerTransport();
|
|
1035
|
-
const server = await newServer(RadSecurityClient.fromEnv());
|
|
1067
|
+
const server = await newServer(RadSecurityClient.fromEnv(), parseToolkitFilters());
|
|
1036
1068
|
await server.connect(transport);
|
|
1037
1069
|
logger.info({ transport: "stdio" }, "server_ready");
|
|
1038
1070
|
}
|
|
@@ -1068,7 +1100,7 @@ async function main() {
|
|
|
1068
1100
|
transport.onclose = () => {
|
|
1069
1101
|
delete transports[transport.sessionId];
|
|
1070
1102
|
};
|
|
1071
|
-
const server = await newServer(RadSecurityClient.fromEnv());
|
|
1103
|
+
const server = await newServer(RadSecurityClient.fromEnv(), parseToolkitFilters());
|
|
1072
1104
|
await server.connect(transport);
|
|
1073
1105
|
});
|
|
1074
1106
|
app.post("/messages", async (req, res) => {
|
|
@@ -1096,6 +1128,9 @@ async function main() {
|
|
|
1096
1128
|
"Authorization",
|
|
1097
1129
|
"mcp-session-id",
|
|
1098
1130
|
"mcp-protocol-version",
|
|
1131
|
+
"X-Rad-Toolkits",
|
|
1132
|
+
"X-Rad-Exclude-Toolkits",
|
|
1133
|
+
"X-Rad-Readonly",
|
|
1099
1134
|
],
|
|
1100
1135
|
exposedHeaders: ["mcp-session-id"],
|
|
1101
1136
|
}));
|
|
@@ -1150,7 +1185,7 @@ async function main() {
|
|
|
1150
1185
|
delete transports[transport.sessionId];
|
|
1151
1186
|
}
|
|
1152
1187
|
};
|
|
1153
|
-
const server = await newServer(client);
|
|
1188
|
+
const server = await newServer(client, toolkitFiltersForRequest(req));
|
|
1154
1189
|
// Connect to the MCP server
|
|
1155
1190
|
await server.connect(transport);
|
|
1156
1191
|
}
|