Skip to main content
Glama

WhatsApp Web MCP

by pnizer
api.ts22.3 kB
import express, { Request, Response, Router } from 'express'; import { Client } from 'whatsapp-web.js'; import { WhatsAppService } from './whatsapp-service'; import logger from './logger'; export function routerFactory(client: Client): Router { // Create a router instance const router: Router = express.Router(); const whatsappService = new WhatsAppService(client); // Get the media storage path from the client configuration const mediaStoragePath = (client as { options?: { mediaStoragePath?: string } }).options?.mediaStoragePath || '.wwebjs_auth/media'; /** * @swagger * /api/status: * get: * summary: Get WhatsApp client connection status * responses: * 200: * description: Returns the connection status of the WhatsApp client */ router.get('/status', async (_req: Request, res: Response) => { try { const status = await whatsappService.getStatus(); res.json(status); } catch (error) { res.status(500).json({ error: 'Failed to get client status', details: error instanceof Error ? error.message : String(error), }); } }); /** * @swagger * /api/contacts: * get: * summary: Get all WhatsApp contacts * responses: * 200: * description: Returns a list of WhatsApp contacts * 500: * description: Server error */ router.get('/contacts', async (_req: Request, res: Response) => { try { const contacts = await whatsappService.getContacts(); res.json(contacts); } catch (error) { if (error instanceof Error && error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to fetch contacts', details: error instanceof Error ? error.message : String(error), }); } } }); /** * @swagger * /api/contacts/search: * get: * summary: Search for contacts by name or number * parameters: * - in: query * name: query * schema: * type: string * required: true * description: Search query to find contacts by name or number * responses: * 200: * description: Returns matching contacts * 500: * description: Server error */ router.get('/contacts/search', async (req: Request, res: Response) => { try { const query = req.query.query as string; if (!query) { res.status(400).json({ error: 'Search query is required' }); return; } const contacts = await whatsappService.searchContacts(query); res.json(contacts); } catch (error) { if (error instanceof Error && error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to search contacts', details: error instanceof Error ? error.message : String(error), }); } } }); /** * @swagger * /api/chats: * get: * summary: Get all WhatsApp chats * responses: * 200: * description: Returns a list of WhatsApp chats * 500: * description: Server error */ router.get('/chats', async (_req: Request, res: Response) => { try { const chats = await whatsappService.getChats(); res.json(chats); } catch (error) { if (error instanceof Error && error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to fetch chats', details: error instanceof Error ? error.message : String(error), }); } } }); /** * @swagger * /api/messages/{number}: * get: * summary: Get messages from a specific chat * parameters: * - in: path * name: number * schema: * type: string * required: true * description: The phone number to get messages from * - in: query * name: limit * schema: * type: integer * description: The number of messages to get (default: 10) * responses: * 200: * description: Returns messages from the specified chat * 404: * description: Number not found on WhatsApp * 500: * description: Server error */ router.get('/messages/:number', async (req: Request, res: Response) => { try { const number = req.params.number; const limit = parseInt(req.query.limit as string) || 10; const messages = await whatsappService.getMessages(number, limit); res.json(messages); } catch (error) { if (error instanceof Error) { if (error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else if (error.message.includes('not registered')) { res.status(404).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to fetch messages', details: error.message, }); } } else { res.status(500).json({ error: 'Failed to fetch messages', details: String(error), }); } } }); /** * @swagger * /api/send: * post: * summary: Send a message to a WhatsApp contact * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - number * - message * properties: * number: * type: string * description: The phone number to send the message to * message: * type: string * description: The message content to send * responses: * 200: * description: Message sent successfully * 404: * description: Number not found on WhatsApp * 500: * description: Server error */ router.post('/send', async (req: Request, res: Response) => { try { const { number, message } = req.body; if (!number || !message) { res.status(400).json({ error: 'Number and message are required' }); return; } const result = await whatsappService.sendMessage(number, message); res.json(result); } catch (error) { if (error instanceof Error) { if (error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else if (error.message.includes('not registered')) { res.status(404).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to send message', details: error.message, }); } } else { res.status(500).json({ error: 'Failed to send message', details: String(error), }); } } }); /** * @swagger * /api/groups: * get: * summary: Get all WhatsApp groups * responses: * 200: * description: Returns a list of WhatsApp groups * 500: * description: Server error */ router.get('/groups', async (_req: Request, res: Response) => { try { const groups = await whatsappService.getGroups(); res.json(groups); } catch (error) { if (error instanceof Error && error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to fetch groups', details: error instanceof Error ? error.message : String(error), }); } } }); /** * @swagger * /api/groups/search: * get: * summary: Search for groups by name, description, or member names * parameters: * - in: query * name: query * schema: * type: string * required: true * description: Search query to find groups by name, description, or member names * responses: * 200: * description: Returns matching groups * 500: * description: Server error */ router.get('/groups/search', async (req: Request, res: Response) => { try { const query = req.query.query as string; if (!query) { res.status(400).json({ error: 'Search query is required' }); return; } const groups = await whatsappService.searchGroups(query); res.json(groups); } catch (error) { if (error instanceof Error && error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to search groups', details: error instanceof Error ? error.message : String(error), }); } } }); /** * @swagger * /api/groups: * post: * summary: Create a new WhatsApp group * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - name * - participants * properties: * name: * type: string * description: The name of the group to create * participants: * type: array * items: * type: string * description: Array of phone numbers to add to the group * responses: * 200: * description: Group created successfully * 400: * description: Invalid request parameters * 500: * description: Server error */ router.post('/groups', async (req: Request, res: Response) => { try { const { name, participants } = req.body; if (!name || !participants || !Array.isArray(participants)) { res.status(400).json({ error: 'Name and array of participants are required' }); return; } const result = await whatsappService.createGroup(name, participants); res.json(result); } catch (error) { if (error instanceof Error && error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to create group', details: error instanceof Error ? error.message : String(error), }); } } }); /** * @swagger * /api/groups/{groupId}: * get: * summary: Get a specific WhatsApp group by ID * parameters: * - in: path * name: groupId * schema: * type: string * required: true * description: The ID of the group to get * responses: * 200: * description: Returns the group details * 404: * description: Group not found * 500: * description: Server error */ router.get('/groups/:groupId', async (req: Request, res: Response) => { try { const groupId = req.params.groupId; const group = await whatsappService.getGroupById(groupId); res.json(group); } catch (error) { if (error instanceof Error) { if (error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else if (error.message.includes('not found') || error.message.includes('invalid chat')) { res.status(404).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to fetch group', details: error.message, }); } } else { res.status(500).json({ error: 'Failed to fetch group', details: String(error), }); } } }); /** * @swagger * /api/groups/{groupId}/messages: * get: * summary: Get messages from a specific group * parameters: * - in: path * name: groupId * schema: * type: string * required: true * description: The ID of the group to get messages from * - in: query * name: limit * schema: * type: integer * description: The number of messages to get (default: 10) * responses: * 200: * description: Returns messages from the specified group * 404: * description: Group not found * 500: * description: Server error */ router.get('/groups/:groupId/messages', async (req: Request, res: Response) => { try { const groupId = req.params.groupId; const limit = parseInt(req.query.limit as string) || 10; const messages = await whatsappService.getGroupMessages(groupId, limit); res.json(messages); } catch (error) { if (error instanceof Error) { if (error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else if (error.message.includes('not found') || error.message.includes('invalid chat')) { res.status(404).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to fetch group messages', details: error.message, }); } } else { res.status(500).json({ error: 'Failed to fetch group messages', details: String(error), }); } } }); /** * @swagger * /api/groups/{groupId}/participants/add: * post: * summary: Add participants to a WhatsApp group * parameters: * - in: path * name: groupId * schema: * type: string * required: true * description: The ID of the group to add participants to * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - participants * properties: * participants: * type: array * items: * type: string * description: Array of phone numbers to add to the group * responses: * 200: * description: Participants added successfully * 400: * description: Invalid request parameters * 404: * description: Group not found * 500: * description: Server error */ router.post('/groups/:groupId/participants/add', async (req: Request, res: Response) => { try { const groupId = req.params.groupId; const { participants } = req.body; if (!participants || !Array.isArray(participants)) { res.status(400).json({ error: 'Array of participants is required' }); return; } const result = await whatsappService.addParticipantsToGroup(groupId, participants); res.json(result); } catch (error) { if (error instanceof Error) { if (error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else if ( error.message.includes('not found') || error.message.includes('not a group chat') ) { res.status(404).json({ error: error.message }); } else if (error.message.includes('not supported')) { res.status(501).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to add participants to group', details: error.message, }); } } else { res.status(500).json({ error: 'Failed to add participants to group', details: String(error), }); } } }); /** * @swagger * /api/groups/{groupId}/send: * post: * summary: Send a message to a WhatsApp group * parameters: * - in: path * name: groupId * schema: * type: string * required: true * description: The ID of the group to send the message to * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - message * properties: * message: * type: string * description: The message content to send * responses: * 200: * description: Message sent successfully * 404: * description: Group not found * 500: * description: Server error */ router.post('/groups/:groupId/send', async (req: Request, res: Response) => { try { const groupId = req.params.groupId; const { message } = req.body; if (!groupId || !message) { res.status(400).json({ error: 'Group ID and message are required' }); return; } const result = await whatsappService.sendGroupMessage(groupId, message); res.json(result); } catch (error) { if (error instanceof Error) { if (error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else if (error.message.includes('not found') || error.message.includes('invalid chat')) { res.status(404).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to send group message', details: error.message, }); } } else { res.status(500).json({ error: 'Failed to send group message', details: String(error), }); } } }); /** * @swagger * /api/messages/{messageId}/media/download: * post: * summary: Download media from a message * parameters: * - in: path * name: messageId * required: true * description: ID of the message containing media * schema: * type: string * responses: * 200: * description: Returns the downloaded media file information * 404: * description: Message not found or does not contain media * 500: * description: Server error */ router.post('/messages/:messageId/media/download', async (req: Request, res: Response) => { try { const { messageId } = req.params; if (!messageId) { res.status(400).json({ error: 'Message ID is required' }); return; } const mediaInfo = await whatsappService.downloadMediaFromMessage(messageId, mediaStoragePath); res.json(mediaInfo); } catch (error) { if (error instanceof Error) { if (error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else if ( error.message.includes('not found') || error.message.includes('does not contain media') ) { res.status(404).json({ error: error.message }); } else { logger.error('Failed to download media', { error }); res.status(500).json({ error: 'Failed to download media', details: error.message, }); } } else { logger.error('Failed to download media', { error }); res.status(500).json({ error: 'Failed to download media', details: String(error), }); } } }); /** * @swagger * /api/send/media: * post: * summary: Send a media message to a WhatsApp contact * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - number * - source * properties: * number: * type: string * description: The phone number to send the message to * source: * type: string * description: The source of the media - URLs must use http:// or https:// prefixes, local files must use file:// prefix (e.g., 'https://example.com/image.jpg' or 'file:///path/to/image.jpg') * caption: * type: string * description: caption for the media * responses: * 200: * description: Media message sent successfully * 400: * description: Invalid request parameters * 404: * description: Number not found on WhatsApp * 500: * description: Server error */ router.post('/send/media', async (req: Request, res: Response) => { try { const { number, source, caption = '' } = req.body; // Validate required parameters if (!number || !source) { res.status(400).json({ error: 'Number and source are required' }); return; } const result = await whatsappService.sendMediaMessage({ number, source, caption, }); res.json(result); } catch (error) { if (error instanceof Error) { if (error.message.includes('not ready')) { res.status(503).json({ error: error.message }); } else if (error.message.includes('not registered')) { res.status(404).json({ error: error.message }); } else { res.status(500).json({ error: 'Failed to send media message', details: error.message, }); } } else { res.status(500).json({ error: 'Failed to send media message', details: String(error), }); } } }); return router; }

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/pnizer/wweb-mcp'

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