Skip to main content
Glama

send_notification

Send notifications to Discord or Slack via webhooks, including messages, embeds, and attachments, with automatic service detection, retry logic, and secure input validation.

Instructions

Send a notification to Discord and/or Slack webhooks

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
avatar_urlNo
embed_jsonNo
messageNo
serviceNo
ttsNo
usernameNo

Implementation Reference

  • Full implementation of the send_notification tool handler, including inline schema validation, service detection, payload construction, API calls to Discord/Slack, error handling, and result aggregation.
    server.tool( "send_notification", "Send a notification to Discord and/or Slack webhooks", { message: z.string().optional(), service: z.enum(["discord", "slack", "both"]).optional(), embed_json: z.union([z.string(), z.object({}).passthrough(), z.array(z.unknown())]).optional(), username: z.string().optional(), avatar_url: z.string().url().optional(), tts: z.boolean().optional(), }, async (args) => { // Validate that either message or embed_json is provided if (!args.message && args.embed_json === undefined) { return { content: [ { type: "text", text: JSON.stringify({ error: "You must provide either message or embed_json parameter" }, null, 2) } ] }; } try { const targetServices = detectService(args.service); const config = getConfig(); const results: ServiceResult[] = []; for (const service of targetServices) { try { let result; if (service === "discord") { const payload = buildDiscordPayload({ message: args.message, embedJson: args.embed_json, username: args.username, avatarUrl: args.avatar_url, tts: args.tts }); result = await sendDiscord(config.discordWebhookUrl!, payload); } else { const payload = buildSlackPayload({ message: args.message, embedJson: args.embed_json, username: args.username, avatarUrl: args.avatar_url }); result = await sendSlack(config.slackWebhookUrl!, payload); } results.push({ service, success: result.success, httpCode: result.httpCode, timestamp: result.timestamp }); } catch (error) { results.push({ service, success: false, error: error instanceof Error ? error.message : "Unknown error" }); } } const overall = results.some(r => r.success); const response: SendResult = { success: overall, overall, results }; return { content: [ { type: "text", text: JSON.stringify(response, null, 2) } ] }; } catch (error) { const errorMsg = error instanceof Error ? error.message : "Unknown error"; return { content: [ { type: "text", text: JSON.stringify({ error: errorMsg }, null, 2) } ] }; } } );
  • Zod input schema for the send_notification tool parameters.
    export const SendNotificationSchema = z.object({ message: z.string().optional(), service: ServiceSchema.optional(), embed_json: z.union([z.string(), z.object({}).passthrough(), z.array(z.unknown())]).optional(), username: z.string().optional(), avatar_url: z.string().url().optional(), tts: z.boolean().optional(), });
  • Helper function to send notifications to Discord webhook with retry logic.
    export async function sendDiscord( webhookUrl: string, payload: object, maxRetries = 2 ): Promise<HttpResult> { logger.debug("Sending Discord notification"); const result = await postJsonWithRetries(webhookUrl, payload, "discord", maxRetries); logger.serviceResult("discord", result.success, result.httpCode); if (!result.success && result.httpCode > 0) { logger.apiError("discord", result.httpCode, maxRetries + 1); } return result; }
  • Helper function to send notifications to Slack webhook with retry logic.
    export async function sendSlack( webhookUrl: string, payload: object, maxRetries = 2 ): Promise<HttpResult> { logger.debug("Sending Slack notification"); const result = await postJsonWithRetries(webhookUrl, payload, "slack", maxRetries); logger.serviceResult("slack", result.success, result.httpCode); if (!result.success && result.httpCode > 0) { logger.apiError("slack", result.httpCode, maxRetries + 1); } return result; }
  • Core HTTP POST helper with retries, rate limiting handling, and error management used by both sendDiscord and sendSlack.
    async function postJsonWithRetries( url: string, payload: object, service: "discord" | "slack", maxRetries = 2 ): Promise<HttpResult> { let attempt = 0; while (true) { attempt++; try { const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(payload), }); // Success cases if (response.status === 200 || response.status === 204) { return { success: true, httpCode: response.status, timestamp: new Date().toISOString(), }; } // Rate limiting (429) - retry with delay if (response.status === 429 && attempt <= maxRetries) { const retryAfterHeader = response.headers.get("retry-after"); const retryAfter = retryAfterHeader ? Number(retryAfterHeader) : 1; const delayMs = retryAfter * 1000; logger.retryAttempt(service, attempt, maxRetries, delayMs); await sleep(delayMs); continue; } // Other error - read body safely for context const errorBody = await safeReadBody(response); return { success: false, httpCode: response.status, timestamp: new Date().toISOString(), }; } catch (error) { if (attempt <= maxRetries) { logger.retryAttempt(service, attempt, maxRetries, 1000); await sleep(1000); continue; } return { success: false, httpCode: 0, // Network error timestamp: new Date().toISOString(), }; } } }

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/thesammykins/notifyme_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server