ofw-mcp 2.0.5 → 2.0.6

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.
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "OurFamilyWizard tools for Claude Code",
9
- "version": "2.0.5"
9
+ "version": "2.0.6"
10
10
  },
11
11
  "plugins": [
12
12
  {
@@ -14,7 +14,7 @@
14
14
  "displayName": "OurFamilyWizard",
15
15
  "source": "./",
16
16
  "description": "OurFamilyWizard co-parenting tools for Claude — messages, calendar, expenses, and journal via MCP",
17
- "version": "2.0.5",
17
+ "version": "2.0.6",
18
18
  "author": {
19
19
  "name": "Chris Chall"
20
20
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ofw",
3
3
  "displayName": "OurFamilyWizard",
4
- "version": "2.0.5",
4
+ "version": "2.0.6",
5
5
  "description": "OurFamilyWizard co-parenting tools for Claude — messages, calendar, expenses, and journal via MCP",
6
6
  "author": {
7
7
  "name": "Chris Chall"
package/dist/bundle.js CHANGED
@@ -31129,13 +31129,59 @@ function getMessage(id) {
31129
31129
  function listMessages(opts) {
31130
31130
  const { db } = openCache();
31131
31131
  const offset = (opts.page - 1) * opts.size;
31132
+ const wheres = [];
31133
+ const params = [];
31134
+ if (opts.folder !== void 0) {
31135
+ wheres.push("folder = ?");
31136
+ params.push(opts.folder);
31137
+ }
31138
+ if (opts.since !== void 0) {
31139
+ wheres.push("sent_at >= ?");
31140
+ params.push(opts.since);
31141
+ }
31142
+ if (opts.until !== void 0) {
31143
+ wheres.push("sent_at < ?");
31144
+ params.push(opts.until);
31145
+ }
31146
+ if (opts.q !== void 0 && opts.q.length > 0) {
31147
+ const pattern = `%${opts.q}%`;
31148
+ wheres.push("(subject LIKE ? OR body LIKE ?)");
31149
+ params.push(pattern, pattern);
31150
+ }
31151
+ const where = wheres.length > 0 ? `WHERE ${wheres.join(" AND ")}` : "";
31152
+ params.push(opts.size, offset);
31132
31153
  const rows = db.prepare(
31133
- `SELECT * FROM messages WHERE folder = ?
31154
+ `SELECT * FROM messages ${where}
31134
31155
  ORDER BY sent_at DESC, id DESC
31135
31156
  LIMIT ? OFFSET ?`
31136
- ).all(opts.folder, opts.size, offset);
31157
+ ).all(...params);
31137
31158
  return rows.map(rowFromDb);
31138
31159
  }
31160
+ function countMessages(opts) {
31161
+ const { db } = openCache();
31162
+ const wheres = [];
31163
+ const params = [];
31164
+ if (opts.folder !== void 0) {
31165
+ wheres.push("folder = ?");
31166
+ params.push(opts.folder);
31167
+ }
31168
+ if (opts.since !== void 0) {
31169
+ wheres.push("sent_at >= ?");
31170
+ params.push(opts.since);
31171
+ }
31172
+ if (opts.until !== void 0) {
31173
+ wheres.push("sent_at < ?");
31174
+ params.push(opts.until);
31175
+ }
31176
+ if (opts.q !== void 0 && opts.q.length > 0) {
31177
+ const pattern = `%${opts.q}%`;
31178
+ wheres.push("(subject LIKE ? OR body LIKE ?)");
31179
+ params.push(pattern, pattern);
31180
+ }
31181
+ const where = wheres.length > 0 ? `WHERE ${wheres.join(" AND ")}` : "";
31182
+ const r = db.prepare(`SELECT COUNT(*) as n FROM messages ${where}`).get(...params);
31183
+ return r?.n ?? 0;
31184
+ }
31139
31185
  function draftFromDb(r) {
31140
31186
  return {
31141
31187
  id: r.id,
@@ -31258,14 +31304,12 @@ async function syncMessageFolder(client2, folder, folderId, opts) {
31258
31304
  const list = await client2.request("GET", path);
31259
31305
  const items = list.data ?? [];
31260
31306
  if (items.length === 0) break;
31261
- let pageSawKnownItem = false;
31307
+ let pageHadNewItem = false;
31262
31308
  for (const item of items) {
31263
31309
  if (newestId === null || item.id > newestId) newestId = item.id;
31264
31310
  const existing = getMessage(item.id);
31265
- if (existing) {
31266
- pageSawKnownItem = true;
31267
- continue;
31268
- }
31311
+ if (existing) continue;
31312
+ pageHadNewItem = true;
31269
31313
  const isInboxUnread = folder === "inbox" && item.showNeverViewed === true;
31270
31314
  const shouldFetchBody = !isInboxUnread || opts.fetchUnreadBodies;
31271
31315
  let body = null;
@@ -31298,7 +31342,7 @@ async function syncMessageFolder(client2, folder, folderId, opts) {
31298
31342
  upsertMessage(row);
31299
31343
  synced++;
31300
31344
  }
31301
- if (pageSawKnownItem) break;
31345
+ if (!opts.deep && !pageHadNewItem) break;
31302
31346
  page++;
31303
31347
  }
31304
31348
  setSyncState(folder, {
@@ -31349,12 +31393,16 @@ async function syncAll(client2, opts) {
31349
31393
  for (const folder of folders) {
31350
31394
  if (folder === "inbox") {
31351
31395
  const r = await syncMessageFolder(client2, "inbox", ids.inbox, {
31352
- fetchUnreadBodies: opts.fetchUnreadBodies ?? false
31396
+ fetchUnreadBodies: opts.fetchUnreadBodies ?? false,
31397
+ deep: opts.deep ?? false
31353
31398
  });
31354
31399
  synced.inbox = r.synced;
31355
31400
  unreadInbox = r.unread;
31356
31401
  } else if (folder === "sent") {
31357
- const r = await syncMessageFolder(client2, "sent", ids.sent, { fetchUnreadBodies: false });
31402
+ const r = await syncMessageFolder(client2, "sent", ids.sent, {
31403
+ fetchUnreadBodies: false,
31404
+ deep: opts.deep ?? false
31405
+ });
31358
31406
  synced.sent = r.synced;
31359
31407
  } else if (folder === "drafts") {
31360
31408
  const r = await syncDrafts(client2, ids.drafts);
@@ -31375,32 +31423,44 @@ function registerMessageTools(server2, client2) {
31375
31423
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
31376
31424
  });
31377
31425
  server2.registerTool("ofw_list_messages", {
31378
- description: 'List messages from the local OurFamilyWizard cache. folderId accepts "inbox" or "sent". Call ofw_sync_messages first if the cache is empty or stale.',
31426
+ description: "List messages from the local OurFamilyWizard cache. Supports filtering by folder, date range, and a substring query on subject+body. Pagination is offset-based but if you know what you want (a date range, a topic), prefer the filters over walking pages \u2014 the cache may have 1000+ messages. Call ofw_sync_messages first if the cache is empty or stale.",
31379
31427
  annotations: { readOnlyHint: true },
31380
31428
  inputSchema: {
31381
- folderId: external_exports.string().describe('Folder name: "inbox" or "sent"'),
31429
+ folderId: external_exports.string().describe('Folder name: "inbox", "sent", or "both" (default "both")').optional(),
31382
31430
  page: external_exports.number().describe("Page number (default 1)").optional(),
31383
- size: external_exports.number().describe("Messages per page (default 50)").optional()
31431
+ size: external_exports.number().describe("Messages per page (default 50)").optional(),
31432
+ since: external_exports.string().describe("ISO date or datetime \u2014 only messages with sent_at >= since (inclusive)").optional(),
31433
+ until: external_exports.string().describe("ISO date or datetime \u2014 only messages with sent_at < until (exclusive)").optional(),
31434
+ q: external_exports.string().describe("Substring match on subject AND body (case-insensitive). Use to find messages on a specific topic.").optional()
31384
31435
  }
31385
31436
  }, async (args) => {
31386
31437
  const page = args.page ?? 1;
31387
31438
  const size = args.size ?? 50;
31388
- let folder = null;
31389
- if (args.folderId === "inbox") folder = "inbox";
31390
- else if (args.folderId === "sent") folder = "sent";
31439
+ const folderArg = args.folderId ?? "both";
31440
+ let folder;
31441
+ if (folderArg === "inbox") folder = "inbox";
31442
+ else if (folderArg === "sent") folder = "sent";
31443
+ else if (folderArg === "both") folder = void 0;
31391
31444
  else {
31392
31445
  return {
31393
31446
  content: [{
31394
31447
  type: "text",
31395
31448
  text: JSON.stringify({
31396
31449
  messages: [],
31397
- note: 'Cache is keyed by folder name. Pass folderId: "inbox" or "sent" (numeric folder IDs are not yet supported by the cache layer).'
31450
+ note: 'folderId must be "inbox", "sent", or "both". Numeric OFW folder IDs are not supported by the cache.'
31398
31451
  }, null, 2)
31399
31452
  }]
31400
31453
  };
31401
31454
  }
31402
- const messages = listMessages({ folder, page, size });
31403
- const payload = messages.length === 0 ? { messages: [], note: "Cache empty for this folder. Call ofw_sync_messages to populate." } : { messages };
31455
+ const filter = { folder, since: args.since, until: args.until, q: args.q };
31456
+ const total = countMessages(filter);
31457
+ const messages = listMessages({ ...filter, page, size });
31458
+ const payload = { messages, total, page, size };
31459
+ if (total === 0) {
31460
+ payload.note = "No messages match these filters. If you expected results, check ofw_sync_messages was run, or relax the filters.";
31461
+ } else if (page * size < total) {
31462
+ payload.note = `Showing ${(page - 1) * size + 1}\u2013${(page - 1) * size + messages.length} of ${total}. Increase 'page' to see more, or narrow with since/until/q.`;
31463
+ }
31404
31464
  return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
31405
31465
  });
31406
31466
  server2.registerTool("ofw_get_message", {
@@ -31614,16 +31674,18 @@ ${text}` : text;
31614
31674
  return { content: [{ type: "text", text: JSON.stringify(unread, null, 2) }] };
31615
31675
  });
31616
31676
  server2.registerTool("ofw_sync_messages", {
31617
- description: "Sync messages from OurFamilyWizard into the local cache. Returns counts per folder and a list of unread inbox messages whose bodies were NOT fetched (to avoid mark-as-read on OFW). Call ofw_get_message(id) on those to read them.",
31677
+ description: "Sync messages from OurFamilyWizard into the local cache. Returns counts per folder and a list of unread inbox messages whose bodies were NOT fetched (to avoid mark-as-read on OFW). Call ofw_get_message(id) on those to read them. Pass deep:true to walk all OFW pages instead of stopping at the first all-cached page (use to backfill suspected gaps).",
31618
31678
  annotations: { readOnlyHint: false },
31619
31679
  inputSchema: {
31620
31680
  folders: external_exports.array(external_exports.enum(["inbox", "sent", "drafts"])).describe("Folders to sync (default: all three)").optional(),
31621
- fetchUnreadBodies: external_exports.boolean().describe("If true, also fetch bodies for unread inbox messages (will mark them as read on OFW). Default false.").optional()
31681
+ fetchUnreadBodies: external_exports.boolean().describe("If true, also fetch bodies for unread inbox messages (will mark them as read on OFW). Default false.").optional(),
31682
+ deep: external_exports.boolean().describe("If true, walk every OFW page until empty regardless of cache state. Use to backfill gaps. Default false.").optional()
31622
31683
  }
31623
31684
  }, async (args) => {
31624
31685
  const result = await syncAll(client2, {
31625
31686
  folders: args.folders,
31626
- fetchUnreadBodies: args.fetchUnreadBodies
31687
+ fetchUnreadBodies: args.fetchUnreadBodies,
31688
+ deep: args.deep
31627
31689
  });
31628
31690
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
31629
31691
  });
@@ -31771,7 +31833,7 @@ process.emit = function(event, ...args) {
31771
31833
  }
31772
31834
  return originalEmit(event, ...args);
31773
31835
  };
31774
- var server = new McpServer({ name: "ofw", version: "2.0.5" });
31836
+ var server = new McpServer({ name: "ofw", version: "2.0.6" });
31775
31837
  registerUserTools(server, client);
31776
31838
  registerMessageTools(server, client);
31777
31839
  registerCalendarTools(server, client);
package/dist/cache.js CHANGED
@@ -106,11 +106,58 @@ export function getMessage(id) {
106
106
  export function listMessages(opts) {
107
107
  const { db } = openCache();
108
108
  const offset = (opts.page - 1) * opts.size;
109
- const rows = db.prepare(`SELECT * FROM messages WHERE folder = ?
109
+ const wheres = [];
110
+ const params = [];
111
+ if (opts.folder !== undefined) {
112
+ wheres.push('folder = ?');
113
+ params.push(opts.folder);
114
+ }
115
+ if (opts.since !== undefined) {
116
+ wheres.push('sent_at >= ?');
117
+ params.push(opts.since);
118
+ }
119
+ if (opts.until !== undefined) {
120
+ wheres.push('sent_at < ?');
121
+ params.push(opts.until);
122
+ }
123
+ if (opts.q !== undefined && opts.q.length > 0) {
124
+ const pattern = `%${opts.q}%`;
125
+ wheres.push('(subject LIKE ? OR body LIKE ?)');
126
+ params.push(pattern, pattern);
127
+ }
128
+ const where = wheres.length > 0 ? `WHERE ${wheres.join(' AND ')}` : '';
129
+ params.push(opts.size, offset);
130
+ const rows = db.prepare(`SELECT * FROM messages ${where}
110
131
  ORDER BY sent_at DESC, id DESC
111
- LIMIT ? OFFSET ?`).all(opts.folder, opts.size, offset);
132
+ LIMIT ? OFFSET ?`).all(...params);
112
133
  return rows.map(rowFromDb);
113
134
  }
135
+ export function countMessages(opts) {
136
+ const { db } = openCache();
137
+ const wheres = [];
138
+ const params = [];
139
+ if (opts.folder !== undefined) {
140
+ wheres.push('folder = ?');
141
+ params.push(opts.folder);
142
+ }
143
+ if (opts.since !== undefined) {
144
+ wheres.push('sent_at >= ?');
145
+ params.push(opts.since);
146
+ }
147
+ if (opts.until !== undefined) {
148
+ wheres.push('sent_at < ?');
149
+ params.push(opts.until);
150
+ }
151
+ if (opts.q !== undefined && opts.q.length > 0) {
152
+ const pattern = `%${opts.q}%`;
153
+ wheres.push('(subject LIKE ? OR body LIKE ?)');
154
+ params.push(pattern, pattern);
155
+ }
156
+ const where = wheres.length > 0 ? `WHERE ${wheres.join(' AND ')}` : '';
157
+ const r = db.prepare(`SELECT COUNT(*) as n FROM messages ${where}`)
158
+ .get(...params);
159
+ return r?.n ?? 0;
160
+ }
114
161
  function draftFromDb(r) {
115
162
  return {
116
163
  id: r.id,
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import { registerMessageTools } from './tools/messages.js';
17
17
  import { registerCalendarTools } from './tools/calendar.js';
18
18
  import { registerExpenseTools } from './tools/expenses.js';
19
19
  import { registerJournalTools } from './tools/journal.js';
20
- const server = new McpServer({ name: 'ofw', version: '2.0.5' });
20
+ const server = new McpServer({ name: 'ofw', version: '2.0.6' });
21
21
  registerUserTools(server, client);
22
22
  registerMessageTools(server, client);
23
23
  registerCalendarTools(server, client);
package/dist/sync.js CHANGED
@@ -34,15 +34,14 @@ export async function syncMessageFolder(client, folder, folderId, opts) {
34
34
  const items = list.data ?? [];
35
35
  if (items.length === 0)
36
36
  break;
37
- let pageSawKnownItem = false;
37
+ let pageHadNewItem = false;
38
38
  for (const item of items) {
39
39
  if (newestId === null || item.id > newestId)
40
40
  newestId = item.id;
41
41
  const existing = getMessage(item.id);
42
- if (existing) {
43
- pageSawKnownItem = true;
42
+ if (existing)
44
43
  continue;
45
- }
44
+ pageHadNewItem = true;
46
45
  const isInboxUnread = folder === 'inbox' && item.showNeverViewed === true;
47
46
  const shouldFetchBody = !isInboxUnread || opts.fetchUnreadBodies;
48
47
  let body = null;
@@ -76,8 +75,12 @@ export async function syncMessageFolder(client, folder, folderId, opts) {
76
75
  upsertMessage(row);
77
76
  synced++;
78
77
  }
79
- // OFW returns date-desc, so a known item means we've reached cached history.
80
- if (pageSawKnownItem)
78
+ // Stop heuristic: a page with no new items means we've reached cached
79
+ // history (OFW returns date-desc). A page with even ONE new item could
80
+ // mean there are more new items on the next page that we haven't seen
81
+ // yet — keep walking. With `deep: true`, walk every page until OFW
82
+ // returns an empty page (used to backfill suspected gaps).
83
+ if (!opts.deep && !pageHadNewItem)
81
84
  break;
82
85
  page++;
83
86
  }
@@ -129,12 +132,16 @@ export async function syncAll(client, opts) {
129
132
  if (folder === 'inbox') {
130
133
  const r = await syncMessageFolder(client, 'inbox', ids.inbox, {
131
134
  fetchUnreadBodies: opts.fetchUnreadBodies ?? false,
135
+ deep: opts.deep ?? false,
132
136
  });
133
137
  synced.inbox = r.synced;
134
138
  unreadInbox = r.unread;
135
139
  }
136
140
  else if (folder === 'sent') {
137
- const r = await syncMessageFolder(client, 'sent', ids.sent, { fetchUnreadBodies: false });
141
+ const r = await syncMessageFolder(client, 'sent', ids.sent, {
142
+ fetchUnreadBodies: false,
143
+ deep: opts.deep ?? false,
144
+ });
138
145
  synced.sent = r.synced;
139
146
  }
140
147
  else if (folder === 'drafts') {
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { syncAll } from '../sync.js';
3
- import { listMessages, listDrafts, getMessage, upsertMessage, upsertDraft, deleteDraft, findLatestReplyTip, } from '../cache.js';
3
+ import { listMessages, countMessages, listDrafts, getMessage, upsertMessage, upsertDraft, deleteDraft, findLatestReplyTip, } from '../cache.js';
4
4
  export function registerMessageTools(server, client) {
5
5
  server.registerTool('ofw_list_message_folders', {
6
6
  description: 'List OurFamilyWizard message folders (inbox, sent, etc.) and their unread counts. Returns folder IDs needed to call ofw_list_messages. Does NOT return message content.',
@@ -10,36 +10,48 @@ export function registerMessageTools(server, client) {
10
10
  return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
11
11
  });
12
12
  server.registerTool('ofw_list_messages', {
13
- description: 'List messages from the local OurFamilyWizard cache. folderId accepts "inbox" or "sent". Call ofw_sync_messages first if the cache is empty or stale.',
13
+ description: 'List messages from the local OurFamilyWizard cache. Supports filtering by folder, date range, and a substring query on subject+body. Pagination is offset-based but if you know what you want (a date range, a topic), prefer the filters over walking pages — the cache may have 1000+ messages. Call ofw_sync_messages first if the cache is empty or stale.',
14
14
  annotations: { readOnlyHint: true },
15
15
  inputSchema: {
16
- folderId: z.string().describe('Folder name: "inbox" or "sent"'),
16
+ folderId: z.string().describe('Folder name: "inbox", "sent", or "both" (default "both")').optional(),
17
17
  page: z.number().describe('Page number (default 1)').optional(),
18
18
  size: z.number().describe('Messages per page (default 50)').optional(),
19
+ since: z.string().describe('ISO date or datetime — only messages with sent_at >= since (inclusive)').optional(),
20
+ until: z.string().describe('ISO date or datetime — only messages with sent_at < until (exclusive)').optional(),
21
+ q: z.string().describe('Substring match on subject AND body (case-insensitive). Use to find messages on a specific topic.').optional(),
19
22
  },
20
23
  }, async (args) => {
21
24
  const page = args.page ?? 1;
22
25
  const size = args.size ?? 50;
23
- let folder = null;
24
- if (args.folderId === 'inbox')
26
+ const folderArg = args.folderId ?? 'both';
27
+ let folder;
28
+ if (folderArg === 'inbox')
25
29
  folder = 'inbox';
26
- else if (args.folderId === 'sent')
30
+ else if (folderArg === 'sent')
27
31
  folder = 'sent';
32
+ else if (folderArg === 'both')
33
+ folder = undefined;
28
34
  else {
29
35
  return {
30
36
  content: [{
31
37
  type: 'text',
32
38
  text: JSON.stringify({
33
39
  messages: [],
34
- note: 'Cache is keyed by folder name. Pass folderId: "inbox" or "sent" (numeric folder IDs are not yet supported by the cache layer).',
40
+ note: 'folderId must be "inbox", "sent", or "both". Numeric OFW folder IDs are not supported by the cache.',
35
41
  }, null, 2),
36
42
  }],
37
43
  };
38
44
  }
39
- const messages = listMessages({ folder, page, size });
40
- const payload = messages.length === 0
41
- ? { messages: [], note: 'Cache empty for this folder. Call ofw_sync_messages to populate.' }
42
- : { messages };
45
+ const filter = { folder, since: args.since, until: args.until, q: args.q };
46
+ const total = countMessages(filter);
47
+ const messages = listMessages({ ...filter, page, size });
48
+ const payload = { messages, total, page, size };
49
+ if (total === 0) {
50
+ payload.note = 'No messages match these filters. If you expected results, check ofw_sync_messages was run, or relax the filters.';
51
+ }
52
+ else if (page * size < total) {
53
+ payload.note = `Showing ${(page - 1) * size + 1}–${(page - 1) * size + messages.length} of ${total}. Increase 'page' to see more, or narrow with since/until/q.`;
54
+ }
43
55
  return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
44
56
  });
45
57
  server.registerTool('ofw_get_message', {
@@ -246,16 +258,18 @@ export function registerMessageTools(server, client) {
246
258
  return { content: [{ type: 'text', text: JSON.stringify(unread, null, 2) }] };
247
259
  });
248
260
  server.registerTool('ofw_sync_messages', {
249
- description: 'Sync messages from OurFamilyWizard into the local cache. Returns counts per folder and a list of unread inbox messages whose bodies were NOT fetched (to avoid mark-as-read on OFW). Call ofw_get_message(id) on those to read them.',
261
+ description: 'Sync messages from OurFamilyWizard into the local cache. Returns counts per folder and a list of unread inbox messages whose bodies were NOT fetched (to avoid mark-as-read on OFW). Call ofw_get_message(id) on those to read them. Pass deep:true to walk all OFW pages instead of stopping at the first all-cached page (use to backfill suspected gaps).',
250
262
  annotations: { readOnlyHint: false },
251
263
  inputSchema: {
252
264
  folders: z.array(z.enum(['inbox', 'sent', 'drafts'])).describe('Folders to sync (default: all three)').optional(),
253
265
  fetchUnreadBodies: z.boolean().describe('If true, also fetch bodies for unread inbox messages (will mark them as read on OFW). Default false.').optional(),
266
+ deep: z.boolean().describe('If true, walk every OFW page until empty regardless of cache state. Use to backfill gaps. Default false.').optional(),
254
267
  },
255
268
  }, async (args) => {
256
269
  const result = await syncAll(client, {
257
270
  folders: args.folders,
258
271
  fetchUnreadBodies: args.fetchUnreadBodies,
272
+ deep: args.deep,
259
273
  });
260
274
  return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
261
275
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ofw-mcp",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "mcpName": "io.github.chrischall/ofw-mcp",
5
5
  "description": "OurFamilyWizard MCP server for Claude — developed and maintained by AI (Claude Code)",
6
6
  "author": "Claude Code (AI) <https://www.anthropic.com/claude>",
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/chrischall/ofw-mcp",
7
7
  "source": "github"
8
8
  },
9
- "version": "2.0.5",
9
+ "version": "2.0.6",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "ofw-mcp",
14
- "version": "2.0.5",
14
+ "version": "2.0.6",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },