UNPKG

mcp-servicenow

Version:

ServiceNow MCP server for Claude AI integration

368 lines (327 loc) 10.3 kB
import axios from 'axios'; import { SendEmailParams, GetEmailsParams } from '../models/email'; import { log } from '../utils/logger'; // Tool definition for sending email export const SendEmailTool = { name: 'send_email', description: 'Send an email through ServiceNow', inputSchema: { type: 'object', properties: { to: { type: 'string', description: 'Recipient email address (required)' }, subject: { type: 'string', description: 'Email subject line (required)' }, body: { type: 'string', description: 'Email body content (required)' }, cc: { type: 'string', description: 'CC recipients (comma-separated email addresses)' }, bcc: { type: 'string', description: 'BCC recipients (comma-separated email addresses)' }, from: { type: 'string', description: 'Sender email address (optional, uses default if not provided)' }, priority: { type: 'string', enum: ['1', '2', '3'], description: 'Email priority (1=high, 2=medium, 3=low)' }, content_type: { type: 'string', enum: ['text/plain', 'text/html'], description: 'Content type of the email body (default: text/plain)' } }, required: ['to', 'subject', 'body'] } }; // Tool definition for getting sent emails export const GetEmailsTool = { name: 'get_emails', description: 'Get sent emails from ServiceNow', inputSchema: { type: 'object', properties: { recipient: { type: 'string', description: 'Filter by recipient email address' }, sender: { type: 'string', description: 'Filter by sender email address' }, subject: { type: 'string', description: 'Filter by subject containing this text' }, created_since: { type: 'string', description: 'Filter emails created since this date (YYYY-MM-DD)' }, state: { type: 'string', description: 'Filter by email state (e.g., "sent", "ready", "error")' }, limit: { type: 'number', description: 'Maximum number of emails to return (default: 50)' } } } }; // Logic for sending email export async function sendEmail(params: any = {}): Promise<any> { try { log(`sendEmail called with params: ${JSON.stringify(params)}`); // Extract and validate required parameters const { to, subject, body, cc, bcc, from, priority, content_type } = params; // Validate required fields if (!to) { return { content: [{ type: 'text', text: 'Error: "to" parameter is required (recipient email address)' }] }; } if (!subject) { return { content: [{ type: 'text', text: 'Error: "subject" parameter is required' }] }; } if (!body) { return { content: [{ type: 'text', text: 'Error: "body" parameter is required' }] }; } // Validate email format const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(to)) { return { content: [{ type: 'text', text: 'Error: "to" parameter must be a valid email address' }] }; } const instanceUrl = process.env.SERVICENOW_INSTANCE_URL; const username = process.env.SERVICENOW_USERNAME; const password = process.env.SERVICENOW_PASSWORD; const defaultSender = process.env.SERVICENOW_DEFAULT_SENDER_EMAIL; if (!instanceUrl || !username || !password) { return { content: [{ type: 'text', text: 'Error: Missing ServiceNow credentials. Please check environment variables.' }] }; } log(`Sending email to: ${to}, subject: ${subject}`); // Build the email payload const emailPayload: any = { recipient: to, subject: subject, body: body, type: 'send-ready' // This tells ServiceNow to send the email }; // Optional fields if (cc) emailPayload.cc = cc; if (bcc) emailPayload.bcc = bcc; if (from) { emailPayload.sender = from; } else if (defaultSender) { emailPayload.sender = defaultSender; } if (priority) emailPayload.priority = priority; if (content_type) emailPayload.content_type = content_type; log(`Email payload: ${JSON.stringify(emailPayload)}`); const response = await axios.post( `${instanceUrl}/api/now/table/sys_email`, emailPayload, { auth: { username, password }, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } } ); const email = response.data.result; log(`Email created successfully: ${email.sys_id}`); return { content: [{ type: 'text', text: `Email sent successfully: - Email ID: ${email.sys_id} - To: ${email.recipient} - Subject: ${email.subject} - From: ${email.sender || 'System Default'} - Created: ${email.sys_created_on} - State: ${email.state || 'Queued for sending'} - Priority: ${email.priority || 'Normal'}` }] }; } catch (error: any) { log(`Error sending email: ${error.message}`); if (error.response) { log(`Error response status: ${error.response.status}`); log(`Error response data: ${JSON.stringify(error.response.data)}`); } let errorMessage = `Error sending email: ${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 has email sending permissions.'; } else if (error.response?.status === 400) { errorMessage += '\nBad request. Please check email parameters and formats.'; if (error.response.data?.error?.message) { errorMessage += `\nServiceNow error: ${error.response.data.error.message}`; } } return { content: [{ type: 'text', text: errorMessage }] }; } } // Logic for getting sent emails export async function getEmails(params: any = {}): Promise<any> { try { log(`getEmails 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 query parameters const queryParts: string[] = []; if (params.recipient) { queryParts.push(`recipient=${params.recipient}`); } if (params.sender) { queryParts.push(`sender=${params.sender}`); } if (params.subject) { queryParts.push(`subjectCONTAINS${params.subject}`); } if (params.created_since) { queryParts.push(`sys_created_on>=${params.created_since}`); } if (params.state) { queryParts.push(`state=${params.state}`); } const query = queryParts.join('^'); // Build request parameters const requestParams: any = { sysparm_fields: 'sys_id,recipient,sender,subject,body,state,sys_created_on,sent_on,type,priority', sysparm_limit: params.limit || 50, sysparm_order_by: '-sys_created_on' }; if (query) { requestParams.sysparm_query = query; } log(`Querying emails with: ${JSON.stringify(requestParams)}`); const response = await axios.get( `${instanceUrl}/api/now/table/sys_email`, { params: requestParams, auth: { username, password }, headers: { 'Accept': 'application/json' } } ); log(`ServiceNow response status: ${response.status}`); const emails = response.data.result; if (!emails) { return { content: [{ type: 'text', text: 'Error: Invalid response from ServiceNow.' }] }; } log(`Found ${emails.length} emails`); if (emails.length === 0) { return { content: [{ type: 'text', text: 'No emails found matching the specified criteria.' }] }; } // Format emails for display const formattedEmails = emails.map((email: any) => { const bodyPreview = email.body ? (email.body.length > 100 ? email.body.substring(0, 100) + '...' : email.body) : 'No body'; return `• **Email ID:** ${email.sys_id} **To:** ${email.recipient} **From:** ${email.sender || 'System'} **Subject:** ${email.subject} **State:** ${email.state || 'Unknown'} **Priority:** ${email.priority || 'Normal'} **Created:** ${email.sys_created_on} **Sent:** ${email.sent_on || 'Not sent yet'} **Body Preview:** ${bodyPreview}`; }).join('\n\n'); return { content: [{ type: 'text', text: `Found ${emails.length} email(s):\n\n${formattedEmails}` }] }; } catch (error: any) { log(`Error getting emails: ${error.message}`); if (error.response) { log(`Error response status: ${error.response.status}`); log(`Error response data: ${JSON.stringify(error.response.data)}`); } let errorMessage = `Error retrieving emails: ${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 for email access.'; } return { content: [{ type: 'text', text: errorMessage }] }; } } // Collection of all email-related tools export const emailTools = { [SendEmailTool.name]: { definition: SendEmailTool, execute: sendEmail }, [GetEmailsTool.name]: { definition: GetEmailsTool, execute: getEmails } };