mcp-servicenow
Version:
ServiceNow MCP server for Claude AI integration
315 lines (314 loc) • 12.3 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.incidentTools = exports.GetIncidentsTool = exports.CreateIncidentTool = void 0;
exports.createIncident = createIncident;
exports.getIncidents = getIncidents;
const axios_1 = __importDefault(require("axios"));
const logger_1 = require("../utils/logger");
// Tool definition for creating an incident
exports.CreateIncidentTool = {
name: 'create_incident',
description: 'Create a new incident in ServiceNow',
inputSchema: {
type: 'object',
properties: {
short_description: {
type: 'string',
description: 'Short description of the incident'
},
description: {
type: 'string',
description: 'Detailed description of the incident'
},
urgency: {
type: 'string',
enum: ['1', '2', '3'],
description: 'Urgency of the incident (1=high, 2=medium, 3=low)'
},
impact: {
type: 'string',
enum: ['1', '2', '3'],
description: 'Impact of the incident (1=high, 2=medium, 3=low)'
},
priority: {
type: 'string',
enum: ['1', '2', '3', '4', '5'],
description: 'Priority of the incident (1=critical, 5=planning)'
},
state: {
type: 'string',
enum: ['New', 'In Progress', 'Resolved', 'On Hold', 'Closed', 'Cancelled'],
description: 'State of the incident'
}
},
required: ['short_description']
}
};
// Logic for creating an incident
async function createIncident(params = {}) {
try {
(0, logger_1.log)(`createIncident called with params: ${JSON.stringify(params)}`);
// Extract parameters
const short_description = params.short_description;
const description = params.description || '';
const urgency = params.urgency;
const impact = params.impact;
const priority = params.priority;
const state = params.state;
// Validate required field
if (!short_description) {
return {
content: [{
type: 'text',
text: 'Error: short_description parameter is required'
}]
};
}
const instanceUrl = process.env.SERVICENOW_INSTANCE_URL;
const username = process.env.SERVICENOW_USERNAME;
const password = process.env.SERVICENOW_PASSWORD;
const senderEmail = process.env.SERVICENOW_DEFAULT_SENDER_EMAIL;
if (!instanceUrl || !username || !password) {
return {
content: [{
type: 'text',
text: 'Error: Missing ServiceNow credentials. Please check environment variables.'
}]
};
}
(0, logger_1.log)(`Creating incident: ${short_description}`);
// Build the incident payload - only include fields that have values
const incidentPayload = {
short_description,
description,
caller_email: senderEmail
};
// Only add optional fields if they have values
if (urgency)
incidentPayload.urgency = urgency;
if (impact)
incidentPayload.impact = impact;
if (priority)
incidentPayload.priority = priority;
if (state)
incidentPayload.state = state;
(0, logger_1.log)(`Incident payload: ${JSON.stringify(incidentPayload)}`);
const response = await axios_1.default.post(`${instanceUrl}/api/now/table/incident`, incidentPayload, {
auth: { username, password },
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }
});
const incident = response.data.result;
(0, logger_1.log)(`Incident created successfully: ${incident.number}`);
return {
content: [{
type: 'text',
text: `Incident created successfully:
- Number: ${incident.number}
- System ID: ${incident.sys_id}
- Created: ${incident.sys_created_on}
- Short Description: ${incident.short_description}
- State: ${incident.state || 'New'}
- Priority: ${incident.priority || 'Not Set'}
- Urgency: ${incident.urgency || 'Not Set'}
- Impact: ${incident.impact || 'Not Set'}`
}]
};
}
catch (error) {
(0, logger_1.log)(`Error creating incident: ${error.message}`);
if (error.response) {
(0, logger_1.log)(`Error response status: ${error.response.status}`);
(0, logger_1.log)(`Error response data: ${JSON.stringify(error.response.data)}`);
}
let errorMessage = `Error creating incident: ${error.message}`;
if (error.response?.status === 401) {
errorMessage += '\nAuthentication error. Please verify ServiceNow credentials.';
}
else if (error.response?.status === 403) {
errorMessage += '\nPermission error. Please verify ServiceNow user roles.';
}
else if (error.response?.status === 400) {
errorMessage += '\nBad request. Please check the field values and formats.';
if (error.response.data?.error?.message) {
errorMessage += `\nServiceNow error: ${error.response.data.error.message}`;
}
}
return {
content: [{
type: 'text',
text: errorMessage
}]
};
}
}
// Tool definition for getting incidents
exports.GetIncidentsTool = {
name: 'get_incidents',
description: 'Get incidents from ServiceNow based on specified criteria',
inputSchema: {
type: 'object',
properties: {
assignment_group: {
type: 'string',
description: 'Name of the assignment group'
},
active: {
type: 'boolean',
description: 'Filter by active status'
},
description: {
type: 'string',
description: 'Keyword to search for in the description'
},
number: {
type: 'string',
description: 'Incident number to search for'
},
urgency: {
type: 'string',
description: 'Filter by urgency level (1=high, 2=medium, 3=low)'
},
priority: {
type: 'string',
description: 'Filter by priority level (1=critical, 5=planning)'
},
state: {
type: 'string',
description: 'State of the incident ("New", "In Progress", "Resolved", "On Hold", "Closed", "Cancelled")'
},
limit: {
type: 'number',
description: 'Maximum number of incidents to return (default: 50)'
}
}
}
};
// Logic for getting incidents
async function getIncidents(params = {}) {
try {
(0, logger_1.log)(`getIncidents called with params: ${JSON.stringify(params)}`);
const instanceUrl = process.env.SERVICENOW_INSTANCE_URL;
const username = process.env.SERVICENOW_USERNAME;
const password = process.env.SERVICENOW_PASSWORD;
if (!instanceUrl || !username || !password) {
return {
content: [{
type: 'text',
text: 'Error: Missing ServiceNow credentials. Please check environment variables.'
}]
};
}
// Build the query string dynamically
const queryParts = [];
if (params.number) {
queryParts.push(`number=${params.number}`);
}
if (params.assignment_group) {
queryParts.push(`assignment_group.name=${params.assignment_group}`);
}
if (typeof params.active === 'boolean') {
queryParts.push(`active=${params.active}`);
}
if (params.description) {
queryParts.push(`descriptionCONTAINS${params.description}`);
}
if (params.urgency) {
queryParts.push(`urgency=${params.urgency}`);
}
if (params.priority) {
queryParts.push(`priority=${params.priority}`);
}
if (params.state) {
queryParts.push(`state=${params.state}`);
}
const query = queryParts.join('^');
// Build request params
const requestParams = {
sysparm_fields: 'number,sys_id,short_description,description,state,priority,urgency,assignment_group.display_value,caller_id.display_value,sys_created_on,active',
sysparm_limit: params.limit || 50,
sysparm_order_by: '-sys_created_on'
};
if (query) {
requestParams.sysparm_query = query;
}
(0, logger_1.log)(`Querying incidents with: ${JSON.stringify(requestParams)}`);
const response = await axios_1.default.get(`${instanceUrl}/api/now/table/incident`, {
params: requestParams,
auth: { username, password },
headers: { 'Accept': 'application/json' }
});
(0, logger_1.log)(`ServiceNow response status: ${response.status}`);
const incidents = response.data.result;
if (!incidents) {
return {
content: [{
type: 'text',
text: 'Error: Invalid response from ServiceNow.'
}]
};
}
(0, logger_1.log)(`Found ${incidents.length} incidents`);
if (incidents.length === 0) {
return {
content: [{
type: 'text',
text: 'No incidents found matching the specified criteria.'
}]
};
}
// Format incidents for display
const formattedIncidents = incidents.map((incident) => {
return `• **${incident.number}** - ${incident.short_description}
State: ${incident.state || 'Unknown'}
Priority: ${incident.priority || 'Not Set'}
Urgency: ${incident.urgency || 'Not Set'}
Assignment Group: ${incident.assignment_group?.display_value || 'Unassigned'}
Caller: ${incident.caller_id?.display_value || 'Unknown'}
Created: ${incident.sys_created_on}
Active: ${incident.active || 'Unknown'}`;
}).join('\n\n');
return {
content: [{
type: 'text',
text: `Found ${incidents.length} incident(s):\n\n${formattedIncidents}`
}]
};
}
catch (error) {
(0, logger_1.log)(`Error getting incidents: ${error.message}`);
if (error.response) {
(0, logger_1.log)(`Error response status: ${error.response.status}`);
(0, logger_1.log)(`Error response data: ${JSON.stringify(error.response.data)}`);
}
let errorMessage = `Error retrieving incidents: ${error.message}`;
if (error.response?.status === 401) {
errorMessage += '\nAuthentication error. Please verify ServiceNow credentials.';
}
else if (error.response?.status === 403) {
errorMessage += '\nPermission error. Please verify ServiceNow user roles.';
}
else if (error.response?.status === 400) {
errorMessage += '\nBad request. Please check the query parameters.';
}
return {
content: [{
type: 'text',
text: errorMessage
}]
};
}
}
// Collection of all incident-related tools
exports.incidentTools = {
[exports.CreateIncidentTool.name]: {
definition: exports.CreateIncidentTool,
execute: createIncident
},
[exports.GetIncidentsTool.name]: {
definition: exports.GetIncidentsTool,
execute: getIncidents
}
};