imsg-mcp 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +4 -1
- package/dist/cli.js +47 -5
- package/dist/cli.js.map +1 -1
- package/dist/{types-Bbi1xtl-.js → exportFormats-CWWiy5uz.js} +1 -10
- package/dist/exportFormats-CWWiy5uz.js.map +1 -0
- package/dist/{exportStream-Bu5recJ4.js → exportStream-B86sO7Mg.js} +19 -23
- package/dist/exportStream-B86sO7Mg.js.map +1 -0
- package/dist/{imessage-db-BYU5mxM-.js → imessage-db-C7w6mu1Q.js} +824 -411
- package/dist/imessage-db-C7w6mu1Q.js.map +1 -0
- package/dist/index.js +70 -34
- package/dist/index.js.map +1 -1
- package/dist/{setup-C8Ys73o9.js → setup-B2HejfMT.js} +2 -2
- package/dist/{setup-C8Ys73o9.js.map → setup-B2HejfMT.js.map} +1 -1
- package/dist/{shutdown-BJifUGdo.js → shutdown-CikCSZru.js} +4 -4
- package/dist/{shutdown-BJifUGdo.js.map → shutdown-CikCSZru.js.map} +1 -1
- package/dist/tui.js +20 -6
- package/dist/tui.js.map +1 -1
- package/dist/{watchdog-0RGOHpj4.js → watchdog-CnbBZnfg.js} +11 -2
- package/dist/watchdog-CnbBZnfg.js.map +1 -0
- package/native/imsg-native.darwin-arm64.node +0 -0
- package/native/index.d.ts +2 -74
- package/native/index.js +0 -2
- package/package.json +1 -1
- package/skills/imsg-mcp/SKILL.md +5 -0
- package/dist/exportStream-Bu5recJ4.js.map +0 -1
- package/dist/imessage-db-BYU5mxM-.js.map +0 -1
- package/dist/types-Bbi1xtl-.js.map +0 -1
- package/dist/watchdog-0RGOHpj4.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -6,17 +6,16 @@ import { promisify } from "node:util";
|
|
|
6
6
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
7
7
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
8
8
|
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
-
import { c as checkLocalAccess, f as formatAccessReport, s as shutdown, g as getImsgDbPath, a as getContactsDbPaths, b as getSlugsDbPath, d as appendLog, e as getFileLogLines, h as getLogDirectory, p as perf, i as checkMessagesAvailable, j as sendToChat, k as sendToChatId, l as sendMessageReliable, m as sendMessageAlt, n as sendAttachment, o as checkImessageAvailability, q as installShutdownHandlers, r as registerCleanup, t as enableStdinEofDetection, u as enableOrphanWatchdog, v as logStartup, w as info, x as startHeapMonitor, y as getLogs, z as setLastSendError, A as logShutdown, B as stopHeapMonitor, C as getLogFilePath, D as getLastSendError } from "./shutdown-
|
|
10
|
-
import { r as resolveRecipient, d as defaultCountryFromEnv, a as rankFuzzy, b as dispatchAnalytic, i as installWatchdog, n as noteActivity, c as readWatchdogState } from "./watchdog-
|
|
9
|
+
import { c as checkLocalAccess, f as formatAccessReport, s as shutdown, g as getImsgDbPath, a as getContactsDbPaths, b as getSlugsDbPath, d as appendLog, e as getFileLogLines, h as getLogDirectory, p as perf, i as checkMessagesAvailable, j as sendToChat, k as sendToChatId, l as sendMessageReliable, m as sendMessageAlt, n as sendAttachment, o as checkImessageAvailability, q as installShutdownHandlers, r as registerCleanup, t as enableStdinEofDetection, u as enableOrphanWatchdog, v as logStartup, w as info, x as startHeapMonitor, y as getLogs, z as setLastSendError, A as logShutdown, B as stopHeapMonitor, C as getLogFilePath, D as getLastSendError } from "./shutdown-CikCSZru.js";
|
|
10
|
+
import { m as minMessageId, r as resolveRecipient, d as defaultCountryFromEnv, a as rankFuzzy, b as dispatchAnalytic, i as installWatchdog, n as noteActivity, c as readWatchdogState } from "./watchdog-CnbBZnfg.js";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
import Database from "better-sqlite3";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { I as IMessageDB, n as normalizedPhoneVariants, h as hasNativeModule } from "./imessage-db-C7w6mu1Q.js";
|
|
14
|
+
import { streamExport } from "./exportStream-B86sO7Mg.js";
|
|
15
15
|
import { z } from "zod";
|
|
16
16
|
import { A as APP_VERSION, a as APP_NAME } from "./meta-D3NoTAjA.js";
|
|
17
17
|
import { randomUUID } from "node:crypto";
|
|
18
18
|
import { parseUserDate } from "./dateParse-DJXMfq3a.js";
|
|
19
|
-
import { m as minMessageId } from "./types-Bbi1xtl-.js";
|
|
20
19
|
const DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
21
20
|
let dbPath = join(homedir(), ".imsg-mcp", "analytics-cache.db");
|
|
22
21
|
let db = null;
|
|
@@ -1453,7 +1452,9 @@ const WaitForReplyOutputSchema = z.object({
|
|
|
1453
1452
|
elapsedSeconds: z.number().optional()
|
|
1454
1453
|
});
|
|
1455
1454
|
const ListConversationsSchema = z.object({
|
|
1456
|
-
|
|
1455
|
+
// Coerce: some MCP hosts serialise numeric tool args as strings.
|
|
1456
|
+
limit: z.coerce.number().int().min(0).default(20),
|
|
1457
|
+
offset: z.coerce.number().int().min(0).default(0)
|
|
1457
1458
|
});
|
|
1458
1459
|
const ListConversationsOutputSchema = z.object({
|
|
1459
1460
|
conversations: z.array(ConversationSchema),
|
|
@@ -1562,7 +1563,14 @@ const GetContactSchema = z.object({
|
|
|
1562
1563
|
message: "Provide either `handle` or `id`."
|
|
1563
1564
|
});
|
|
1564
1565
|
const GetContactOutputSchema = z.object({
|
|
1565
|
-
contact: ContactSchema.nullable()
|
|
1566
|
+
contact: ContactSchema.nullable(),
|
|
1567
|
+
/** Per-handle conversation mapping: which thread slug each handle chats under. */
|
|
1568
|
+
threads: z.array(
|
|
1569
|
+
z.object({
|
|
1570
|
+
handle: z.string(),
|
|
1571
|
+
threadSlug: z.string().nullable()
|
|
1572
|
+
})
|
|
1573
|
+
)
|
|
1566
1574
|
});
|
|
1567
1575
|
const ResolveHandleSchema = z.object({
|
|
1568
1576
|
handle: nonEmptyString("Phone number or email to resolve to a contact name.")
|
|
@@ -1805,7 +1813,7 @@ const TOOLS = [
|
|
|
1805
1813
|
},
|
|
1806
1814
|
{
|
|
1807
1815
|
name: "list_conversations",
|
|
1808
|
-
description: "List recent conversations with thread slugs, snippets, unread counts, participants, and service metadata.",
|
|
1816
|
+
description: "List recent conversations (newest first) with thread slugs, snippets, unread counts, participants, and service metadata. Paginate with `offset` + the returned `nextOffset` to page past the per-call cap.",
|
|
1809
1817
|
annotations: annotations.read,
|
|
1810
1818
|
inputSchema: {
|
|
1811
1819
|
type: "object",
|
|
@@ -1813,7 +1821,12 @@ const TOOLS = [
|
|
|
1813
1821
|
limit: {
|
|
1814
1822
|
type: "number",
|
|
1815
1823
|
default: 20,
|
|
1816
|
-
description: "
|
|
1824
|
+
description: "Conversations per page. 0 = as many as fit (capped at 500 per call)."
|
|
1825
|
+
},
|
|
1826
|
+
offset: {
|
|
1827
|
+
type: "number",
|
|
1828
|
+
default: 0,
|
|
1829
|
+
description: "Skip this many conversations (for pagination; pass the prior nextOffset)."
|
|
1817
1830
|
}
|
|
1818
1831
|
}
|
|
1819
1832
|
},
|
|
@@ -1925,7 +1938,7 @@ const TOOLS = [
|
|
|
1925
1938
|
},
|
|
1926
1939
|
{
|
|
1927
1940
|
name: "get_contact",
|
|
1928
|
-
description: "Fetch a single contact by handle (phone/email) or by numeric id. Returns null if not found.",
|
|
1941
|
+
description: "Fetch a single contact by handle (phone/email) or by numeric id, including each handle's thread slug (for send_message/get_messages). Returns null if not found.",
|
|
1929
1942
|
annotations: annotations.read,
|
|
1930
1943
|
inputSchema: {
|
|
1931
1944
|
type: "object",
|
|
@@ -2645,22 +2658,26 @@ ${formatted}${paginationLine}${perfLine}`,
|
|
|
2645
2658
|
signal
|
|
2646
2659
|
});
|
|
2647
2660
|
const durMs = span.end({ format, count: result.count, sizeBytes: result.sizeBytes });
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2661
|
+
const lines = [
|
|
2662
|
+
`Exported ${result.count} message(s) to ${result.savedTo}`,
|
|
2663
|
+
`Format: ${format}`,
|
|
2664
|
+
`Range: ${result.oldest?.toISOString() ?? "(none)"} → ${result.newest?.toISOString() ?? "(none)"}`,
|
|
2665
|
+
`Size: ${(result.sizeBytes / 1024).toFixed(1)} KB`
|
|
2666
|
+
];
|
|
2667
|
+
if (result.unmergedSiblings.length > 0) {
|
|
2668
|
+
const which = result.unmergedSiblings.map((s) => s.chatIdentifier).join(", ");
|
|
2669
|
+
lines.push(
|
|
2670
|
+
`⚠️ ${result.unmergedSiblings.length} other chat(s) (${which}) share this contact's identity but were not merged — history may be incomplete.`
|
|
2671
|
+
);
|
|
2672
|
+
}
|
|
2673
|
+
lines.push(`_Took ${durMs.toFixed(0)}ms_`);
|
|
2674
|
+
return toolText(lines.join("\n"), {
|
|
2675
|
+
...result,
|
|
2676
|
+
format,
|
|
2677
|
+
oldest: result.oldest?.toISOString() ?? null,
|
|
2678
|
+
newest: result.newest?.toISOString() ?? null,
|
|
2679
|
+
durationMs: durMs
|
|
2680
|
+
});
|
|
2664
2681
|
}
|
|
2665
2682
|
async handleGetUnreadMessages(args) {
|
|
2666
2683
|
const { limit } = GetUnreadMessagesSchema.parse(args ?? {});
|
|
@@ -2881,12 +2898,13 @@ ${formatted}`, {
|
|
|
2881
2898
|
);
|
|
2882
2899
|
}
|
|
2883
2900
|
async handleListConversations(args) {
|
|
2884
|
-
const { limit } = ListConversationsSchema.parse(args);
|
|
2901
|
+
const { limit, offset } = ListConversationsSchema.parse(args);
|
|
2885
2902
|
const HARD_CAP = 500;
|
|
2886
2903
|
const resolvedLimit = Math.min(resolveLimit(limit), HARD_CAP);
|
|
2887
|
-
const
|
|
2888
|
-
const
|
|
2889
|
-
const
|
|
2904
|
+
const startAfter = offset + resolvedLimit;
|
|
2905
|
+
const limited = await this.db.listConversations(startAfter + 1);
|
|
2906
|
+
const hasMore = limited.length > startAfter;
|
|
2907
|
+
const results = limited.slice(offset, startAfter);
|
|
2890
2908
|
if (results.length === 0) {
|
|
2891
2909
|
return toolText("No conversations found.", {
|
|
2892
2910
|
conversations: [],
|
|
@@ -2927,7 +2945,7 @@ ${formatted}`, {
|
|
|
2927
2945
|
})),
|
|
2928
2946
|
count: results.length,
|
|
2929
2947
|
hasMore,
|
|
2930
|
-
nextOffset: null
|
|
2948
|
+
nextOffset: hasMore ? startAfter : null
|
|
2931
2949
|
});
|
|
2932
2950
|
}
|
|
2933
2951
|
async handleSearchMessages(args) {
|
|
@@ -3057,7 +3075,7 @@ ${formatted}${hint}`,
|
|
|
3057
3075
|
contact = this.db.contacts.getContact(id);
|
|
3058
3076
|
}
|
|
3059
3077
|
if (!contact) {
|
|
3060
|
-
return toolText("Contact not found.", { contact: null });
|
|
3078
|
+
return toolText("Contact not found.", { contact: null, threads: [] });
|
|
3061
3079
|
}
|
|
3062
3080
|
const phones = contact.phoneNumbers.length > 0 ? `
|
|
3063
3081
|
Phones: ${contact.phoneNumbers.join(", ")}` : "";
|
|
@@ -3065,9 +3083,27 @@ Phones: ${contact.phoneNumbers.join(", ")}` : "";
|
|
|
3065
3083
|
Emails: ${contact.emails.join(", ")}` : "";
|
|
3066
3084
|
const org = contact.organization ? `
|
|
3067
3085
|
Organization: ${contact.organization}` : "";
|
|
3086
|
+
const resolveThreadSlug = async (handle2) => {
|
|
3087
|
+
const candidates = handle2.includes("@") ? [handle2] : normalizedPhoneVariants(handle2);
|
|
3088
|
+
for (const candidate of candidates) {
|
|
3089
|
+
const conv = await this.db.findChatByHandle(candidate);
|
|
3090
|
+
if (conv?.threadSlug) return conv.threadSlug;
|
|
3091
|
+
}
|
|
3092
|
+
return null;
|
|
3093
|
+
};
|
|
3094
|
+
const threads = await Promise.all(
|
|
3095
|
+
[...contact.phoneNumbers, ...contact.emails].map(async (h) => ({
|
|
3096
|
+
handle: h,
|
|
3097
|
+
threadSlug: await resolveThreadSlug(h)
|
|
3098
|
+
}))
|
|
3099
|
+
);
|
|
3100
|
+
const withThreads = threads.filter((t) => t.threadSlug);
|
|
3101
|
+
const threadLines = withThreads.length > 0 ? `
|
|
3102
|
+
Threads:
|
|
3103
|
+
${withThreads.map((t) => ` ${t.handle} → ${t.threadSlug}`).join("\n")}` : "";
|
|
3068
3104
|
return toolText(
|
|
3069
|
-
`${sanitizeUserText(contact.displayName)} (id ${contact.id})${phones}${emails}${org}`,
|
|
3070
|
-
{ contact }
|
|
3105
|
+
`${sanitizeUserText(contact.displayName)} (id ${contact.id})${phones}${emails}${org}${threadLines}`,
|
|
3106
|
+
{ contact, threads }
|
|
3071
3107
|
);
|
|
3072
3108
|
}
|
|
3073
3109
|
async handleResolveHandle(args) {
|