ofw-mcp 1.4.1 → 1.5.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/dist/bundle.js CHANGED
@@ -21054,6 +21054,19 @@ var toolDefinitions2 = [
21054
21054
  },
21055
21055
  required: ["messageId"]
21056
21056
  }
21057
+ },
21058
+ {
21059
+ name: "ofw_get_unread_sent",
21060
+ description: "List sent messages that have not been read by one or more recipients. Fetches sent messages page by page and returns only those with unread recipients.",
21061
+ annotations: { readOnlyHint: true },
21062
+ inputSchema: {
21063
+ type: "object",
21064
+ properties: {
21065
+ page: { type: "number", description: "Page of sent messages to scan (default 1)" },
21066
+ size: { type: "number", description: "Number of sent messages per page, max 50 (default 20)" }
21067
+ },
21068
+ required: []
21069
+ }
21057
21070
  }
21058
21071
  ];
21059
21072
  async function handleTool2(name, args, client2) {
@@ -21119,6 +21132,35 @@ async function handleTool2(name, args, client2) {
21119
21132
  const data = await client2.request("DELETE", "/pub/v1/messages", form);
21120
21133
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
21121
21134
  }
21135
+ case "ofw_get_unread_sent": {
21136
+ const { page = 1, size = 20 } = args;
21137
+ const folders = await client2.request(
21138
+ "GET",
21139
+ "/pub/v1/messageFolders?includeFolderCounts=true"
21140
+ );
21141
+ const sentFolder = folders.find((f) => f.folderType === "SENT_MESSAGES");
21142
+ if (!sentFolder) throw new Error("Sent folder not found");
21143
+ const listPath = `/pub/v3/messages?folders=${encodeURIComponent(sentFolder.id)}&page=${page}&size=${size}&sort=date&sortDirection=desc`;
21144
+ const listData = await client2.request("GET", listPath);
21145
+ const messages = listData.data ?? [];
21146
+ const unread = [];
21147
+ for (const msg of messages) {
21148
+ const detail = await client2.request("GET", `/pub/v3/messages/${msg.id}`);
21149
+ const unreadRecipients = (detail.recipients ?? []).filter((r) => !r.viewed).map((r) => r.user.name);
21150
+ if (unreadRecipients.length > 0) {
21151
+ unread.push({
21152
+ id: detail.id,
21153
+ subject: detail.subject,
21154
+ sentAt: detail.date.dateTime,
21155
+ unreadBy: unreadRecipients
21156
+ });
21157
+ }
21158
+ }
21159
+ if (unread.length === 0) {
21160
+ return { content: [{ type: "text", text: JSON.stringify({ message: "All scanned sent messages have been read." }, null, 2) }] };
21161
+ }
21162
+ return { content: [{ type: "text", text: JSON.stringify(unread, null, 2) }] };
21163
+ }
21122
21164
  default:
21123
21165
  throw new Error(`Unknown tool: ${name}`);
21124
21166
  }
@@ -108,6 +108,19 @@ export const toolDefinitions = [
108
108
  required: ['messageId'],
109
109
  },
110
110
  },
111
+ {
112
+ name: 'ofw_get_unread_sent',
113
+ description: 'List sent messages that have not been read by one or more recipients. Fetches sent messages page by page and returns only those with unread recipients.',
114
+ annotations: { readOnlyHint: true },
115
+ inputSchema: {
116
+ type: 'object',
117
+ properties: {
118
+ page: { type: 'number', description: 'Page of sent messages to scan (default 1)' },
119
+ size: { type: 'number', description: 'Number of sent messages per page, max 50 (default 20)' },
120
+ },
121
+ required: [],
122
+ },
123
+ },
111
124
  ];
112
125
  export async function handleTool(name, args, client) {
113
126
  switch (name) {
@@ -170,6 +183,38 @@ export async function handleTool(name, args, client) {
170
183
  const data = await client.request('DELETE', '/pub/v1/messages', form);
171
184
  return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
172
185
  }
186
+ case 'ofw_get_unread_sent': {
187
+ const { page = 1, size = 20 } = args;
188
+ // Step 1: find the sent folder
189
+ const folders = await client.request('GET', '/pub/v1/messageFolders?includeFolderCounts=true');
190
+ const sentFolder = folders.find((f) => f.folderType === 'SENT_MESSAGES');
191
+ if (!sentFolder)
192
+ throw new Error('Sent folder not found');
193
+ // Step 2: list sent messages
194
+ const listPath = `/pub/v3/messages?folders=${encodeURIComponent(sentFolder.id)}&page=${page}&size=${size}&sort=date&sortDirection=desc`;
195
+ const listData = await client.request('GET', listPath);
196
+ const messages = listData.data ?? [];
197
+ // Step 3: fetch each message detail and filter to unread
198
+ const unread = [];
199
+ for (const msg of messages) {
200
+ const detail = await client.request('GET', `/pub/v3/messages/${msg.id}`);
201
+ const unreadRecipients = (detail.recipients ?? [])
202
+ .filter((r) => !r.viewed)
203
+ .map((r) => r.user.name);
204
+ if (unreadRecipients.length > 0) {
205
+ unread.push({
206
+ id: detail.id,
207
+ subject: detail.subject,
208
+ sentAt: detail.date.dateTime,
209
+ unreadBy: unreadRecipients,
210
+ });
211
+ }
212
+ }
213
+ if (unread.length === 0) {
214
+ return { content: [{ type: 'text', text: JSON.stringify({ message: 'All scanned sent messages have been read.' }, null, 2) }] };
215
+ }
216
+ return { content: [{ type: 'text', text: JSON.stringify(unread, null, 2) }] };
217
+ }
173
218
  default:
174
219
  throw new Error(`Unknown tool: ${name}`);
175
220
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ofw-mcp",
3
- "version": "1.4.1",
3
+ "version": "1.5.0",
4
4
  "description": "OurFamilyWizard MCP server for Claude — developed and maintained by AI (Claude Sonnet 4.6)",
5
5
  "author": "Claude Sonnet 4.6 (AI) <https://www.anthropic.com/claude>",
6
6
  "repository": {