Skip to main content
Glama
anipotts

imessage-mcp

by anipotts

conversation_gaps

Identify extended pauses in iMessage conversations to analyze communication patterns, detect periods of reduced contact, and understand relationship dynamics through message history.

Instructions

Find the longest silences in a conversation. Detects periods where you and a contact stopped talking — falling-outs, busy periods, or drifting apart. Shows gap duration and when it happened.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
contactYesContact handle or name
min_gap_daysNoMinimum gap in days to include (default: 7)
limitNoMax gaps to return (default 10)

Implementation Reference

  • Full registration and implementation of the conversation_gaps tool. This includes the handler function that queries the database to find the longest silences between consecutive messages in a conversation, using SQL window functions (LAG) to compare message timestamps and identify gaps exceeding a specified threshold.
    server.tool(
      "conversation_gaps",
      "Find the longest silences in a conversation. Detects periods where you and a contact stopped talking — falling-outs, busy periods, or drifting apart. Shows gap duration and when it happened.",
      {
        contact: z.string().describe("Contact handle or name"),
        min_gap_days: z.number().optional().describe("Minimum gap in days to include (default: 7)"),
        limit: z.number().optional().describe("Max gaps to return (default 10)"),
      },
      { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
      async (params) => {
        const db = getDb();
        const limit = clamp(params.limit ?? 10, 1, MAX_LIMIT);
        const minGapNano = (params.min_gap_days ?? 7) * 86400 * 1_000_000_000;
    
        const rows = db.prepare(`
          WITH msg_pairs AS (
            SELECT
              ${DATE_EXPR} as date,
              LAG(${DATE_EXPR}) OVER (ORDER BY m.date) as prev_date,
              m.date as raw_date,
              LAG(m.date) OVER (ORDER BY m.date) as prev_raw_date,
              m.is_from_me as broken_by_me,
              m.text as break_text,
              m.attributedBody as break_body
            FROM message m
            JOIN handle h ON m.handle_id = h.ROWID
            WHERE h.id LIKE @contact
              AND (m.text IS NOT NULL OR m.attributedBody IS NOT NULL) ${MSG_FILTER}
          )
          SELECT
            prev_date as silence_start,
            date as silence_end,
            ROUND((raw_date - prev_raw_date) / 1000000000.0 / 86400.0, 1) as gap_days,
            broken_by_me,
            break_text,
            break_body
          FROM msg_pairs
          WHERE prev_raw_date IS NOT NULL
            AND (raw_date - prev_raw_date) > @min_gap_nano
          ORDER BY gap_days DESC
          LIMIT @limit
        `).all({ contact: `%${params.contact}%`, min_gap_nano: minGapNano, limit }) as any[];
    
        if (rows.length === 0) {
          return { content: [{ type: "text", text: `No gaps longer than ${params.min_gap_days ?? 7} days found for "${params.contact}"` }] };
        }
    
        const contact = lookupContact(params.contact);
    
        return {
          content: [{
            type: "text",
            text: JSON.stringify({
              contact: contact.name,
              min_gap_days: params.min_gap_days ?? 7,
              gaps: rows.map((r: any) => ({
                gap_days: r.gap_days,
                silence_start: r.silence_start,
                silence_end: r.silence_end,
                broken_by: r.broken_by_me ? "you" : contact.name,
                ice_breaker_text: safeText(getMessageText({ text: r.break_text, attributedBody: r.break_body })) || "(attachment)",
              })),
            }, null, 2),
          }],
        };
      },
    );
  • Input schema definition for conversation_gaps tool using Zod validation. Defines three optional parameters: contact (required string), min_gap_days (default 7), and limit (default 10).
      contact: z.string().describe("Contact handle or name"),
      min_gap_days: z.number().optional().describe("Minimum gap in days to include (default: 7)"),
      limit: z.number().optional().describe("Max gaps to return (default 10)"),
    },

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/anipotts/imessage-mcp'

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