Skip to main content
Glama
messages.ts8.44 kB
import { z } from "zod"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { getSDK } from "../utils/sdk.js"; import { logger } from "../utils/logger.js"; export function registerMessageTools(server: McpServer) { // Get messages with filtering server.tool( "get-messages", "Get messages with optional filtering by sender, date, service, etc.", { sender: z.string().optional().describe("Filter by sender phone/email"), limit: z.number().min(1).max(100).default(50).describe("Max messages to return"), since: z.string().optional().describe("Get messages after this ISO date"), unreadOnly: z.boolean().default(false).describe("Only get unread messages"), hasAttachments: z.boolean().optional().describe("Only messages with attachments"), service: z.enum(["iMessage", "SMS", "RCS"]).optional().describe("Filter by service"), chatId: z.string().optional().describe("Filter by chat ID"), includeOwn: z.boolean().default(false).describe("Include your own messages"), }, async ({ sender, limit, since, unreadOnly, hasAttachments, service, chatId, includeOwn }) => { try { logger.tool("get-messages", "Fetching messages with filters"); const sdk = getSDK(); const result = await sdk.getMessages({ sender, limit, since: since ? new Date(since) : undefined, unreadOnly, hasAttachments, service, chatId, excludeOwnMessages: !includeOwn, }); if (result.messages.length === 0) { return { content: [{ type: "text", text: "No messages found matching criteria" }] }; } const formatted = result.messages.map((msg) => { const date = new Date(msg.date).toLocaleString(); const sender = msg.isFromMe ? "Me" : msg.senderName || msg.sender; const read = msg.isRead ? "" : " [UNREAD]"; const attachments = msg.attachments.length > 0 ? ` [${msg.attachments.length} attachment(s)]` : ""; return `[${date}] ${sender} (${msg.service})${read}: ${msg.text || "[No text]"}${attachments}`; }).join("\n"); return { content: [{ type: "text", text: `Found ${result.total} messages (${result.unreadCount} unread):\n\n${formatted}`, }], }; } catch (error: any) { logger.error("get-messages failed: %s", error.message); return { content: [{ type: "text", text: `Error: ${error.message}` }] }; } } ); // Get unread messages grouped by sender server.tool( "get-unread-messages", "Get all unread messages grouped by sender", {}, async () => { try { logger.tool("get-unread-messages", "Fetching unread messages"); const sdk = getSDK(); const result = await sdk.getUnreadMessages(); if (result.total === 0) { return { content: [{ type: "text", text: "No unread messages" }] }; } const formatted = result.groups.map(({ sender, messages }) => { const msgList = messages.map((m) => { const time = new Date(m.date).toLocaleTimeString(); return ` [${time}] ${m.text || "[No text]"}`; }).join("\n"); return `${sender} (${messages.length} unread):\n${msgList}`; }).join("\n\n"); return { content: [{ type: "text", text: `${result.total} unread messages from ${result.senderCount} sender(s):\n\n${formatted}`, }], }; } catch (error: any) { logger.error("get-unread-messages failed: %s", error.message); return { content: [{ type: "text", text: `Error: ${error.message}` }] }; } } ); // Search messages server.tool( "search-messages", "Search for messages containing specific text", { query: z.string().min(1).describe("Text to search for"), sender: z.string().optional().describe("Filter by sender"), limit: z.number().min(1).max(100).default(20).describe("Max results"), }, async ({ query, sender, limit }) => { try { logger.tool("search-messages", "Searching for: %s", query); const sdk = getSDK(); // Get messages and filter by text content const result = await sdk.getMessages({ sender, limit: 500, // Get more to search through excludeOwnMessages: false, }); const matches = result.messages .filter((m) => m.text?.toLowerCase().includes(query.toLowerCase())) .slice(0, limit); if (matches.length === 0) { return { content: [{ type: "text", text: `No messages found containing "${query}"` }] }; } const formatted = matches.map((msg) => { const date = new Date(msg.date).toLocaleString(); const sender = msg.isFromMe ? "Me" : msg.senderName || msg.sender; return `[${date}] ${sender}: ${msg.text}`; }).join("\n"); return { content: [{ type: "text", text: `Found ${matches.length} messages containing "${query}":\n\n${formatted}`, }], }; } catch (error: any) { logger.error("search-messages failed: %s", error.message); return { content: [{ type: "text", text: `Error: ${error.message}` }] }; } } ); // Send text message server.tool( "send-message", "Send a text message to a phone number or email", { to: z.string().describe("Recipient phone number (e.g., +1234567890) or email"), message: z.string().min(1).describe("Message text to send"), }, async ({ to, message }) => { try { logger.tool("send-message", "Sending to %s", to); const sdk = getSDK(); const result = await sdk.send(to, message); logger.success("Message sent to %s", to); return { content: [{ type: "text", text: `Message sent successfully!\nTo: ${to}\nSent at: ${result.sentAt.toLocaleString()}`, }], }; } catch (error: any) { logger.error("send-message failed: %s", error.message); return { content: [{ type: "text", text: `Error sending message: ${error.message}` }] }; } } ); // Send file server.tool( "send-file", "Send a file attachment to a recipient", { to: z.string().describe("Recipient phone number or email"), filePath: z.string().describe("Path to the file to send"), message: z.string().optional().describe("Optional text message with the file"), }, async ({ to, filePath, message }) => { try { logger.tool("send-file", "Sending file to %s", to); const sdk = getSDK(); const result = await sdk.sendFile(to, filePath, message); logger.success("File sent to %s", to); return { content: [{ type: "text", text: `File sent successfully!\nTo: ${to}\nFile: ${filePath}\nSent at: ${result.sentAt.toLocaleString()}`, }], }; } catch (error: any) { logger.error("send-file failed: %s", error.message); return { content: [{ type: "text", text: `Error sending file: ${error.message}` }] }; } } ); // Send image server.tool( "send-image", "Send an image to a recipient", { to: z.string().describe("Recipient phone number or email"), imagePath: z.string().describe("Path to the image file or URL"), message: z.string().optional().describe("Optional text message with the image"), }, async ({ to, imagePath, message }) => { try { logger.tool("send-image", "Sending image to %s", to); const sdk = getSDK(); const content: { text?: string; images: string[] } = { images: [imagePath] }; if (message) content.text = message; const result = await sdk.send(to, content); logger.success("Image sent to %s", to); return { content: [{ type: "text", text: `Image sent successfully!\nTo: ${to}\nSent at: ${result.sentAt.toLocaleString()}`, }], }; } catch (error: any) { logger.error("send-image failed: %s", error.message); return { content: [{ type: "text", text: `Error sending image: ${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/sameelarif/imessage-mcp'

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