@jupiterone/jupiterone-mcp
Version:
Model Context Protocol server for JupiterOne account rules and rule details
971 lines • 84.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JupiterOneMcpServer = void 0;
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
const zod_1 = require("zod");
const jupiterone_client_js_1 = require("../client/jupiterone-client.js");
const load_description_js_1 = require("../utils/load-description.js");
const j1ql_validator_js_1 = require("../utils/j1ql-validator.js");
class JupiterOneMcpServer {
server;
client;
validator;
hasEnvironmentAccount;
constructor(config) {
this.client = new jupiterone_client_js_1.JupiterOneClient(config);
this.validator = new j1ql_validator_js_1.J1QLValidator(this.client.j1qlService);
this.server = new mcp_js_1.McpServer({
name: 'jupiterone-mcp',
version: '1.0.0',
});
this.hasEnvironmentAccount = !config.accountId;
this.setupTools();
}
registerTool(options) {
const { name, schema, handler, description } = options;
let finalSchema = schema;
if (this.hasEnvironmentAccount) {
finalSchema = {
...schema,
accountId: zod_1.z
.string()
.describe('JupiterOne Account ID for this request. This should be explicitly asked for with the first tool call.'),
};
}
this.server.tool(name, description || '', finalSchema, async (params) => {
let client = this.client;
let toolParams = params;
let validator = this.validator;
if (this.hasEnvironmentAccount) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { accountId, ...otherParams } = params;
if (!accountId) {
return {
content: [
{
type: 'text',
text: 'Error: accountId is required for this operation because no default JUPITERONE_ACCOUNT_ID is configured.',
},
],
isError: true,
};
}
client = this.client.cloneWithAccountId(accountId);
validator = new j1ql_validator_js_1.J1QLValidator(client.j1qlService);
toolParams = otherParams;
}
return handler(toolParams, client, validator);
});
}
setupTools() {
// Tool: List all rules
this.registerTool({
name: 'list-rules',
description: (0, load_description_js_1.loadDescription)('list-rules.md'),
schema: {
limit: zod_1.z.number().min(1).max(1000).optional(),
cursor: zod_1.z.string().optional(),
},
handler: async ({ limit, cursor }, client) => {
try {
const response = await client.listRuleInstances(limit, cursor);
const instances = response.questionInstances || [];
return {
content: [
{
type: 'text',
text: JSON.stringify({
returned: instances.length,
rules: instances.map((instance) => ({
id: instance.id,
name: instance.name,
description: instance.description,
version: instance.version,
pollingInterval: instance.pollingInterval,
lastEvaluationStartOn: instance.lastEvaluationStartOn,
lastEvaluationEndOn: instance.lastEvaluationEndOn,
latestAlertId: instance.latestAlertId,
latestAlertIsActive: instance.latestAlertIsActive,
type: instance.type,
tags: instance.tags,
outputs: instance.outputs,
})),
pageInfo: response.pageInfo,
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error listing rules: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
});
// Tool: Get rule details
this.registerTool({
name: 'get-rule-details',
schema: {
ruleId: zod_1.z.string(),
},
handler: async ({ ruleId }, client) => {
try {
const instances = await client.getAllRuleInstances();
const rule = instances.find((instance) => instance.id === ruleId);
if (!rule) {
return {
content: [
{
type: 'text',
text: `Rule with ID ${ruleId} not found`,
},
],
isError: true,
};
}
return {
content: [
{
type: 'text',
text: JSON.stringify({
id: rule.id,
resourceGroupId: rule.resourceGroupId,
accountId: rule.accountId,
name: rule.name,
description: rule.description,
version: rule.version,
lastEvaluationStartOn: rule.lastEvaluationStartOn,
lastEvaluationEndOn: rule.lastEvaluationEndOn,
evaluationStep: rule.evaluationStep,
specVersion: rule.specVersion,
notifyOnFailure: rule.notifyOnFailure,
triggerActionsOnNewEntitiesOnly: rule.triggerActionsOnNewEntitiesOnly,
ignorePreviousResults: rule.ignorePreviousResults,
pollingInterval: rule.pollingInterval,
templates: rule.templates,
outputs: rule.outputs,
labels: rule.labels?.map((label) => ({
labelName: label.labelName,
labelValue: label.labelValue,
})) || [],
question: rule.question
? {
queries: rule.question.queries?.map((query) => ({
query: query.query,
name: query.name,
includeDeleted: query.includeDeleted,
})) || [],
}
: null,
questionId: rule.questionId,
latest: rule.latest,
deleted: rule.deleted,
type: rule.type,
operations: rule.operations?.map((op) => ({
when: op.when,
actions: op.actions,
})) || [],
latestAlertId: rule.latestAlertId,
latestAlertIsActive: rule.latestAlertIsActive,
state: rule.state
? {
actions: rule.state.actions,
}
: null,
tags: rule.tags,
remediationSteps: rule.remediationSteps,
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error getting rule details: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
});
// Tool: Test connection
this.registerTool({
name: 'test-connection',
schema: {},
handler: async (_, client) => {
try {
const isConnected = await client.testConnection();
const accountInfo = isConnected ? await client.getAccountInfo() : null;
return {
content: [
{
type: 'text',
text: JSON.stringify({
connected: isConnected,
account: accountInfo,
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Connection test failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
});
// Tool: Evaluate rule
this.registerTool({
name: 'evaluate-rule',
schema: {
ruleId: zod_1.z.string(),
},
handler: async ({ ruleId }, client) => {
try {
const result = await client.evaluateRuleInstance(ruleId);
return {
content: [
{
type: 'text',
text: JSON.stringify({
ruleId,
id: result.id,
__typename: result.__typename,
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error evaluating rule: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
});
// Tool: Get active alerts
this.registerTool({
name: 'get-active-alerts',
description: (0, load_description_js_1.loadDescription)('list-alerts.md'),
schema: {
limit: zod_1.z.number().min(1).max(1000).optional(),
},
handler: async ({ limit }, client) => {
try {
const instances = await client.getAllAlertInstances('ACTIVE');
if (!instances || !Array.isArray(instances)) {
throw new Error('Invalid response from JupiterOne API: instances is not an array');
}
const limitedInstances = limit ? instances.slice(0, limit) : instances;
return {
content: [
{
type: 'text',
text: JSON.stringify({
total: instances.length,
returned: limitedInstances.length,
activeAlerts: limitedInstances.map((instance) => ({
id: instance.id,
name: instance.questionRuleInstance?.name ||
instance.reportRuleInstance?.name ||
'Unknown',
description: instance.questionRuleInstance?.description ||
instance.reportRuleInstance?.description,
level: instance.level,
status: instance.status,
createdOn: instance.createdOn,
lastUpdatedOn: instance.lastUpdatedOn,
lastEvaluationBeginOn: instance.lastEvaluationBeginOn,
lastEvaluationEndOn: instance.lastEvaluationEndOn,
recordCount: instance.lastEvaluationResult?.rawDataDescriptors?.[0]?.recordCount || 0,
tags: instance.questionRuleInstance?.tags || [],
labels: instance.questionRuleInstance?.labels || [],
outputs: instance.lastEvaluationResult?.outputs || [],
users: instance.users,
ruleId: instance.ruleId,
ruleVersion: instance.ruleVersion,
endReason: instance.endReason,
dismissedOn: instance.dismissedOn,
})),
}, null, 2),
},
],
};
}
catch (error) {
console.error('Error in get-active-alerts:', error);
return {
content: [
{
type: 'text',
text: `Error getting active alerts: ${error instanceof Error ? error.message : 'Unknown error'}. Please check your JupiterOne API credentials and connection.`,
},
],
isError: true,
};
}
},
});
// Tool: Get dashboards
this.registerTool({
name: 'get-dashboards',
schema: {},
handler: async (_, client) => {
try {
const dashboards = await client.getDashboards();
return {
content: [
{
type: 'text',
text: JSON.stringify({
total: dashboards.length,
dashboards: dashboards.map((dashboard) => ({
id: dashboard.id,
name: dashboard.name,
category: dashboard.category,
supportedUseCase: dashboard.supportedUseCase,
isJ1ManagedBoard: dashboard.isJ1ManagedBoard,
resourceGroupId: dashboard.resourceGroupId,
starred: dashboard.starred,
lastUpdated: dashboard._timeUpdated,
createdAt: dashboard._createdAt,
prerequisites: dashboard.prerequisites
? {
prerequisitesMet: dashboard.prerequisites.prerequisitesMet,
preRequisitesGroupsFulfilled: dashboard.prerequisites.preRequisitesGroupsFulfilled,
preRequisitesGroupsRequired: dashboard.prerequisites.preRequisitesGroupsRequired,
}
: null,
})),
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error getting dashboards: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
});
// Tool: Create dashboard
this.registerTool({
name: 'create-dashboard',
description: (0, load_description_js_1.loadDescription)('create-dashboard.md'),
schema: {
name: zod_1.z.string(),
type: zod_1.z.string(),
},
handler: async ({ name, type }, client) => {
try {
const result = await client.createDashboard({ name, type });
return {
content: [
{
type: 'text',
text: JSON.stringify({
id: result.id,
name,
type,
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error creating dashboard: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
});
// Tool: Get dashboard details
this.registerTool({
name: 'get-dashboard-details',
schema: {
dashboardId: zod_1.z.string(),
},
handler: async ({ dashboardId }, client) => {
try {
const dashboard = await client.getDashboard(dashboardId);
return {
content: [
{
type: 'text',
text: JSON.stringify({
id: dashboard.id,
name: dashboard.name,
category: dashboard.category,
supportedUseCase: dashboard.supportedUseCase,
isJ1ManagedBoard: dashboard.isJ1ManagedBoard,
published: dashboard.published,
publishedToUserIds: dashboard.publishedToUserIds,
publishedToGroupIds: dashboard.publishedToGroupIds,
groupIds: dashboard.groupIds,
userIds: dashboard.userIds,
scopeFilters: dashboard.scopeFilters,
resourceGroupId: dashboard.resourceGroupId,
starred: dashboard.starred,
lastUpdated: dashboard._timeUpdated,
createdAt: dashboard._createdAt,
prerequisites: dashboard.prerequisites
? {
prerequisitesMet: dashboard.prerequisites.prerequisitesMet,
preRequisitesGroupsFulfilled: dashboard.prerequisites.preRequisitesGroupsFulfilled,
preRequisitesGroupsRequired: dashboard.prerequisites.preRequisitesGroupsRequired,
}
: null,
parameters: dashboard.parameters.map((param) => ({
id: param.id,
label: param.label,
name: param.name,
type: param.type,
valueType: param.valueType,
default: param.default,
options: param.options,
requireValue: param.requireValue,
disableCustomInput: param.disableCustomInput,
})),
widgets: dashboard.widgets.map((widget) => ({
id: widget.id,
title: widget.title,
description: widget.description,
type: widget.type,
questionId: widget.questionId,
noResultMessage: widget.noResultMessage,
includeDeleted: widget.includeDeleted,
config: {
queries: widget.config.queries.map((query) => ({
id: query.id,
name: query.name,
query: query.query,
})),
settings: widget.config.settings,
postQueryFilters: widget.config.postQueryFilters,
disableQueryPolicyFilters: widget.config.disableQueryPolicyFilters,
},
})),
layouts: {
xs: dashboard.layouts.xs.map((item) => ({
i: item.i,
x: item.x,
y: item.y,
w: item.w,
h: item.h,
static: item.static,
moved: item.moved,
})),
sm: dashboard.layouts.sm.map((item) => ({
i: item.i,
x: item.x,
y: item.y,
w: item.w,
h: item.h,
static: item.static,
moved: item.moved,
})),
md: dashboard.layouts.md.map((item) => ({
i: item.i,
x: item.x,
y: item.y,
w: item.w,
h: item.h,
static: item.static,
moved: item.moved,
})),
lg: dashboard.layouts.lg.map((item) => ({
i: item.i,
x: item.x,
y: item.y,
w: item.w,
h: item.h,
static: item.static,
moved: item.moved,
})),
xl: dashboard.layouts.xl.map((item) => ({
i: item.i,
x: item.x,
y: item.y,
w: item.w,
h: item.h,
static: item.static,
moved: item.moved,
})),
},
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error getting dashboard details: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
});
// Tool: Get integration definitions
this.registerTool({
name: 'get-integration-definitions',
description: (0, load_description_js_1.loadDescription)('get-integration-definitions.md'),
schema: {
cursor: zod_1.z.string().optional().describe('Optional cursor for pagination'),
includeConfig: zod_1.z.boolean().optional().describe('Whether to include configuration fields'),
},
handler: async ({ cursor, includeConfig }, client) => {
try {
const definitions = await client.getIntegrationDefinitions(cursor, includeConfig);
return {
content: [
{
type: 'text',
text: JSON.stringify({
total: definitions.definitions.length,
definitions: definitions.definitions.map((def) => ({
id: def.id,
name: def.name,
type: def.type,
title: def.title,
displayMode: def.displayMode,
integrationType: def.integrationType,
integrationClass: def.integrationClass,
integrationCategory: def.integrationCategory,
beta: def.beta,
docsWebLink: def.docsWebLink,
repoWebLink: def.repoWebLink,
invocationPaused: def.invocationPaused,
managedExecutionDisabled: def.managedExecutionDisabled,
managedCreateDisabled: def.managedCreateDisabled,
managedDeleteDisabled: def.managedDeleteDisabled,
totalInstanceCount: def.totalInstanceCount,
description: def.description,
provisioningType: def.provisioningType,
customDefinitionType: def.customDefinitionType,
integrationPlatformFeatures: def.integrationPlatformFeatures,
configFields: def.configFields,
authSections: def.authSections,
configSections: def.configSections,
})),
pageInfo: definitions.pageInfo,
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error getting integration definitions: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
});
// Tool: Get integration instances
this.registerTool({
name: 'get-integration-instances',
description: (0, load_description_js_1.loadDescription)('get-integration-instances.md'),
schema: {
definitionId: zod_1.z
.string()
.optional()
.describe('Optional ID to filter instances by definition'),
limit: zod_1.z
.number()
.min(1)
.max(1000)
.optional()
.describe('Optional limit for number of instances to return'),
},
handler: async ({ definitionId, limit }, client) => {
try {
const instances = await client.getIntegrationInstances(definitionId, undefined, limit);
return {
content: [
{
type: 'text',
text: JSON.stringify({
total: instances.instances.length,
instances: instances.instances.map((instance) => ({
id: instance.id,
name: instance.name,
accountId: instance.accountId,
sourceIntegrationInstanceId: instance.sourceIntegrationInstanceId,
pollingInterval: instance.pollingInterval,
pollingIntervalCronExpression: instance.pollingIntervalCronExpression,
integrationDefinitionId: instance.integrationDefinitionId,
description: instance.description,
config: instance.config,
instanceRelationship: instance.instanceRelationship,
resourceGroupId: instance.resourceGroupId,
createdOn: instance.createdOn,
createdBy: instance.createdBy,
updatedOn: instance.updatedOn,
updatedBy: instance.updatedBy,
mostRecentJob: instance.mostRecentJob
? {
status: instance.mostRecentJob.status,
hasSkippedSteps: instance.mostRecentJob.hasSkippedSteps,
createDate: instance.mostRecentJob.createDate,
}
: null,
})),
pageInfo: instances.pageInfo,
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error getting integration instances: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
});
// Tool: Get integration jobs
this.registerTool({
name: 'get-integration-jobs',
schema: {
status: zod_1.z
.enum(['PENDING', 'RUNNING', 'COMPLETED', 'FAILED', 'CANCELLED'])
.optional()
.describe('Optional status to filter jobs'),
integrationInstanceId: zod_1.z
.string()
.optional()
.describe('Optional ID to filter jobs by instance'),
integrationDefinitionId: zod_1.z
.string()
.optional()
.describe('Optional ID to filter jobs by definition'),
integrationInstanceIds: zod_1.z
.array(zod_1.z.string())
.optional()
.describe('Optional array of instance IDs to filter jobs'),
size: zod_1.z
.number()
.min(1)
.max(1000)
.optional()
.describe('Optional size limit for number of jobs to return'),
},
handler: async ({ status, integrationInstanceId, integrationDefinitionId, integrationInstanceIds, size }, client) => {
try {
const jobs = await client.getIntegrationJobs(status, integrationInstanceId, integrationDefinitionId, integrationInstanceIds, undefined, size);
return {
content: [
{
type: 'text',
text: JSON.stringify({
total: jobs.jobs.length,
jobs: jobs.jobs.map((job) => ({
id: job.id,
status: job.status,
integrationInstanceId: job.integrationInstanceId,
createDate: job.createDate,
endDate: job.endDate,
hasSkippedSteps: job.hasSkippedSteps,
integrationInstance: job.integrationInstance,
integrationDefinition: job.integrationDefinition,
})),
pageInfo: jobs.pageInfo,
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error getting integration jobs: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
});
// Tool: Create inline question rule instance
this.registerTool({
name: 'create-inline-question-rule',
description: (0, load_description_js_1.loadDescription)('create-inline-question-rule.md'),
schema: {
name: zod_1.z.string().describe('Name of the rule'),
description: zod_1.z.string().describe('Description of the rule'),
notifyOnFailure: zod_1.z.boolean().optional().describe('Whether to notify on failure'),
triggerActionsOnNewEntitiesOnly: zod_1.z
.boolean()
.optional()
.describe('Whether to trigger actions only on new entities'),
ignorePreviousResults: zod_1.z
.boolean()
.optional()
.describe('Whether to ignore previous results'),
pollingInterval: zod_1.z
.enum([
'DISABLED',
'THIRTY_MINUTES',
'ONE_HOUR',
'FOUR_HOURS',
'EIGHT_HOURS',
'TWELVE_HOURS',
'ONE_DAY',
'ONE_WEEK',
])
.describe('How frequently to evaluate the rule'),
outputs: zod_1.z.array(zod_1.z.string()).describe('Output fields from the rule evaluation'),
specVersion: zod_1.z.number().optional().describe('Specification version'),
tags: zod_1.z.array(zod_1.z.string()).optional().describe('Tags for categorizing the rule'),
templates: zod_1.z.record(zod_1.z.any()).optional().describe('Template variables'),
question: zod_1.z
.object({
queries: zod_1.z.array(zod_1.z.object({
query: zod_1.z.string().describe('J1QL query string'),
name: zod_1.z.string().describe('Name identifier for the query'),
version: zod_1.z.string().optional().describe('Version of the query'),
includeDeleted: zod_1.z.boolean().describe('Whether to include deleted entities'),
})),
})
.describe('Question configuration'),
labels: zod_1.z
.array(zod_1.z.object({
labelName: zod_1.z.string(),
labelValue: zod_1.z.string().nullable(),
}))
.describe('Labels for the rule'),
operations: zod_1.z
.array(zod_1.z.object({
when: zod_1.z
.object({
type: zod_1.z.literal('FILTER'),
condition: zod_1.z
.array(zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.array(zod_1.z.union([zod_1.z.string(), zod_1.z.number()]))]))
.describe('Filter condition array (e.g., ["AND", ["queries.query0.total", ">", 0]])'),
})
.describe('Condition that triggers the actions'),
actions: zod_1.z
.array(zod_1.z.object({
id: zod_1.z.string().optional(),
type: zod_1.z
.string()
.describe('Action type (e.g., SET_PROPERTY, CREATE_ALERT, SEND_EMAIL)'),
targetProperty: zod_1.z
.string()
.optional()
.describe('Property to set (for SET_PROPERTY actions)'),
targetValue: zod_1.z
.any()
.optional()
.describe('Value to set (for SET_PROPERTY actions)'),
integrationInstanceId: zod_1.z
.string()
.optional()
.describe('ID of the integration instance for integration actions'),
recipients: zod_1.z
.array(zod_1.z.string())
.optional()
.describe('Email recipients for SEND_EMAIL action'),
body: zod_1.z.string().optional().describe('Message body for email/slack actions'),
channels: zod_1.z
.array(zod_1.z.string())
.optional()
.describe('Slack channels for SEND_SLACK_MESSAGE action'),
bucket: zod_1.z.string().optional().describe('S3 bucket name for SEND_TO_S3 action'),
region: zod_1.z.string().optional().describe('AWS region for SEND_TO_S3 action'),
data: zod_1.z.any().optional().describe('Additional data for actions'),
entityClass: zod_1.z
.string()
.optional()
.describe('Entity class for CREATE_JIRA_TICKET action'),
summary: zod_1.z
.string()
.optional()
.describe('Summary for CREATE_JIRA_TICKET action'),
issueType: zod_1.z
.string()
.optional()
.describe('Issue type for CREATE_JIRA_TICKET action'),
project: zod_1.z
.string()
.optional()
.describe('Project key for CREATE_JIRA_TICKET action'),
updateContentOnChanges: zod_1.z
.boolean()
.optional()
.describe('Whether to update content on changes for CREATE_JIRA_TICKET action'),
additionalFields: zod_1.z
.any()
.optional()
.describe('Additional fields for CREATE_JIRA_TICKET action'),
}))
.describe('Actions to take when condition is met'),
}))
.describe('Operations to perform when conditions are met'),
},
handler: async ({ name, description, notifyOnFailure, triggerActionsOnNewEntitiesOnly, ignorePreviousResults, pollingInterval, outputs, specVersion, labels, tags, templates, question, operations, }, client, validator) => {
try {
// Validate all queries before creating the rule
const validationResults = await this.validateQueries(question.queries, validator);
if (validationResults.length > 0) {
return this.createValidationErrorResponse(validationResults);
}
const instance = {
name,
description,
notifyOnFailure,
triggerActionsOnNewEntitiesOnly,
ignorePreviousResults,
pollingInterval,
outputs,
specVersion,
labels,
tags,
templates,
question,
operations,
};
const result = await client.createInlineQuestionRuleInstance(instance);
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: true,
rule: {
id: result.id,
name: result.name,
description: result.description,
version: result.version,
pollingInterval: result.pollingInterval,
outputs: result.outputs,
specVersion: result.specVersion,
notifyOnFailure: result.notifyOnFailure,
triggerActionsOnNewEntitiesOnly: result.triggerActionsOnNewEntitiesOnly,
ignorePreviousResults: result.ignorePreviousResults,
tags: result.tags,
question: result.question,
operations: result.operations,
latestAlertId: result.latestAlertId,
latestAlertIsActive: result.latestAlertIsActive,
},
}, null, 2),
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error creating inline question rule: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
});
// Tool: Update inline question rule instance
this.registerTool({
name: 'update-inline-question-rule',
description: (0, load_description_js_1.loadDescription)('update-inline-question-rule.md'),
schema: {
id: zod_1.z.string().describe('ID of the rule to update'),
name: zod_1.z.string().describe('Name of the rule'),
description: zod_1.z.string().describe('Description of the rule'),
notifyOnFailure: zod_1.z.boolean().describe('Whether to notify on failure'),
triggerActionsOnNewEntitiesOnly: zod_1.z
.boolean()
.describe('Whether to trigger actions only on new entities'),
ignorePreviousResults: zod_1.z.boolean().describe('Whether to ignore previous results'),
pollingInterval: zod_1.z
.enum([
'DISABLED',
'THIRTY_MINUTES',
'ONE_HOUR',
'FOUR_HOURS',
'EIGHT_HOURS',
'TWELVE_HOURS',
'ONE_DAY',
'ONE_WEEK',
])
.describe('How frequently to evaluate the rule'),
outputs: zod_1.z.array(zod_1.z.string()).describe('Output fields from the rule evaluation'),
specVersion: zod_1.z.number().describe('Specification version'),
tags: zod_1.z.array(zod_1.z.string()).describe('Tags for categorizing the rule'),
templates: zod_1.z.record(zod_1.z.any()).describe('Template variables'),
labels: zod_1.z
.array(zod_1.z.object({
labelName: zod_1.z.string(),
labelValue: zod_1.z.string().nullable(),
}))
.describe('Labels for the rule'),
resourceGroupId: zod_1.z.string().nullable().describe('Resource group ID'),
remediationSteps: zod_1.z
.string()
.nullable()
.describe('Steps to remediate issues found by the rule'),
question: zod_1.z
.object({
queries: zod_1.z.array(zod_1.z.object({
query: zod_1.z.string().describe('J1QL query string'),
name: zod_1.z.string().describe('Name identifier for the query'),
version: zod_1.z.string().optional().de