Skip to main content
Glama

WaPulse WhatsApp MCP Server

by Quegenx
sendAudio.ts•5.37 kB
import { z } from 'zod'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js'; import { makeApiRequest, validatePhoneNumber, formatPhoneNumber } from '../../utils/helpers.js'; export const sendAudioTool: Tool = { name: 'send_whatsapp_audio', description: 'Send audio messages (voice notes, music, etc.) to a specific phone number or group using WaPulse API', annotations: { title: 'Send WhatsApp Audio', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true }, inputSchema: { type: 'object', properties: { to: { type: 'string', description: 'Phone number (with country code, no + or spaces)', pattern: '^\\d{1,4}\\d{6,15}$', minLength: 6, maxLength: 20 }, audio: { type: 'object', description: 'Audio file to send', properties: { file: { type: 'string', description: "Base64 encoded audio data with data URI prefix (e.g., 'data:audio/mpeg;base64,/9j/4AAQ...')" }, filename: { type: 'string', description: 'Name of the audio file including extension (e.g., voice_note.mp3, song.wav)' }, caption: { type: 'string', description: 'Optional caption for the audio message' }, isVoiceNote: { type: 'boolean', description: 'Whether this should be sent as a voice note (true) or regular audio file (false)', default: false } }, required: ['file', 'filename'], additionalProperties: false }, customToken: { type: 'string', description: 'Override default token for this request' }, customInstanceID: { type: 'string', description: 'Override default instance ID for this request' } }, required: ['to', 'audio'], additionalProperties: false } }; export async function handleSendAudio(args: any, context?: any) { const schema = z.object({ to: z.string().regex(/^\d{1,4}\d{6,15}$/, 'Invalid phone number format'), audio: z.object({ file: z.string(), filename: z.string(), caption: z.string().optional(), isVoiceNote: z.boolean().default(false) }), customToken: z.string().optional(), customInstanceID: z.string().optional() }); const { to, audio, customToken, customInstanceID } = schema.parse(args); // Validate phone number format const isValid = validatePhoneNumber(to); if (!isValid) { throw new McpError(ErrorCode.InvalidParams, `Invalid phone number format: ${to}. Use format: country code + number (e.g., 972512345678) - no + sign, no spaces`); } // Validate audio file format if (!audio.file.startsWith('data:audio/')) { throw new McpError(ErrorCode.InvalidParams, `Invalid audio format for "${audio.filename}". File must be base64 encoded audio with data URI prefix (e.g., 'data:audio/mpeg;base64,...')`); } // Validate audio file extensions const audioExtensions = ['.mp3', '.wav', '.ogg', '.m4a', '.aac', '.opus', '.flac']; const hasValidExtension = audioExtensions.some(ext => audio.filename.toLowerCase().endsWith(ext) ); if (!hasValidExtension) { throw new McpError(ErrorCode.InvalidParams, `Invalid audio file extension for "${audio.filename}". Supported formats: ${audioExtensions.join(', ')}`); } const { log, reportProgress } = context || {}; try { if (log) { log.info("Sending WhatsApp audio", { to: formatPhoneNumber(to), filename: audio.filename, isVoiceNote: audio.isVoiceNote, hasCaption: !!audio.caption }); } // Report initial progress if (reportProgress) { await reportProgress({ progress: 0, total: 1 }); } // Prepare the request payload const payload = { to, files: [{ file: audio.file, filename: audio.filename, caption: audio.caption, type: audio.isVoiceNote ? 'voice' : 'audio' }] }; const response = await makeApiRequest('/api/sendFiles', payload, customToken, customInstanceID); // Report completion if (reportProgress) { await reportProgress({ progress: 1, total: 1 }); } const formattedPhone = formatPhoneNumber(to); const audioType = audio.isVoiceNote ? 'šŸŽ¤ Voice Note' : 'šŸŽµ Audio File'; const captionText = audio.caption ? `\nšŸ’¬ Caption: ${audio.caption}` : ''; if (log) { log.info("Audio sent successfully", { to: formattedPhone, filename: audio.filename, type: audio.isVoiceNote ? 'voice' : 'audio' }); } return { content: [{ type: 'text', text: `āœ… Audio sent successfully to ${formattedPhone}!\n\nšŸ“± Recipient: ${formattedPhone}\n${audioType}: ${audio.filename}${captionText}\nšŸ“Š Response: ${JSON.stringify(response, null, 2)}` }] }; } catch (error: any) { if (log) { log.error("Failed to send audio", { error: error.message, to, filename: audio.filename }); } throw new McpError(ErrorCode.InternalError, `Failed to send audio to ${formatPhoneNumber(to)}: ${error.message}`); } }

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/Quegenx/wapulse-mcp'

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