@davidwoods/skylight-mcp 0.0.0-stage → 1.7.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.
Files changed (168) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +583 -2
  3. package/THIRD_PARTY_NOTICES.md +38 -0
  4. package/dist/api/auth.d.ts +34 -0
  5. package/dist/api/auth.d.ts.map +1 -0
  6. package/dist/api/auth.js +328 -0
  7. package/dist/api/auth.js.map +1 -0
  8. package/dist/api/client.d.ts +103 -0
  9. package/dist/api/client.d.ts.map +1 -0
  10. package/dist/api/client.js +324 -0
  11. package/dist/api/client.js.map +1 -0
  12. package/dist/api/constants.d.ts +4 -0
  13. package/dist/api/constants.d.ts.map +1 -0
  14. package/dist/api/constants.js +4 -0
  15. package/dist/api/constants.js.map +1 -0
  16. package/dist/api/credential-store.d.ts +38 -0
  17. package/dist/api/credential-store.d.ts.map +1 -0
  18. package/dist/api/credential-store.js +273 -0
  19. package/dist/api/credential-store.js.map +1 -0
  20. package/dist/api/credential-types.d.ts +15 -0
  21. package/dist/api/credential-types.d.ts.map +1 -0
  22. package/dist/api/credential-types.js +11 -0
  23. package/dist/api/credential-types.js.map +1 -0
  24. package/dist/api/endpoints/calendar.d.ts +36 -0
  25. package/dist/api/endpoints/calendar.d.ts.map +1 -0
  26. package/dist/api/endpoints/calendar.js +74 -0
  27. package/dist/api/endpoints/calendar.js.map +1 -0
  28. package/dist/api/endpoints/categories.d.ts +32 -0
  29. package/dist/api/endpoints/categories.d.ts.map +1 -0
  30. package/dist/api/endpoints/categories.js +77 -0
  31. package/dist/api/endpoints/categories.js.map +1 -0
  32. package/dist/api/endpoints/chores.d.ts +50 -0
  33. package/dist/api/endpoints/chores.d.ts.map +1 -0
  34. package/dist/api/endpoints/chores.js +106 -0
  35. package/dist/api/endpoints/chores.js.map +1 -0
  36. package/dist/api/endpoints/devices.d.ts +6 -0
  37. package/dist/api/endpoints/devices.d.ts.map +1 -0
  38. package/dist/api/endpoints/devices.js +10 -0
  39. package/dist/api/endpoints/devices.js.map +1 -0
  40. package/dist/api/endpoints/frames.d.ts +6 -0
  41. package/dist/api/endpoints/frames.d.ts.map +1 -0
  42. package/dist/api/endpoints/frames.js +10 -0
  43. package/dist/api/endpoints/frames.js.map +1 -0
  44. package/dist/api/endpoints/lists.d.ts +55 -0
  45. package/dist/api/endpoints/lists.d.ts.map +1 -0
  46. package/dist/api/endpoints/lists.js +125 -0
  47. package/dist/api/endpoints/lists.js.map +1 -0
  48. package/dist/api/endpoints/meals.d.ts +154 -0
  49. package/dist/api/endpoints/meals.d.ts.map +1 -0
  50. package/dist/api/endpoints/meals.js +194 -0
  51. package/dist/api/endpoints/meals.js.map +1 -0
  52. package/dist/api/endpoints/messages.d.ts +98 -0
  53. package/dist/api/endpoints/messages.d.ts.map +1 -0
  54. package/dist/api/endpoints/messages.js +116 -0
  55. package/dist/api/endpoints/messages.js.map +1 -0
  56. package/dist/api/endpoints/misc.d.ts +27 -0
  57. package/dist/api/endpoints/misc.d.ts.map +1 -0
  58. package/dist/api/endpoints/misc.js +19 -0
  59. package/dist/api/endpoints/misc.js.map +1 -0
  60. package/dist/api/endpoints/photos.d.ts +13 -0
  61. package/dist/api/endpoints/photos.d.ts.map +1 -0
  62. package/dist/api/endpoints/photos.js +10 -0
  63. package/dist/api/endpoints/photos.js.map +1 -0
  64. package/dist/api/endpoints/rewards.d.ts +49 -0
  65. package/dist/api/endpoints/rewards.d.ts.map +1 -0
  66. package/dist/api/endpoints/rewards.js +106 -0
  67. package/dist/api/endpoints/rewards.js.map +1 -0
  68. package/dist/api/endpoints/shape.d.ts +11 -0
  69. package/dist/api/endpoints/shape.d.ts.map +1 -0
  70. package/dist/api/endpoints/shape.js +34 -0
  71. package/dist/api/endpoints/shape.js.map +1 -0
  72. package/dist/api/endpoints/taskbox.d.ts +13 -0
  73. package/dist/api/endpoints/taskbox.d.ts.map +1 -0
  74. package/dist/api/endpoints/taskbox.js +22 -0
  75. package/dist/api/endpoints/taskbox.js.map +1 -0
  76. package/dist/api/oauth.d.ts +62 -0
  77. package/dist/api/oauth.d.ts.map +1 -0
  78. package/dist/api/oauth.js +206 -0
  79. package/dist/api/oauth.js.map +1 -0
  80. package/dist/api/types.d.ts +277 -0
  81. package/dist/api/types.d.ts.map +1 -0
  82. package/dist/api/types.js +5 -0
  83. package/dist/api/types.js.map +1 -0
  84. package/dist/cli.d.ts +23 -0
  85. package/dist/cli.d.ts.map +1 -0
  86. package/dist/cli.js +105 -0
  87. package/dist/cli.js.map +1 -0
  88. package/dist/config.d.ts +27 -0
  89. package/dist/config.d.ts.map +1 -0
  90. package/dist/config.js +78 -0
  91. package/dist/config.js.map +1 -0
  92. package/dist/context.d.ts +17 -0
  93. package/dist/context.d.ts.map +1 -0
  94. package/dist/context.js +17 -0
  95. package/dist/context.js.map +1 -0
  96. package/dist/doctor.d.ts +19 -0
  97. package/dist/doctor.d.ts.map +1 -0
  98. package/dist/doctor.js +109 -0
  99. package/dist/doctor.js.map +1 -0
  100. package/dist/index.d.ts +3 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +24 -0
  103. package/dist/index.js.map +1 -0
  104. package/dist/server.d.ts +7 -0
  105. package/dist/server.d.ts.map +1 -0
  106. package/dist/server.js +29 -0
  107. package/dist/server.js.map +1 -0
  108. package/dist/tools/calendar.d.ts +3 -0
  109. package/dist/tools/calendar.d.ts.map +1 -0
  110. package/dist/tools/calendar.js +298 -0
  111. package/dist/tools/calendar.js.map +1 -0
  112. package/dist/tools/chores.d.ts +3 -0
  113. package/dist/tools/chores.d.ts.map +1 -0
  114. package/dist/tools/chores.js +349 -0
  115. package/dist/tools/chores.js.map +1 -0
  116. package/dist/tools/family.d.ts +3 -0
  117. package/dist/tools/family.d.ts.map +1 -0
  118. package/dist/tools/family.js +182 -0
  119. package/dist/tools/family.js.map +1 -0
  120. package/dist/tools/lists.d.ts +3 -0
  121. package/dist/tools/lists.d.ts.map +1 -0
  122. package/dist/tools/lists.js +481 -0
  123. package/dist/tools/lists.js.map +1 -0
  124. package/dist/tools/meals.d.ts +3 -0
  125. package/dist/tools/meals.d.ts.map +1 -0
  126. package/dist/tools/meals.js +491 -0
  127. package/dist/tools/meals.js.map +1 -0
  128. package/dist/tools/messages.d.ts +3 -0
  129. package/dist/tools/messages.d.ts.map +1 -0
  130. package/dist/tools/messages.js +195 -0
  131. package/dist/tools/messages.js.map +1 -0
  132. package/dist/tools/misc.d.ts +3 -0
  133. package/dist/tools/misc.d.ts.map +1 -0
  134. package/dist/tools/misc.js +102 -0
  135. package/dist/tools/misc.js.map +1 -0
  136. package/dist/tools/photos.d.ts +3 -0
  137. package/dist/tools/photos.d.ts.map +1 -0
  138. package/dist/tools/photos.js +42 -0
  139. package/dist/tools/photos.js.map +1 -0
  140. package/dist/tools/planning.d.ts +15 -0
  141. package/dist/tools/planning.d.ts.map +1 -0
  142. package/dist/tools/planning.js +303 -0
  143. package/dist/tools/planning.js.map +1 -0
  144. package/dist/tools/registry.d.ts +39 -0
  145. package/dist/tools/registry.d.ts.map +1 -0
  146. package/dist/tools/registry.js +142 -0
  147. package/dist/tools/registry.js.map +1 -0
  148. package/dist/tools/rewards.d.ts +3 -0
  149. package/dist/tools/rewards.d.ts.map +1 -0
  150. package/dist/tools/rewards.js +339 -0
  151. package/dist/tools/rewards.js.map +1 -0
  152. package/dist/tools/tasks.d.ts +3 -0
  153. package/dist/tools/tasks.d.ts.map +1 -0
  154. package/dist/tools/tasks.js +68 -0
  155. package/dist/tools/tasks.js.map +1 -0
  156. package/dist/utils/dates.d.ts +26 -0
  157. package/dist/utils/dates.d.ts.map +1 -0
  158. package/dist/utils/dates.js +109 -0
  159. package/dist/utils/dates.js.map +1 -0
  160. package/dist/utils/errors.d.ts +45 -0
  161. package/dist/utils/errors.d.ts.map +1 -0
  162. package/dist/utils/errors.js +102 -0
  163. package/dist/utils/errors.js.map +1 -0
  164. package/dist/utils/schedule.d.ts +86 -0
  165. package/dist/utils/schedule.d.ts.map +1 -0
  166. package/dist/utils/schedule.js +189 -0
  167. package/dist/utils/schedule.js.map +1 -0
  168. package/package.json +76 -4
@@ -0,0 +1,195 @@
1
+ import { z } from "zod";
2
+ import { assertNudgeId, createNudge, deleteNudge, findNudge, getNudges, updateNudge } from "../api/endpoints/messages.js";
3
+ import { getCategories, findCategoryByName, resolveProfileIds } from "../api/endpoints/categories.js";
4
+ import { getConfig } from "../config.js";
5
+ import { parseDate, getDateOffset } from "../utils/dates.js";
6
+ import { dateInZone, formatDay, formatTime } from "../utils/schedule.js";
7
+ import { formatErrorForMcp } from "../utils/errors.js";
8
+ export function registerMessageTools(server) {
9
+ server.tool("get_messages", `Get messages (Skylight calls them "nudges") shown on the family frame.
10
+
11
+ Use this when:
12
+ - Checking what has already been posted to the frame
13
+ - Avoiding a duplicate before sending a reminder
14
+
15
+ Returns: Messages grouped by day with time, text, recipients and sender.
16
+ Defaults to the last 7 days through the next 7 days. Max 31 days.`, {
17
+ date: z.string().optional().describe("Start date (YYYY-MM-DD or 'today'). Default: 7 days ago."),
18
+ dateEnd: z.string().optional().describe("End date, inclusive. Default: 7 days ahead."),
19
+ }, async ({ date, dateEnd }) => {
20
+ try {
21
+ const { timezone } = getConfig();
22
+ const start = date ? parseDate(date, timezone) : getDateOffset(-7, timezone);
23
+ const end = dateEnd ? parseDate(dateEnd, timezone) : getDateOffset(7, timezone);
24
+ if (end < start)
25
+ throw new Error("dateEnd is before date.");
26
+ const days = (Date.parse(end) - Date.parse(start)) / 86_400_000 + 1;
27
+ if (days > 31)
28
+ throw new Error("Range is limited to 31 days.");
29
+ const [nudges, categories] = await Promise.all([
30
+ getNudges(start, end, timezone),
31
+ getCategories().catch(() => []),
32
+ ]);
33
+ const names = new Map(categories.map((c) => [c.id, c.attributes.label ?? `profile ${c.id}`]));
34
+ if (nudges.length === 0) {
35
+ return { content: [{ type: "text", text: `No messages from ${start} to ${end}.` }] };
36
+ }
37
+ const sorted = [...nudges].sort((a, b) => Date.parse(a.attributes.deliver_at ?? "") - Date.parse(b.attributes.deliver_at ?? ""));
38
+ const byDay = new Map();
39
+ for (const n of sorted) {
40
+ const at = Date.parse(n.attributes.deliver_at ?? "");
41
+ if (Number.isNaN(at))
42
+ continue;
43
+ const day = dateInZone(at, timezone);
44
+ const line = `- ${formatTime(at, timezone)}: "${n.attributes.body ?? ""}"${describeRoute(n, names)} [message ID: ${n.id}]`;
45
+ byDay.set(day, [...(byDay.get(day) ?? []), line]);
46
+ }
47
+ const text = [...byDay.entries()].map(([d, lines]) => `${formatDay(d)}\n${lines.join("\n")}`).join("\n\n");
48
+ return { content: [{ type: "text", text: `Messages ${start} to ${end}:\n\n${text}` }] };
49
+ }
50
+ catch (error) {
51
+ return { content: [{ type: "text", text: formatErrorForMcp(error) }], isError: true };
52
+ }
53
+ });
54
+ server.tool("send_message", `Post a message to the family frame now, on all devices. Shown to everyone unless "to" names profiles.
55
+
56
+ PERMANENT in practice: the Skylight app has no way to delete a message (delete_message
57
+ is experimental), and it appears on the family frame for the whole
58
+ household immediately.
59
+
60
+ Two-step by design. Called without confirm it only previews and posts nothing.
61
+ Show the user the exact text and get a clear yes, then call again with confirm: true.
62
+ Never pass confirm: true on the first call, and never invent message text the user
63
+ did not ask for. Read aloud is OFF by default; enable it only if the user asked.
64
+
65
+ Check get_messages first to avoid posting a duplicate.`, {
66
+ body: z.string().min(1).max(300).describe("Message text, up to 300 characters."),
67
+ readAloud: z.boolean().optional().describe("Speak the message on the frame when delivered. Default false."),
68
+ from: z.string().optional().describe("Optional sender profile name, e.g. a family member. Omit for no sender."),
69
+ to: z.array(z.string()).optional().describe("Profile names to send to (see get_family_members), e.g. [\"Jordan\"]. Omit to send to everyone."),
70
+ confirm: z.boolean().optional().describe("Must be true to actually post. Default false: preview only."),
71
+ }, async ({ body, readAloud, from, to, confirm }) => {
72
+ try {
73
+ const text = body.trim();
74
+ if (!text)
75
+ throw new Error("Message is empty.");
76
+ const recipients = to && to.length > 0 ? await resolveProfileIds(to) : undefined;
77
+ const audience = recipients ? recipients.labels.join(", ") : "everyone";
78
+ let senderCategoryId;
79
+ if (from) {
80
+ const match = await findCategoryByName(from);
81
+ if (!match) {
82
+ const known = (await getCategories()).map((c) => c.attributes.label).filter(Boolean).join(", ");
83
+ throw new Error(`No profile called "${from}". Profiles: ${known}.`);
84
+ }
85
+ senderCategoryId = match.id;
86
+ }
87
+ const who = senderCategoryId ? ` from ${from}` : "";
88
+ if (confirm !== true) {
89
+ return {
90
+ content: [
91
+ {
92
+ type: "text",
93
+ text: `NOT SENT. Preview: would post to ${audience} on all devices${who}${readAloud ? ", read aloud" : ", silent"}: "${text}"\n\nDeleting a message afterwards is experimental. If the user approves this exact text, call send_message again with confirm: true.`,
94
+ },
95
+ ],
96
+ };
97
+ }
98
+ const sent = await createNudge({ body: text, readAloud: readAloud === true, senderCategoryId, recipientCategoryIds: recipients?.ids, timeZone: getConfig().timezone });
99
+ const id = sent?.id ? ` [message ID: ${sent.id}]` : "";
100
+ return {
101
+ content: [{ type: "text", text: `Posted to the frame${recipients ? ` for ${audience}` : ""}${who}${readAloud ? " (read aloud)" : ""}: "${text}"${id}` }],
102
+ };
103
+ }
104
+ catch (error) {
105
+ return { content: [{ type: "text", text: formatErrorForMcp(error) }], isError: true };
106
+ }
107
+ });
108
+ server.tool("update_message", `Edit the text (and optionally the sender) of a message already on the frame.
109
+
110
+ Only messages sent to everyone on all devices and not repeating can be edited;
111
+ anything else must be edited in the Skylight app. Delivery time and read-aloud
112
+ setting are kept. The edit is visible on the frame immediately. Get the message
113
+ ID from get_messages (looks within 31 days either side of today).`, {
114
+ messageId: z.string().describe("Numeric message ID from get_messages."),
115
+ body: z.string().min(1).max(300).describe("New message text, up to 300 characters."),
116
+ from: z.string().optional().describe("Optional new sender profile name. Omit to keep the current sender."),
117
+ }, async ({ messageId, body, from }) => {
118
+ try {
119
+ const id = assertNudgeId(messageId.trim());
120
+ const text = body.trim();
121
+ if (!text)
122
+ throw new Error("Message is empty.");
123
+ const { timezone } = getConfig();
124
+ const existing = await findNudge(id, timezone);
125
+ if (!existing)
126
+ throw new Error(`No message with ID ${id} within 31 days of today.`);
127
+ let senderCategoryId;
128
+ if (from) {
129
+ const match = await findCategoryByName(from);
130
+ if (!match) {
131
+ const known = (await getCategories()).map((c) => c.attributes.label).filter(Boolean).join(", ");
132
+ throw new Error(`No profile called "${from}". Profiles: ${known}.`);
133
+ }
134
+ senderCategoryId = match.id;
135
+ }
136
+ await updateNudge({ existing, body: text, senderCategoryId, timeZone: timezone });
137
+ return { content: [{ type: "text", text: `Updated message ${id}: "${text}"` }] };
138
+ }
139
+ catch (error) {
140
+ return { content: [{ type: "text", text: formatErrorForMcp(error) }], isError: true };
141
+ }
142
+ });
143
+ server.tool("delete_message", `EXPERIMENTAL: delete a message from the family frame.
144
+
145
+ The Skylight app has no delete button for messages. This calls the delete endpoint
146
+ that other Skylight clients use; it is unverified on this account until tested, so a
147
+ failure is expected to be reported plainly, not retried.
148
+
149
+ Two-step. Without confirm it only previews which message would go. Show the user the
150
+ text and get a clear yes before calling with confirm: true. After deleting it reads the
151
+ message list back and reports whether the message is really gone. Get the ID from
152
+ get_messages (looks within 31 days either side of today).`, {
153
+ messageId: z.string().describe("Numeric message ID from get_messages."),
154
+ confirm: z.boolean().optional().describe("Must be true to actually delete. Default false: preview only."),
155
+ }, async ({ messageId, confirm }) => {
156
+ try {
157
+ const id = assertNudgeId(messageId.trim());
158
+ const { timezone } = getConfig();
159
+ const existing = await findNudge(id, timezone);
160
+ if (!existing)
161
+ throw new Error(`No message with ID ${id} within 31 days of today.`);
162
+ const text = existing.attributes.body ?? "";
163
+ if (confirm !== true) {
164
+ return {
165
+ content: [
166
+ {
167
+ type: "text",
168
+ text: `NOT DELETED. This would delete message ${id}: "${text}"${existing.attributes.recurring ? " (it repeats; the whole series would go)" : ""}.\n\nIf the user approves, call delete_message again with confirm: true.`,
169
+ },
170
+ ],
171
+ };
172
+ }
173
+ await deleteNudge(existing);
174
+ const still = await findNudge(id, timezone);
175
+ if (still) {
176
+ throw new Error(`Skylight accepted the delete call but message ${id} is still listed. Do not assume it is gone; check the app.`);
177
+ }
178
+ return { content: [{ type: "text", text: `Deleted message ${id}: "${text}". Confirmed gone from the message list.` }] };
179
+ }
180
+ catch (error) {
181
+ return { content: [{ type: "text", text: formatErrorForMcp(error) }], isError: true };
182
+ }
183
+ });
184
+ }
185
+ function describeRoute(n, names) {
186
+ const a = n.attributes;
187
+ const rel = n.relationships;
188
+ const to = a.all_profiles
189
+ ? "everyone"
190
+ : (rel?.categories?.data ?? []).map((c) => names.get(c.id) ?? `profile ${c.id}`).join(", ");
191
+ const from = rel?.sender_category?.data ? names.get(rel.sender_category.data.id) : undefined;
192
+ const parts = [to ? `to ${to}` : "", from ? `from ${from}` : "", a.recurring ? "recurring" : "", a.all_devices ? "" : "selected devices"].filter(Boolean);
193
+ return parts.length ? ` (${parts.join(", ")})` : "";
194
+ }
195
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/tools/messages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerMiscTools(server: McpServer): void;
3
+ //# sourceMappingURL=misc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"misc.d.ts","sourceRoot":"","sources":["../../src/tools/misc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgHzD"}
@@ -0,0 +1,102 @@
1
+ import { getAvatars, getColors } from "../api/endpoints/misc.js";
2
+ import { attributesOf } from "../api/endpoints/shape.js";
3
+ import { formatErrorForMcp } from "../utils/errors.js";
4
+ export function registerMiscTools(server) {
5
+ // get_avatars tool
6
+ server.tool("get_avatars", `Get available avatar options for Skylight profiles.
7
+
8
+ Use this when:
9
+ - Setting up a new family member profile
10
+ - Changing someone's profile picture
11
+ - Exploring available avatar options
12
+
13
+ Returns: List of available avatars with their IDs and details.`, {}, async () => {
14
+ try {
15
+ const avatars = await getAvatars();
16
+ if (avatars.length === 0) {
17
+ return {
18
+ content: [
19
+ {
20
+ type: "text",
21
+ text: "No avatars found.",
22
+ },
23
+ ],
24
+ };
25
+ }
26
+ const avatarList = avatars
27
+ .map((avatar) => {
28
+ const parts = [`- Avatar (ID: ${avatar.id})`];
29
+ for (const [key, value] of Object.entries(avatar.attributes)) {
30
+ if (value !== null && value !== undefined) {
31
+ parts.push(` ${key}: ${value}`);
32
+ }
33
+ }
34
+ return parts.join("\n");
35
+ })
36
+ .join("\n\n");
37
+ return {
38
+ content: [
39
+ {
40
+ type: "text",
41
+ text: `Available avatars:\n\n${avatarList}`,
42
+ },
43
+ ],
44
+ };
45
+ }
46
+ catch (error) {
47
+ return {
48
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
49
+ isError: true,
50
+ };
51
+ }
52
+ });
53
+ // get_colors tool
54
+ server.tool("get_colors", `Get available color options for Skylight profiles and lists.
55
+
56
+ Use this when:
57
+ - Choosing a color for a family member profile
58
+ - Setting a list color
59
+ - Exploring available color options
60
+
61
+ Returns: List of available colors with their IDs and hex values.`, {}, async () => {
62
+ try {
63
+ const colors = await getColors();
64
+ if (colors.length === 0) {
65
+ return {
66
+ content: [
67
+ {
68
+ type: "text",
69
+ text: "No colors found.",
70
+ },
71
+ ],
72
+ };
73
+ }
74
+ const colorList = colors
75
+ .map((color) => {
76
+ const parts = [`- Color (ID: ${color.id})`];
77
+ for (const [key, value] of Object.entries(attributesOf(color))) {
78
+ if (value !== null && value !== undefined) {
79
+ parts.push(` ${key}: ${value}`);
80
+ }
81
+ }
82
+ return parts.join("\n");
83
+ })
84
+ .join("\n\n");
85
+ return {
86
+ content: [
87
+ {
88
+ type: "text",
89
+ text: `Available colors:\n\n${colorList}`,
90
+ },
91
+ ],
92
+ };
93
+ }
94
+ catch (error) {
95
+ return {
96
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
97
+ isError: true,
98
+ };
99
+ }
100
+ });
101
+ }
102
+ //# sourceMappingURL=misc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"misc.js","sourceRoot":"","sources":["../../src/tools/misc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerPhotoTools(server: McpServer): void;
3
+ //# sourceMappingURL=photos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"photos.d.ts","sourceRoot":"","sources":["../../src/tools/photos.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6C1D"}
@@ -0,0 +1,42 @@
1
+ import { getAlbums } from "../api/endpoints/photos.js";
2
+ import { formatErrorForMcp } from "../utils/errors.js";
3
+ export function registerPhotoTools(server) {
4
+ // get_albums tool
5
+ server.tool("get_albums", `Get photo albums from Skylight - Plus subscription required.
6
+
7
+ Use this when:
8
+ - Viewing available photo albums
9
+ - Getting album IDs for photo management
10
+
11
+ Returns: List of photo albums with their IDs.`, {}, async () => {
12
+ try {
13
+ const albums = await getAlbums();
14
+ if (albums.length === 0) {
15
+ return {
16
+ content: [{ type: "text", text: "No photo albums found." }],
17
+ };
18
+ }
19
+ const list = albums
20
+ .map((album) => {
21
+ const parts = [`- ${album.attributes.name ?? "Untitled Album"} (ID: ${album.id})`];
22
+ for (const [key, value] of Object.entries(album.attributes)) {
23
+ if (value !== null && value !== undefined && key !== "name") {
24
+ parts.push(` ${key}: ${value}`);
25
+ }
26
+ }
27
+ return parts.join("\n");
28
+ })
29
+ .join("\n\n");
30
+ return {
31
+ content: [{ type: "text", text: `Photo albums:\n\n${list}` }],
32
+ };
33
+ }
34
+ catch (error) {
35
+ return {
36
+ content: [{ type: "text", text: formatErrorForMcp(error) }],
37
+ isError: true,
38
+ };
39
+ }
40
+ });
41
+ }
42
+ //# sourceMappingURL=photos.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"photos.js","sourceRoot":"","sources":["../../src/tools/photos.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,kBAAkB;IAClB,MAAM,CAAC,IAAI,CACT,YAAY,EACZ;;;;;;8CAM0C,EAC1C,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAC;YAEjC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,wBAAwB,EAAE,CAAC;iBACrE,CAAC;YACJ,CAAC;YAED,MAAM,IAAI,GAAG,MAAM;iBAChB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;gBACb,MAAM,KAAK,GAAG,CAAC,KAAK,KAAK,CAAC,UAAU,CAAC,IAAI,IAAI,gBAAgB,SAAS,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;gBACnF,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC5D,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;wBAC5D,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,KAAK,EAAE,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;gBACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC,CAAC;iBACD,IAAI,CAAC,MAAM,CAAC,CAAC;YAEhB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,oBAAoB,IAAI,EAAE,EAAE,CAAC;aACvE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Planning tools: the ones a proactive assistant (Claude Duet) needs to
3
+ * reason about a family week in one or two calls instead of five.
4
+ *
5
+ * get_week_overview calendar + chores + meals + lists, day by day, compact
6
+ * find_conflicts overlapping timed events
7
+ * find_free_slots gaps of at least N minutes within a daily window
8
+ * plan_week_meals write several meal sittings in one call, with dry run
9
+ *
10
+ * Output deliberately omits emails, calendar ids and UIDs: they are noise for
11
+ * the model and personal data in every transcript.
12
+ */
13
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
14
+ export declare function registerPlanningTools(server: McpServer): void;
15
+ //# sourceMappingURL=planning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../../src/tools/planning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAoEzE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0P7D"}