@bmhall2/skylight-mcp 1.1.7 → 1.1.8

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.
@@ -5,12 +5,12 @@ import { formatErrorForMcp } from "../utils/errors.js";
5
5
  import { getConfig } from "../config.js";
6
6
  export function registerMealTools(server) {
7
7
  // get_meal_categories tool
8
- server.tool("get_meal_categories", `Get meal categories (Breakfast, Lunch, Dinner, etc.) - Plus subscription required.
9
-
10
- Use this when:
11
- - Finding category IDs for scheduling meals
12
- - Seeing what meal times are available
13
-
8
+ server.tool("get_meal_categories", `Get meal categories (Breakfast, Lunch, Dinner, etc.) - Plus subscription required.
9
+
10
+ Use this when:
11
+ - Finding category IDs for scheduling meals
12
+ - Seeing what meal times are available
13
+
14
14
  Returns: List of meal categories with IDs.`, {}, async () => {
15
15
  try {
16
16
  const categories = await getMealCategories();
@@ -34,12 +34,12 @@ Returns: List of meal categories with IDs.`, {}, async () => {
34
34
  }
35
35
  });
36
36
  // get_recipes tool
37
- server.tool("get_recipes", `Get all saved recipes - Plus subscription required.
38
-
39
- Use this when:
40
- - Browsing available recipes
41
- - Finding a recipe ID for meal planning
42
-
37
+ server.tool("get_recipes", `Get all saved recipes - Plus subscription required.
38
+
39
+ Use this when:
40
+ - Browsing available recipes
41
+ - Finding a recipe ID for meal planning
42
+
43
43
  Returns: List of recipes with their details.`, {}, async () => {
44
44
  try {
45
45
  const recipes = await getRecipes();
@@ -69,11 +69,11 @@ Returns: List of recipes with their details.`, {}, async () => {
69
69
  }
70
70
  });
71
71
  // get_recipe tool
72
- server.tool("get_recipe", `Get details for a specific recipe - Plus subscription required.
73
-
74
- Parameters:
75
- - recipeId (required): ID of the recipe
76
-
72
+ server.tool("get_recipe", `Get details for a specific recipe - Plus subscription required.
73
+
74
+ Parameters:
75
+ - recipeId (required): ID of the recipe
76
+
77
77
  Returns: Recipe details including description.`, {
78
78
  recipeId: z.string().describe("ID of the recipe"),
79
79
  }, async ({ recipeId }) => {
@@ -97,17 +97,17 @@ Returns: Recipe details including description.`, {
97
97
  }
98
98
  });
99
99
  // create_recipe tool
100
- server.tool("create_recipe", `Create a new recipe - Plus subscription required.
101
-
102
- Use this when:
103
- - Adding a new family recipe
104
- - Saving a meal for meal planning
105
-
106
- Parameters:
107
- - summary (required): Recipe name
108
- - description: Recipe details or instructions
109
- - mealCategoryId: Category ID (use get_meal_categories)
110
-
100
+ server.tool("create_recipe", `Create a new recipe - Plus subscription required.
101
+
102
+ Use this when:
103
+ - Adding a new family recipe
104
+ - Saving a meal for meal planning
105
+
106
+ Parameters:
107
+ - summary (required): Recipe name
108
+ - description: Recipe details or instructions
109
+ - mealCategoryId: Category ID (use get_meal_categories)
110
+
111
111
  Returns: The created recipe.`, {
112
112
  summary: z.string().describe("Recipe name (e.g., 'Spaghetti Bolognese')"),
113
113
  description: z.string().optional().describe("Recipe details or instructions"),
@@ -132,13 +132,13 @@ Returns: The created recipe.`, {
132
132
  }
133
133
  });
134
134
  // update_recipe tool
135
- server.tool("update_recipe", `Update an existing recipe - Plus subscription required.
136
-
137
- Parameters:
138
- - recipeId (required): ID of the recipe
139
- - summary: New name
140
- - description: New description
141
-
135
+ server.tool("update_recipe", `Update an existing recipe - Plus subscription required.
136
+
137
+ Parameters:
138
+ - recipeId (required): ID of the recipe
139
+ - summary: New name
140
+ - description: New description
141
+
142
142
  Returns: The updated recipe.`, {
143
143
  recipeId: z.string().describe("ID of the recipe to update"),
144
144
  summary: z.string().optional().describe("New recipe name"),
@@ -168,11 +168,11 @@ Returns: The updated recipe.`, {
168
168
  }
169
169
  });
170
170
  // delete_recipe tool
171
- server.tool("delete_recipe", `Delete a recipe - Plus subscription required.
172
-
173
- Parameters:
174
- - recipeId (required): ID of the recipe to delete
175
-
171
+ server.tool("delete_recipe", `Delete a recipe - Plus subscription required.
172
+
173
+ Parameters:
174
+ - recipeId (required): ID of the recipe to delete
175
+
176
176
  Note: This permanently removes the recipe.`, {
177
177
  recipeId: z.string().describe("ID of the recipe to delete"),
178
178
  }, async ({ recipeId }) => {
@@ -190,15 +190,15 @@ Note: This permanently removes the recipe.`, {
190
190
  }
191
191
  });
192
192
  // add_recipe_to_grocery_list tool
193
- server.tool("add_recipe_to_grocery_list", `Add a recipe's ingredients to the grocery list - Plus subscription required.
194
-
195
- Use this when:
196
- - Planning to make a recipe and need to buy ingredients
197
- - Adding meal ingredients to shopping list
198
-
199
- Parameters:
200
- - recipeId (required): ID of the recipe
201
-
193
+ server.tool("add_recipe_to_grocery_list", `Add a recipe's ingredients to the grocery list - Plus subscription required.
194
+
195
+ Use this when:
196
+ - Planning to make a recipe and need to buy ingredients
197
+ - Adding meal ingredients to shopping list
198
+
199
+ Parameters:
200
+ - recipeId (required): ID of the recipe
201
+
202
202
  Returns: Confirmation that ingredients were added.`, {
203
203
  recipeId: z.string().describe("ID of the recipe"),
204
204
  }, async ({ recipeId }) => {
@@ -221,16 +221,16 @@ Returns: Confirmation that ingredients were added.`, {
221
221
  }
222
222
  });
223
223
  // get_meal_sittings tool
224
- server.tool("get_meal_sittings", `Get scheduled meals for a date range - Plus subscription required.
225
-
226
- Use this when:
227
- - Viewing the meal plan for the week
228
- - Checking what's scheduled for dinner
229
-
230
- Parameters:
231
- - date: Start date (defaults to today)
232
- - dateEnd: End date (defaults to 7 days from start)
233
-
224
+ server.tool("get_meal_sittings", `Get scheduled meals for a date range - Plus subscription required.
225
+
226
+ Use this when:
227
+ - Viewing the meal plan for the week
228
+ - Checking what's scheduled for dinner
229
+
230
+ Parameters:
231
+ - date: Start date (defaults to today)
232
+ - dateEnd: End date (defaults to 7 days from start)
233
+
234
234
  Returns: List of scheduled meals.`, {
235
235
  date: z.string().optional().describe("Start date (YYYY-MM-DD or 'today')"),
236
236
  dateEnd: z.string().optional().describe("End date (YYYY-MM-DD)"),
@@ -275,17 +275,17 @@ Returns: List of scheduled meals.`, {
275
275
  }
276
276
  });
277
277
  // create_meal_sitting tool
278
- server.tool("create_meal_sitting", `Schedule a meal for a specific date - Plus subscription required.
279
-
280
- Use this when:
281
- - Planning meals for the week
282
- - Scheduling a recipe for dinner
283
-
284
- Parameters:
285
- - date (required): Date for the meal (YYYY-MM-DD)
286
- - mealCategoryId (required): Meal category ID (use get_meal_categories)
287
- - recipeId: Recipe ID to schedule (optional)
288
-
278
+ server.tool("create_meal_sitting", `Schedule a meal for a specific date - Plus subscription required.
279
+
280
+ Use this when:
281
+ - Planning meals for the week
282
+ - Scheduling a recipe for dinner
283
+
284
+ Parameters:
285
+ - date (required): Date for the meal (YYYY-MM-DD)
286
+ - mealCategoryId (required): Meal category ID (use get_meal_categories)
287
+ - recipeId: Recipe ID to schedule (optional)
288
+
289
289
  Returns: The created meal sitting.`, {
290
290
  date: z.string().describe("Date for the meal (YYYY-MM-DD or 'today', 'tomorrow')"),
291
291
  mealCategoryId: z.string().describe("Meal category ID (e.g., ID for 'Dinner')"),
@@ -2,13 +2,13 @@ import { getAvatars, getColors } from "../api/endpoints/misc.js";
2
2
  import { formatErrorForMcp } from "../utils/errors.js";
3
3
  export function registerMiscTools(server) {
4
4
  // get_avatars tool
5
- server.tool("get_avatars", `Get available avatar options for Skylight profiles.
6
-
7
- Use this when:
8
- - Setting up a new family member profile
9
- - Changing someone's profile picture
10
- - Exploring available avatar options
11
-
5
+ server.tool("get_avatars", `Get available avatar options for Skylight profiles.
6
+
7
+ Use this when:
8
+ - Setting up a new family member profile
9
+ - Changing someone's profile picture
10
+ - Exploring available avatar options
11
+
12
12
  Returns: List of available avatars with their IDs and details.`, {}, async () => {
13
13
  try {
14
14
  const avatars = await getAvatars();
@@ -50,13 +50,13 @@ Returns: List of available avatars with their IDs and details.`, {}, async () =>
50
50
  }
51
51
  });
52
52
  // get_colors tool
53
- server.tool("get_colors", `Get available color options for Skylight profiles and lists.
54
-
55
- Use this when:
56
- - Choosing a color for a family member profile
57
- - Setting a list color
58
- - Exploring available color options
59
-
53
+ server.tool("get_colors", `Get available color options for Skylight profiles and lists.
54
+
55
+ Use this when:
56
+ - Choosing a color for a family member profile
57
+ - Setting a list color
58
+ - Exploring available color options
59
+
60
60
  Returns: List of available colors with their IDs and hex values.`, {}, async () => {
61
61
  try {
62
62
  const colors = await getColors();
@@ -2,12 +2,12 @@ import { getAlbums } from "../api/endpoints/photos.js";
2
2
  import { formatErrorForMcp } from "../utils/errors.js";
3
3
  export function registerPhotoTools(server) {
4
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
-
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
11
  Returns: List of photo albums with their IDs.`, {}, async () => {
12
12
  try {
13
13
  const albums = await getAlbums();
@@ -4,13 +4,13 @@ import { findCategoryByName } from "../api/endpoints/categories.js";
4
4
  import { formatErrorForMcp } from "../utils/errors.js";
5
5
  export function registerRewardTools(server) {
6
6
  // get_rewards tool
7
- server.tool("get_rewards", `Get available rewards that can be redeemed with reward points.
8
-
9
- For family gamification - shows rewards that family members can earn.
10
-
11
- Use this to answer:
12
- - "What rewards can we redeem?"
13
- - "What can the kids earn?"
7
+ server.tool("get_rewards", `Get available rewards that can be redeemed with reward points.
8
+
9
+ For family gamification - shows rewards that family members can earn.
10
+
11
+ Use this to answer:
12
+ - "What rewards can we redeem?"
13
+ - "What can the kids earn?"
14
14
  - "Show available rewards"`, {
15
15
  redeemedSince: z
16
16
  .string()
@@ -65,13 +65,13 @@ Use this to answer:
65
65
  }
66
66
  });
67
67
  // get_reward_points tool
68
- server.tool("get_reward_points", `Get reward points balance for family members.
69
-
70
- Shows how many reward points each family member has earned.
71
-
72
- Use this to answer:
73
- - "How many points does [name] have?"
74
- - "Show reward points balance"
68
+ server.tool("get_reward_points", `Get reward points balance for family members.
69
+
70
+ Shows how many reward points each family member has earned.
71
+
72
+ Use this to answer:
73
+ - "How many points does [name] have?"
74
+ - "Show reward points balance"
75
75
  - "Who has the most points?"`, {}, async () => {
76
76
  try {
77
77
  const points = await getRewardPoints();
@@ -119,20 +119,20 @@ Use this to answer:
119
119
  }
120
120
  });
121
121
  // create_reward tool
122
- server.tool("create_reward", `Create a new reward that can be redeemed with points (Plus subscription required).
123
-
124
- Use this when:
125
- - Adding a new reward: "Create a reward for 30 minutes of screen time"
126
- - Setting up family incentives: "Add a pizza night reward worth 100 points"
127
-
128
- Parameters:
129
- - name (required): Reward name (e.g., "30 min Screen Time")
130
- - pointValue (required): Points needed to redeem this reward
131
- - description: Additional details about the reward
132
- - emojiIcon: Emoji to display with the reward
133
- - assignee: Family member name to assign this reward to
134
- - respawnOnRedemption: If true, reward can be redeemed multiple times
135
-
122
+ server.tool("create_reward", `Create a new reward that can be redeemed with points (Plus subscription required).
123
+
124
+ Use this when:
125
+ - Adding a new reward: "Create a reward for 30 minutes of screen time"
126
+ - Setting up family incentives: "Add a pizza night reward worth 100 points"
127
+
128
+ Parameters:
129
+ - name (required): Reward name (e.g., "30 min Screen Time")
130
+ - pointValue (required): Points needed to redeem this reward
131
+ - description: Additional details about the reward
132
+ - emojiIcon: Emoji to display with the reward
133
+ - assignee: Family member name to assign this reward to
134
+ - respawnOnRedemption: If true, reward can be redeemed multiple times
135
+
136
136
  Returns: The created reward details.`, {
137
137
  name: z.string().describe("Reward name (e.g., '30 min Screen Time')"),
138
138
  pointValue: z.number().describe("Points needed to redeem this reward"),
@@ -178,19 +178,19 @@ Returns: The created reward details.`, {
178
178
  }
179
179
  });
180
180
  // update_reward tool
181
- server.tool("update_reward", `Update an existing reward (Plus subscription required).
182
-
183
- Use this when:
184
- - Changing point value: "Make the screen time reward cost 50 points"
185
- - Updating reward details: "Add a description to the pizza reward"
186
-
187
- Parameters:
188
- - rewardId (required): ID of the reward (from get_rewards)
189
- - name: New reward name
190
- - pointValue: New point cost
191
- - description: Updated description
192
- - emojiIcon: Updated emoji
193
-
181
+ server.tool("update_reward", `Update an existing reward (Plus subscription required).
182
+
183
+ Use this when:
184
+ - Changing point value: "Make the screen time reward cost 50 points"
185
+ - Updating reward details: "Add a description to the pizza reward"
186
+
187
+ Parameters:
188
+ - rewardId (required): ID of the reward (from get_rewards)
189
+ - name: New reward name
190
+ - pointValue: New point cost
191
+ - description: Updated description
192
+ - emojiIcon: Updated emoji
193
+
194
194
  Returns: The updated reward details.`, {
195
195
  rewardId: z.string().describe("ID of the reward to update"),
196
196
  name: z.string().optional().describe("New reward name"),
@@ -229,15 +229,15 @@ Returns: The updated reward details.`, {
229
229
  }
230
230
  });
231
231
  // delete_reward tool
232
- server.tool("delete_reward", `Delete a reward (Plus subscription required).
233
-
234
- Use this when:
235
- - Removing an old reward
236
- - Cleaning up unused rewards
237
-
238
- Parameters:
239
- - rewardId (required): ID of the reward to delete (from get_rewards)
240
-
232
+ server.tool("delete_reward", `Delete a reward (Plus subscription required).
233
+
234
+ Use this when:
235
+ - Removing an old reward
236
+ - Cleaning up unused rewards
237
+
238
+ Parameters:
239
+ - rewardId (required): ID of the reward to delete (from get_rewards)
240
+
241
241
  Note: This permanently removes the reward.`, {
242
242
  rewardId: z.string().describe("ID of the reward to delete"),
243
243
  }, async ({ rewardId }) => {
@@ -260,16 +260,16 @@ Note: This permanently removes the reward.`, {
260
260
  }
261
261
  });
262
262
  // redeem_reward tool
263
- server.tool("redeem_reward", `Redeem a reward using points (Plus subscription required).
264
-
265
- Use this when:
266
- - A family member wants to cash in points: "Redeem the screen time reward for Johnny"
267
- - Claiming an earned reward
268
-
269
- Parameters:
270
- - rewardId (required): ID of the reward to redeem (from get_rewards)
271
- - assignee: Family member redeeming the reward (uses their points)
272
-
263
+ server.tool("redeem_reward", `Redeem a reward using points (Plus subscription required).
264
+
265
+ Use this when:
266
+ - A family member wants to cash in points: "Redeem the screen time reward for Johnny"
267
+ - Claiming an earned reward
268
+
269
+ Parameters:
270
+ - rewardId (required): ID of the reward to redeem (from get_rewards)
271
+ - assignee: Family member redeeming the reward (uses their points)
272
+
273
273
  Returns: The redeemed reward details.`, {
274
274
  rewardId: z.string().describe("ID of the reward to redeem"),
275
275
  assignee: z.string().optional().describe("Family member redeeming the reward"),
@@ -304,15 +304,15 @@ Returns: The redeemed reward details.`, {
304
304
  }
305
305
  });
306
306
  // unredeem_reward tool
307
- server.tool("unredeem_reward", `Cancel a reward redemption (Plus subscription required).
308
-
309
- Use this when:
310
- - A redemption was made by mistake
311
- - Undoing a reward claim
312
-
313
- Parameters:
314
- - rewardId (required): ID of the reward to unredeem
315
-
307
+ server.tool("unredeem_reward", `Cancel a reward redemption (Plus subscription required).
308
+
309
+ Use this when:
310
+ - A redemption was made by mistake
311
+ - Undoing a reward claim
312
+
313
+ Parameters:
314
+ - rewardId (required): ID of the reward to unredeem
315
+
316
316
  Returns: The unredeemed reward details.`, {
317
317
  rewardId: z.string().describe("ID of the reward to unredeem"),
318
318
  }, async ({ rewardId }) => {
@@ -3,15 +3,15 @@ import { createTaskBoxItem } from "../api/endpoints/taskbox.js";
3
3
  import { formatErrorForMcp } from "../utils/errors.js";
4
4
  export function registerTaskTools(server) {
5
5
  // create_task tool
6
- server.tool("create_task", `Add a task to the Skylight task box.
7
-
8
- The task box holds unscheduled tasks that can later be assigned to specific dates.
9
-
10
- Use this when the user says:
11
- - "Add XYZ to my task list"
12
- - "Remind me to do ABC" (without a specific date)
13
- - "Put 'clean garage' on the task box"
14
-
6
+ server.tool("create_task", `Add a task to the Skylight task box.
7
+
8
+ The task box holds unscheduled tasks that can later be assigned to specific dates.
9
+
10
+ Use this when the user says:
11
+ - "Add XYZ to my task list"
12
+ - "Remind me to do ABC" (without a specific date)
13
+ - "Put 'clean garage' on the task box"
14
+
15
15
  The task will appear on the Skylight display in the task box.`, {
16
16
  summary: z.string().describe("Task description"),
17
17
  emoji: z
@@ -64,31 +64,31 @@ export class ParseError extends SkylightError {
64
64
  */
65
65
  export function formatErrorForMcp(error) {
66
66
  if (error instanceof AuthenticationError) {
67
- return `Authentication Error: ${error.message}
68
-
69
- Your Skylight token may have expired. To fix this:
70
- 1. Open the Skylight app on your device
71
- 2. Capture fresh API traffic using a proxy tool
72
- 3. Update your SKYLIGHT_TOKEN environment variable
73
-
67
+ return `Authentication Error: ${error.message}
68
+
69
+ Your Skylight token may have expired. To fix this:
70
+ 1. Open the Skylight app on your device
71
+ 2. Capture fresh API traffic using a proxy tool
72
+ 3. Update your SKYLIGHT_TOKEN environment variable
73
+
74
74
  See the auth documentation for detailed steps.`;
75
75
  }
76
76
  if (error instanceof NotFoundError) {
77
- return `Not Found: ${error.message}
78
-
79
- This could mean:
80
- - The requested item doesn't exist
81
- - Your frame ID is incorrect
77
+ return `Not Found: ${error.message}
78
+
79
+ This could mean:
80
+ - The requested item doesn't exist
81
+ - Your frame ID is incorrect
82
82
  - The item was deleted from Skylight`;
83
83
  }
84
84
  if (error instanceof RateLimitError) {
85
- return `Rate Limited: ${error.message}
86
-
85
+ return `Rate Limited: ${error.message}
86
+
87
87
  The Skylight API is temporarily limiting requests. Please wait a moment and try again.`;
88
88
  }
89
89
  if (error instanceof ConfigurationError) {
90
- return `Configuration Error: ${error.message}
91
-
90
+ return `Configuration Error: ${error.message}
91
+
92
92
  Please check your environment variables are set correctly.`;
93
93
  }
94
94
  if (error instanceof SkylightError) {
package/package.json CHANGED
@@ -1,59 +1,59 @@
1
- {
2
- "name": "@bmhall2/skylight-mcp",
3
- "version": "1.1.7",
4
- "description": "MCP server for Skylight Calendar API - enables agentic interactions for calendar, chores, lists, and family management",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "bin": {
8
- "skylight-mcp": "dist/index.js"
9
- },
10
- "files": [
11
- "dist",
12
- "README.md",
13
- "LICENSE"
14
- ],
15
- "scripts": {
16
- "build": "tsc",
17
- "start": "node dist/index.js",
18
- "dev": "tsx watch src/index.ts",
19
- "test": "vitest",
20
- "test:coverage": "vitest --coverage",
21
- "lint": "eslint src/",
22
- "typecheck": "tsc --noEmit",
23
- "prepare": "npm run build",
24
- "generate:types": "openapi-typescript ../skylight-api/docs/openapi/openapi.yaml -o src/api/generated-types.ts"
25
- },
26
- "keywords": [
27
- "mcp",
28
- "skylight",
29
- "calendar",
30
- "model-context-protocol",
31
- "claude",
32
- "ai",
33
- "family",
34
- "chores"
35
- ],
36
- "author": "Ben Hall <bmhall2@gmail.com>",
37
- "license": "MIT",
38
- "repository": {
39
- "type": "git",
40
- "url": "https://github.com/bmhall2/skylight-mcp.git"
41
- },
42
- "dependencies": {
43
- "@modelcontextprotocol/sdk": "^1.11.0",
44
- "zod": "^3.24.1"
45
- },
46
- "devDependencies": {
47
- "@types/node": "^20.12.2",
48
- "typescript": "^5.4.5",
49
- "tsx": "^4.7.0",
50
- "vitest": "^1.6.0",
51
- "eslint": "^8.57.0",
52
- "@typescript-eslint/eslint-plugin": "^7.0.0",
53
- "@typescript-eslint/parser": "^7.0.0",
54
- "openapi-typescript": "^7.0.0"
55
- },
56
- "engines": {
57
- "node": ">=18.0.0"
58
- }
59
- }
1
+ {
2
+ "name": "@bmhall2/skylight-mcp",
3
+ "version": "1.1.8",
4
+ "description": "MCP server for Skylight Calendar API - enables agentic interactions for calendar, chores, lists, and family management",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "skylight-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "start": "node dist/index.js",
18
+ "dev": "tsx watch src/index.ts",
19
+ "test": "vitest",
20
+ "test:coverage": "vitest --coverage",
21
+ "lint": "eslint src/",
22
+ "typecheck": "tsc --noEmit",
23
+ "prepare": "npm run build",
24
+ "generate:types": "openapi-typescript ../skylight-api/docs/openapi/openapi.yaml -o src/api/generated-types.ts"
25
+ },
26
+ "keywords": [
27
+ "mcp",
28
+ "skylight",
29
+ "calendar",
30
+ "model-context-protocol",
31
+ "claude",
32
+ "ai",
33
+ "family",
34
+ "chores"
35
+ ],
36
+ "author": "Ben Hall <bmhall2@gmail.com>",
37
+ "license": "MIT",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/bmhall2/skylight-mcp.git"
41
+ },
42
+ "dependencies": {
43
+ "@modelcontextprotocol/sdk": "^1.11.0",
44
+ "zod": "^3.24.1"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^20.12.2",
48
+ "typescript": "^5.4.5",
49
+ "tsx": "^4.7.0",
50
+ "vitest": "^1.6.0",
51
+ "eslint": "^8.57.0",
52
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
53
+ "@typescript-eslint/parser": "^7.0.0",
54
+ "openapi-typescript": "^7.0.0"
55
+ },
56
+ "engines": {
57
+ "node": ">=18.0.0"
58
+ }
59
+ }