imsg-mcp 1.17.0 → 1.18.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 CHANGED
@@ -3,6 +3,13 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and follows [Semantic Versioning](https://semver.org/).
5
5
 
6
+ # [1.18.0](https://github.com/george43g/imsg-mcp/compare/v1.17.0...v1.18.0) (2026-07-25)
7
+
8
+
9
+ ### Features
10
+
11
+ * **tools:** uniform completeness metadata across list responses ([d8fd930](https://github.com/george43g/imsg-mcp/commit/d8fd930dfd28f28ac677ec4ffefd1addb39afbf5))
12
+
6
13
  # [1.17.0](https://github.com/george43g/imsg-mcp/compare/v1.16.0...v1.17.0) (2026-07-25)
7
14
 
8
15
 
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { createInterface } from "node:readline";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
5
5
  import { Command } from "commander";
6
6
  import { d as checkLocalAccess, f as formatAccessReport, I as IMPLEMENTED_TYPES, A as ANALYTIC_INFO, i as installShutdownHandlers, r as registerCleanup, l as looksLikeThreadSlug } from "./shutdown-0TCv4XJB.js";
7
- import { A as APP_VERSION, t as toYaml } from "./meta-B5cdb7uT.js";
7
+ import { A as APP_VERSION, t as toYaml } from "./meta-CZmUZHTh.js";
8
8
  import { spawn } from "node:child_process";
9
9
  import { join, dirname } from "node:path";
10
10
  function distRoot() {
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import { ensureAttachmentDownloaded } from "./attachment-sync-DMvlT8Zk.js";
14
14
  import { n as normalizedPhoneVariants, h as hasNativeModule, I as IMessageDB, r as rankFuzzy } from "./imessage-db-CHbdUXk3.js";
15
15
  import { parseUserDate } from "./date-parse-DJXMfq3a.js";
16
16
  import { streamExport, ExportInterpretGuardError } from "./exportStream-BFxilSlL.js";
17
- import { r as renderAnalyticText, A as APP_VERSION, a as APP_NAME } from "./meta-B5cdb7uT.js";
17
+ import { r as renderAnalyticText, A as APP_VERSION, a as APP_NAME } from "./meta-CZmUZHTh.js";
18
18
  import { randomUUID } from "node:crypto";
19
19
  import { z } from "zod";
20
20
  import { a as applyInlineInterpretations, i as imageBlockFromFile, v as videoPosterFrame, m as mediaMetadata, b as refForAttachment, T as TRANSCRIBE_MAX_BYTES, g as getInterpretRuntime, t as transcriptSourceEnum, d as detectTranscriber } from "./media-intel-runtime-BkxG4bmW.js";
@@ -1826,7 +1826,9 @@ const GetUnreadMessagesOutputSchema = z.object({
1826
1826
  messages: z.array(MessageSchema),
1827
1827
  count: z.number().int(),
1828
1828
  hasMore: z.boolean(),
1829
- nextOffset: z.number().int().nullable()
1829
+ truncated: z.boolean().describe(
1830
+ "True if more unread messages exist than were returned — raise `limit` to get the rest."
1831
+ )
1830
1832
  });
1831
1833
  const SendMessageSchema = z.object({
1832
1834
  recipient: nonEmptyString("Phone number or email address to send to").optional(),
@@ -1886,6 +1888,9 @@ const ListConversationsOutputSchema = z.object({
1886
1888
  conversations: z.array(ConversationSchema),
1887
1889
  count: z.number().int(),
1888
1890
  hasMore: z.boolean(),
1891
+ truncated: z.boolean().describe(
1892
+ "True if more conversations exist beyond this page — page on with `offset` + `nextOffset`."
1893
+ ),
1889
1894
  nextOffset: z.number().int().nullable()
1890
1895
  });
1891
1896
  const SearchMessagesSchema = z.object({
@@ -1904,7 +1909,7 @@ const SearchMessagesOutputSchema = z.object({
1904
1909
  messages: z.array(MessageSchema),
1905
1910
  count: z.number().int(),
1906
1911
  hasMore: z.boolean(),
1907
- nextOffset: z.number().int().nullable(),
1912
+ truncated: z.boolean().describe("True if more matches exist than were returned — raise `limit` or narrow the query."),
1908
1913
  softCapWarning: z.string().optional()
1909
1914
  });
1910
1915
  const GetLogsSchema = z.object({
@@ -1971,7 +1976,9 @@ const ListContactsOutputSchema = z.object({
1971
1976
  contacts: z.array(ContactSchema),
1972
1977
  count: z.number().int(),
1973
1978
  hasMore: z.boolean(),
1974
- totalCount: z.number().int()
1979
+ truncated: z.boolean().describe("True if more contacts exist beyond this page — page on with `offset`."),
1980
+ totalAvailable: z.number().int().describe("Total contacts available across all pages."),
1981
+ totalCount: z.number().int().describe("Alias of `totalAvailable` (kept for back-compat).")
1975
1982
  });
1976
1983
  const RankedContactSchema = ContactSchema.extend({
1977
1984
  score: z.number().describe("Relevance in [0,1]; higher = better. Results are sorted best-first."),
@@ -1984,7 +1991,9 @@ const SearchContactsSchema = z.object({
1984
1991
  const SearchContactsOutputSchema = z.object({
1985
1992
  query: z.string(),
1986
1993
  contacts: z.array(RankedContactSchema),
1987
- count: z.number().int()
1994
+ count: z.number().int(),
1995
+ truncated: z.boolean().describe("True if more contacts matched than were returned — raise `limit`."),
1996
+ totalAvailable: z.number().int().describe("Total contacts that matched the query.")
1988
1997
  });
1989
1998
  const GetContactSchema = z.object({
1990
1999
  handle: z.string().optional().describe("Phone number or email to look up."),
@@ -2057,11 +2066,12 @@ const SearchAttachmentsSchema = z.object({
2057
2066
  chatIdentifier: z.string().optional().describe("Restrict to a single chat (use chat_identifier from list_conversations)."),
2058
2067
  since: z.string().optional().describe("ISO date or relative ('1 week ago'). Lower bound on attachment creation."),
2059
2068
  until: z.string().optional().describe("ISO date or relative. Upper bound on creation."),
2060
- limit: z.number().int().min(0).default(20).describe("Max results. 0 = unlimited (capped at 1000).")
2069
+ limit: z.number().int().min(0).default(20).describe("Max results. 0 = unlimited.")
2061
2070
  });
2062
2071
  const SearchAttachmentsOutputSchema = z.object({
2063
2072
  attachments: z.array(AttachmentRecordSchema),
2064
- count: z.number().int()
2073
+ count: z.number().int(),
2074
+ truncated: z.boolean().describe("True if more attachments matched than were returned — raise `limit`.")
2065
2075
  });
2066
2076
  const InitHumanSchema = z.object({
2067
2077
  contact: nonEmptyString(
@@ -2415,7 +2425,7 @@ const TOOLS = [
2415
2425
  },
2416
2426
  {
2417
2427
  name: "search_contacts",
2418
- description: "Substring-match contacts by display name, phone number, or email.",
2428
+ description: "Substring-match contacts by display name, phone number, or email, ranked best-first (score + matchedField). Response reports `truncated` and `totalAvailable` so you know when more matched than were returned — raise `limit` to widen.",
2419
2429
  annotations: annotations.read,
2420
2430
  inputSchema: {
2421
2431
  type: "object",
@@ -2488,7 +2498,7 @@ const TOOLS = [
2488
2498
  },
2489
2499
  {
2490
2500
  name: "search_attachments",
2491
- description: "Search attachments (images, videos, files) by MIME type prefix, date range, and/or chat. Returns metadata only — use get_attachment to fetch bytes. Excludes stickers and Apple plugin payloads.",
2501
+ description: "Search attachments (images, videos, files) by MIME type prefix, date range, and/or chat. Returns metadata only — use get_attachment to fetch bytes. Excludes stickers and Apple plugin payloads. Response reports `truncated` (more matched than returned — raise `limit`).",
2492
2502
  annotations: annotations.read,
2493
2503
  inputSchema: {
2494
2504
  type: "object",
@@ -3181,7 +3191,7 @@ ${formatted}${paginationLine}${perfLine}${humansLine}`,
3181
3191
  messages: [],
3182
3192
  count: 0,
3183
3193
  hasMore: false,
3184
- nextOffset: null
3194
+ truncated: false
3185
3195
  });
3186
3196
  }
3187
3197
  const formatted = results.map((msg) => {
@@ -3195,7 +3205,7 @@ ${formatted}`, {
3195
3205
  messages: results.map(messageToStructured),
3196
3206
  count: results.length,
3197
3207
  hasMore,
3198
- nextOffset: null
3208
+ truncated: hasMore
3199
3209
  });
3200
3210
  }
3201
3211
  async handleSendMessage(args) {
@@ -3462,6 +3472,7 @@ ${formatted}${humansLine}`, {
3462
3472
  conversations: [],
3463
3473
  count: 0,
3464
3474
  hasMore: false,
3475
+ truncated: false,
3465
3476
  nextOffset: null
3466
3477
  });
3467
3478
  }
@@ -3501,6 +3512,7 @@ ${formatted}`, {
3501
3512
  }),
3502
3513
  count: results.length,
3503
3514
  hasMore,
3515
+ truncated: hasMore,
3504
3516
  nextOffset: hasMore ? startAfter : null
3505
3517
  });
3506
3518
  }
@@ -3529,7 +3541,7 @@ ${formatted}`, {
3529
3541
  messages: [],
3530
3542
  count: 0,
3531
3543
  hasMore: false,
3532
- nextOffset: null,
3544
+ truncated: false,
3533
3545
  softCapWarning
3534
3546
  });
3535
3547
  }
@@ -3546,7 +3558,7 @@ ${formatted}`, {
3546
3558
  messages: results.map(messageToStructured),
3547
3559
  count: results.length,
3548
3560
  hasMore,
3549
- nextOffset: null,
3561
+ truncated: hasMore,
3550
3562
  softCapWarning
3551
3563
  });
3552
3564
  }
@@ -3563,6 +3575,8 @@ ${formatted}`, {
3563
3575
  contacts: [],
3564
3576
  count: 0,
3565
3577
  hasMore: false,
3578
+ truncated: false,
3579
+ totalAvailable: total,
3566
3580
  totalCount: total
3567
3581
  });
3568
3582
  }
@@ -3577,6 +3591,8 @@ ${formatted}`, {
3577
3591
  contacts,
3578
3592
  count: contacts.length,
3579
3593
  hasMore,
3594
+ truncated: hasMore,
3595
+ totalAvailable: total,
3580
3596
  totalCount: total
3581
3597
  });
3582
3598
  }
@@ -3590,7 +3606,9 @@ ${formatted}`, {
3590
3606
  return toolText(`No contacts match "${query}".`, {
3591
3607
  query,
3592
3608
  contacts: [],
3593
- count: 0
3609
+ count: 0,
3610
+ truncated: false,
3611
+ totalAvailable: 0
3594
3612
  });
3595
3613
  }
3596
3614
  rememberSearch(
@@ -3621,7 +3639,9 @@ ${formatted}${hint}`,
3621
3639
  score: m.score,
3622
3640
  matchedField: m.matchedField
3623
3641
  })),
3624
- count: results.length
3642
+ count: results.length,
3643
+ truncated: ranked.length > results.length,
3644
+ totalAvailable: ranked.length
3625
3645
  }
3626
3646
  );
3627
3647
  }
@@ -3774,14 +3794,17 @@ ${lines}${hint}`,
3774
3794
  const sinceMs = since ? parseUserDate(since)?.getTime() : void 0;
3775
3795
  const untilMs = until ? parseUserDate(until)?.getTime() : void 0;
3776
3796
  const resolvedLimit = resolveLimit(limit);
3797
+ const bounded = resolvedLimit < Number.MAX_SAFE_INTEGER;
3777
3798
  const opts = {
3778
- limit: resolvedLimit
3799
+ limit: bounded ? resolvedLimit + 1 : resolvedLimit
3779
3800
  };
3780
3801
  if (mimePrefix !== void 0) opts.mimePrefix = mimePrefix;
3781
3802
  if (chatIdentifier !== void 0) opts.chatIdentifier = chatIdentifier;
3782
3803
  if (sinceMs !== void 0) opts.sinceMs = sinceMs;
3783
3804
  if (untilMs !== void 0) opts.untilMs = untilMs;
3784
- const results = this.db.searchAttachments(opts);
3805
+ const raw = this.db.searchAttachments(opts);
3806
+ const truncated = raw.length > resolvedLimit;
3807
+ const results = raw.slice(0, resolvedLimit);
3785
3808
  const formatted = results.map(
3786
3809
  (a) => `[${a.rowId}] ${a.mimeType ?? "?"} · ${a.totalBytes}B · ${a.createdDate.toISOString().slice(0, 10)} · ${a.transferName ?? a.filename}`
3787
3810
  ).join("\n");
@@ -3797,7 +3820,8 @@ ${formatted}`, {
3797
3820
  createdDate: a.createdDate.toISOString(),
3798
3821
  chatId: a.chatId
3799
3822
  })),
3800
- count: results.length
3823
+ count: results.length,
3824
+ truncated
3801
3825
  });
3802
3826
  }
3803
3827
  async handleGetAttachment(args) {