good-eggs-mcp-server 0.1.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/README.md +178 -0
- package/build/index.integration-with-mock.js +149 -0
- package/build/index.js +93 -0
- package/package.json +46 -0
- package/shared/index.d.ts +5 -0
- package/shared/index.js +6 -0
- package/shared/logging.d.ts +20 -0
- package/shared/logging.js +34 -0
- package/shared/server.d.ts +120 -0
- package/shared/server.js +620 -0
- package/shared/tools.d.ts +4 -0
- package/shared/tools.js +612 -0
- package/shared/types.d.ts +95 -0
- package/shared/types.js +43 -0
package/shared/tools.js
ADDED
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { SearchGrocerySchema, GetGroceryDetailsSchema, AddToCartSchema, GetPastOrderGroceriesSchema, AddFavoriteSchema, RemoveFavoriteSchema, RemoveFromCartSchema, } from './types.js';
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// TOOL DESCRIPTIONS
|
|
5
|
+
// =============================================================================
|
|
6
|
+
const SEARCH_GROCERY_DESCRIPTION = `Search for groceries on Good Eggs.
|
|
7
|
+
|
|
8
|
+
Returns a list of grocery items matching your search query, including:
|
|
9
|
+
- Product URL (for use with other tools)
|
|
10
|
+
- Product name and brand
|
|
11
|
+
- Price information
|
|
12
|
+
- Any discounts/deals
|
|
13
|
+
|
|
14
|
+
**Example queries:**
|
|
15
|
+
- "organic apples"
|
|
16
|
+
- "milk"
|
|
17
|
+
- "chicken breast"
|
|
18
|
+
- "gluten free bread"`;
|
|
19
|
+
const GET_FAVORITES_DESCRIPTION = `Get the user's favorite/saved grocery items on Good Eggs.
|
|
20
|
+
|
|
21
|
+
Returns a list of all items the user has marked as favorites, including:
|
|
22
|
+
- Product URL (for use with other tools)
|
|
23
|
+
- Product name and brand
|
|
24
|
+
- Price information
|
|
25
|
+
|
|
26
|
+
Requires the user to be logged in.`;
|
|
27
|
+
const GET_GROCERY_DETAILS_DESCRIPTION = `Get detailed information about a specific grocery item.
|
|
28
|
+
|
|
29
|
+
Provide the Good Eggs URL of the item (from search results or favorites).
|
|
30
|
+
Returns comprehensive details including:
|
|
31
|
+
- Full product name and brand
|
|
32
|
+
- Current and original prices
|
|
33
|
+
- Product description
|
|
34
|
+
- Delivery availability dates
|
|
35
|
+
|
|
36
|
+
**Tip:** This tool checks if you're already on the product page to minimize navigation.`;
|
|
37
|
+
const ADD_TO_CART_DESCRIPTION = `Add a grocery item to your shopping cart.
|
|
38
|
+
|
|
39
|
+
Provide:
|
|
40
|
+
- grocery_url: The Good Eggs URL of the item to add
|
|
41
|
+
- quantity: Number of items to add (default: 1)
|
|
42
|
+
|
|
43
|
+
Returns confirmation of the item added and quantity.
|
|
44
|
+
|
|
45
|
+
**Tip:** This tool checks if you're already on the product page to minimize navigation.`;
|
|
46
|
+
const SEARCH_FREEBIE_GROCERIES_DESCRIPTION = `Search for free items ($0.00) on Good Eggs.
|
|
47
|
+
|
|
48
|
+
Checks the homepage and /fresh-picks page for items priced at $0.00.
|
|
49
|
+
These are typically promotional freebies offered by Good Eggs.
|
|
50
|
+
|
|
51
|
+
Returns a list of free items with their URLs for adding to cart.`;
|
|
52
|
+
const GET_PAST_ORDER_DATES_DESCRIPTION = `Get a list of past order dates from Good Eggs.
|
|
53
|
+
|
|
54
|
+
Returns a list of previous orders with:
|
|
55
|
+
- Order date
|
|
56
|
+
- Order total (if available)
|
|
57
|
+
- Number of items (if available)
|
|
58
|
+
|
|
59
|
+
Use these dates with get_past_order_groceries to see specific order contents.
|
|
60
|
+
Requires the user to be logged in.`;
|
|
61
|
+
const GET_PAST_ORDER_GROCERIES_DESCRIPTION = `Get the grocery items from a specific past order.
|
|
62
|
+
|
|
63
|
+
Provide the past_order_date (from get_list_of_past_order_dates) to see what was ordered.
|
|
64
|
+
Returns a list of items from that order including:
|
|
65
|
+
- Product URL
|
|
66
|
+
- Product name and brand
|
|
67
|
+
- Price at time of order
|
|
68
|
+
|
|
69
|
+
Useful for reordering frequently purchased items.
|
|
70
|
+
Requires the user to be logged in.`;
|
|
71
|
+
const ADD_FAVORITE_DESCRIPTION = `Add a grocery item to your favorites.
|
|
72
|
+
|
|
73
|
+
Provide the Good Eggs URL of the item to add to favorites.
|
|
74
|
+
If the item is already in favorites, it will let you know.
|
|
75
|
+
|
|
76
|
+
Returns confirmation of the action taken.`;
|
|
77
|
+
const REMOVE_FAVORITE_DESCRIPTION = `Remove a grocery item from your favorites.
|
|
78
|
+
|
|
79
|
+
Provide the Good Eggs URL of the item to remove from favorites.
|
|
80
|
+
If the item is not in favorites, it will let you know.
|
|
81
|
+
|
|
82
|
+
Returns confirmation of the action taken.`;
|
|
83
|
+
const REMOVE_FROM_CART_DESCRIPTION = `Remove a grocery item from your shopping cart.
|
|
84
|
+
|
|
85
|
+
Provide the Good Eggs URL of the item to remove from your cart.
|
|
86
|
+
Navigates to the cart and removes the specified item.
|
|
87
|
+
|
|
88
|
+
Returns confirmation of the removal or an error if the item is not in the cart.`;
|
|
89
|
+
export function createRegisterTools(clientFactory) {
|
|
90
|
+
// Create a single client instance that persists across calls
|
|
91
|
+
let client = null;
|
|
92
|
+
let isInitialized = false;
|
|
93
|
+
const getClient = async () => {
|
|
94
|
+
if (!client) {
|
|
95
|
+
client = clientFactory();
|
|
96
|
+
}
|
|
97
|
+
if (!isInitialized) {
|
|
98
|
+
await client.initialize();
|
|
99
|
+
isInitialized = true;
|
|
100
|
+
}
|
|
101
|
+
return client;
|
|
102
|
+
};
|
|
103
|
+
const tools = [
|
|
104
|
+
{
|
|
105
|
+
name: 'search_for_grocery',
|
|
106
|
+
description: SEARCH_GROCERY_DESCRIPTION,
|
|
107
|
+
inputSchema: {
|
|
108
|
+
type: 'object',
|
|
109
|
+
properties: {
|
|
110
|
+
query: {
|
|
111
|
+
type: 'string',
|
|
112
|
+
description: 'Search query for groceries (e.g., "organic apples", "milk", "bread")',
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
required: ['query'],
|
|
116
|
+
},
|
|
117
|
+
handler: async (args) => {
|
|
118
|
+
try {
|
|
119
|
+
const validated = SearchGrocerySchema.parse(args);
|
|
120
|
+
const goodEggsClient = await getClient();
|
|
121
|
+
const results = await goodEggsClient.searchGroceries(validated.query);
|
|
122
|
+
if (results.length === 0) {
|
|
123
|
+
return {
|
|
124
|
+
content: [
|
|
125
|
+
{
|
|
126
|
+
type: 'text',
|
|
127
|
+
text: `No groceries found for "${validated.query}". Try a different search term.`,
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
const formattedResults = results
|
|
133
|
+
.map((item, i) => `${i + 1}. **${item.name}**\n Brand: ${item.brand || 'N/A'}\n Price: ${item.price || 'N/A'}${item.discount ? `\n Discount: ${item.discount}` : ''}\n URL: ${item.url}`)
|
|
134
|
+
.join('\n\n');
|
|
135
|
+
return {
|
|
136
|
+
content: [
|
|
137
|
+
{
|
|
138
|
+
type: 'text',
|
|
139
|
+
text: `Found ${results.length} groceries for "${validated.query}":\n\n${formattedResults}`,
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
return {
|
|
146
|
+
content: [
|
|
147
|
+
{
|
|
148
|
+
type: 'text',
|
|
149
|
+
text: `Error searching for groceries: ${error instanceof Error ? error.message : String(error)}`,
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
isError: true,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: 'get_favorites',
|
|
159
|
+
description: GET_FAVORITES_DESCRIPTION,
|
|
160
|
+
inputSchema: {
|
|
161
|
+
type: 'object',
|
|
162
|
+
properties: {},
|
|
163
|
+
},
|
|
164
|
+
handler: async () => {
|
|
165
|
+
try {
|
|
166
|
+
const goodEggsClient = await getClient();
|
|
167
|
+
const results = await goodEggsClient.getFavorites();
|
|
168
|
+
if (results.length === 0) {
|
|
169
|
+
return {
|
|
170
|
+
content: [
|
|
171
|
+
{
|
|
172
|
+
type: 'text',
|
|
173
|
+
text: 'No favorite items found. Add items to your favorites on Good Eggs to see them here.',
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const formattedResults = results
|
|
179
|
+
.map((item, i) => `${i + 1}. **${item.name}**\n Brand: ${item.brand || 'N/A'}\n Price: ${item.price || 'N/A'}\n URL: ${item.url}`)
|
|
180
|
+
.join('\n\n');
|
|
181
|
+
return {
|
|
182
|
+
content: [
|
|
183
|
+
{
|
|
184
|
+
type: 'text',
|
|
185
|
+
text: `Found ${results.length} favorite items:\n\n${formattedResults}`,
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
return {
|
|
192
|
+
content: [
|
|
193
|
+
{
|
|
194
|
+
type: 'text',
|
|
195
|
+
text: `Error getting favorites: ${error instanceof Error ? error.message : String(error)}`,
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
isError: true,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'get_grocery_details',
|
|
205
|
+
description: GET_GROCERY_DETAILS_DESCRIPTION,
|
|
206
|
+
inputSchema: {
|
|
207
|
+
type: 'object',
|
|
208
|
+
properties: {
|
|
209
|
+
grocery_url: {
|
|
210
|
+
type: 'string',
|
|
211
|
+
description: 'The Good Eggs URL of the grocery item to get details for',
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
required: ['grocery_url'],
|
|
215
|
+
},
|
|
216
|
+
handler: async (args) => {
|
|
217
|
+
try {
|
|
218
|
+
const validated = GetGroceryDetailsSchema.parse(args);
|
|
219
|
+
const goodEggsClient = await getClient();
|
|
220
|
+
const details = await goodEggsClient.getGroceryDetails(validated.grocery_url);
|
|
221
|
+
const lines = [
|
|
222
|
+
`**${details.name}**`,
|
|
223
|
+
`Brand: ${details.brand || 'N/A'}`,
|
|
224
|
+
`Price: ${details.price || 'N/A'}`,
|
|
225
|
+
];
|
|
226
|
+
if (details.originalPrice) {
|
|
227
|
+
lines.push(`Original Price: ${details.originalPrice}`);
|
|
228
|
+
}
|
|
229
|
+
if (details.discount) {
|
|
230
|
+
lines.push(`Discount: ${details.discount}`);
|
|
231
|
+
}
|
|
232
|
+
if (details.description) {
|
|
233
|
+
lines.push(`\nDescription: ${details.description}`);
|
|
234
|
+
}
|
|
235
|
+
if (details.productDetails) {
|
|
236
|
+
lines.push(`\nProduct Details: ${details.productDetails}`);
|
|
237
|
+
}
|
|
238
|
+
if (details.availability && details.availability.length > 0) {
|
|
239
|
+
lines.push(`\nAvailable for delivery: ${details.availability.join(', ')}`);
|
|
240
|
+
}
|
|
241
|
+
lines.push(`\nURL: ${details.url}`);
|
|
242
|
+
return {
|
|
243
|
+
content: [
|
|
244
|
+
{
|
|
245
|
+
type: 'text',
|
|
246
|
+
text: lines.join('\n'),
|
|
247
|
+
},
|
|
248
|
+
],
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
return {
|
|
253
|
+
content: [
|
|
254
|
+
{
|
|
255
|
+
type: 'text',
|
|
256
|
+
text: `Error getting grocery details: ${error instanceof Error ? error.message : String(error)}`,
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
isError: true,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
name: 'add_to_cart',
|
|
266
|
+
description: ADD_TO_CART_DESCRIPTION,
|
|
267
|
+
inputSchema: {
|
|
268
|
+
type: 'object',
|
|
269
|
+
properties: {
|
|
270
|
+
grocery_url: {
|
|
271
|
+
type: 'string',
|
|
272
|
+
description: 'The Good Eggs URL of the grocery item to add to cart',
|
|
273
|
+
},
|
|
274
|
+
quantity: {
|
|
275
|
+
type: 'number',
|
|
276
|
+
description: 'Quantity to add (default: 1)',
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
required: ['grocery_url'],
|
|
280
|
+
},
|
|
281
|
+
handler: async (args) => {
|
|
282
|
+
try {
|
|
283
|
+
const validated = AddToCartSchema.parse(args);
|
|
284
|
+
const goodEggsClient = await getClient();
|
|
285
|
+
const result = await goodEggsClient.addToCart(validated.grocery_url, validated.quantity);
|
|
286
|
+
return {
|
|
287
|
+
content: [
|
|
288
|
+
{
|
|
289
|
+
type: 'text',
|
|
290
|
+
text: result.success ? result.message : `Failed to add to cart: ${result.message}`,
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
isError: !result.success,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
catch (error) {
|
|
297
|
+
return {
|
|
298
|
+
content: [
|
|
299
|
+
{
|
|
300
|
+
type: 'text',
|
|
301
|
+
text: `Error adding to cart: ${error instanceof Error ? error.message : String(error)}`,
|
|
302
|
+
},
|
|
303
|
+
],
|
|
304
|
+
isError: true,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
name: 'search_for_freebie_groceries',
|
|
311
|
+
description: SEARCH_FREEBIE_GROCERIES_DESCRIPTION,
|
|
312
|
+
inputSchema: {
|
|
313
|
+
type: 'object',
|
|
314
|
+
properties: {},
|
|
315
|
+
},
|
|
316
|
+
handler: async () => {
|
|
317
|
+
try {
|
|
318
|
+
const goodEggsClient = await getClient();
|
|
319
|
+
const results = await goodEggsClient.searchFreebieGroceries();
|
|
320
|
+
if (results.length === 0) {
|
|
321
|
+
return {
|
|
322
|
+
content: [
|
|
323
|
+
{
|
|
324
|
+
type: 'text',
|
|
325
|
+
text: 'No free items or deals currently available.',
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
const formattedResults = results
|
|
331
|
+
.map((item, i) => `${i + 1}. **${item.name}**\n Brand: ${item.brand || 'N/A'}\n Price: ${item.price || 'N/A'}\n Discount: ${item.discount || 'N/A'}\n URL: ${item.url}`)
|
|
332
|
+
.join('\n\n');
|
|
333
|
+
return {
|
|
334
|
+
content: [
|
|
335
|
+
{
|
|
336
|
+
type: 'text',
|
|
337
|
+
text: `Found ${results.length} deals/freebies:\n\n${formattedResults}`,
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
return {
|
|
344
|
+
content: [
|
|
345
|
+
{
|
|
346
|
+
type: 'text',
|
|
347
|
+
text: `Error searching for freebies: ${error instanceof Error ? error.message : String(error)}`,
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
isError: true,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
name: 'get_list_of_past_order_dates',
|
|
357
|
+
description: GET_PAST_ORDER_DATES_DESCRIPTION,
|
|
358
|
+
inputSchema: {
|
|
359
|
+
type: 'object',
|
|
360
|
+
properties: {},
|
|
361
|
+
},
|
|
362
|
+
handler: async () => {
|
|
363
|
+
try {
|
|
364
|
+
const goodEggsClient = await getClient();
|
|
365
|
+
const orders = await goodEggsClient.getPastOrderDates();
|
|
366
|
+
if (orders.length === 0) {
|
|
367
|
+
return {
|
|
368
|
+
content: [
|
|
369
|
+
{
|
|
370
|
+
type: 'text',
|
|
371
|
+
text: 'No past orders found.',
|
|
372
|
+
},
|
|
373
|
+
],
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
const formattedResults = orders
|
|
377
|
+
.map((order, i) => {
|
|
378
|
+
const parts = [`${i + 1}. **${order.date}**`];
|
|
379
|
+
if (order.total)
|
|
380
|
+
parts.push(` Total: ${order.total}`);
|
|
381
|
+
if (order.itemCount)
|
|
382
|
+
parts.push(` Items: ${order.itemCount}`);
|
|
383
|
+
return parts.join('\n');
|
|
384
|
+
})
|
|
385
|
+
.join('\n\n');
|
|
386
|
+
return {
|
|
387
|
+
content: [
|
|
388
|
+
{
|
|
389
|
+
type: 'text',
|
|
390
|
+
text: `Found ${orders.length} past orders:\n\n${formattedResults}`,
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
catch (error) {
|
|
396
|
+
return {
|
|
397
|
+
content: [
|
|
398
|
+
{
|
|
399
|
+
type: 'text',
|
|
400
|
+
text: `Error getting past order dates: ${error instanceof Error ? error.message : String(error)}`,
|
|
401
|
+
},
|
|
402
|
+
],
|
|
403
|
+
isError: true,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
name: 'get_past_order_groceries',
|
|
410
|
+
description: GET_PAST_ORDER_GROCERIES_DESCRIPTION,
|
|
411
|
+
inputSchema: {
|
|
412
|
+
type: 'object',
|
|
413
|
+
properties: {
|
|
414
|
+
past_order_date: {
|
|
415
|
+
type: 'string',
|
|
416
|
+
description: 'The date of the past order to get groceries from (e.g., "2024-01-15")',
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
required: ['past_order_date'],
|
|
420
|
+
},
|
|
421
|
+
handler: async (args) => {
|
|
422
|
+
try {
|
|
423
|
+
const validated = GetPastOrderGroceriesSchema.parse(args);
|
|
424
|
+
const goodEggsClient = await getClient();
|
|
425
|
+
const results = await goodEggsClient.getPastOrderGroceries(validated.past_order_date);
|
|
426
|
+
if (results.length === 0) {
|
|
427
|
+
return {
|
|
428
|
+
content: [
|
|
429
|
+
{
|
|
430
|
+
type: 'text',
|
|
431
|
+
text: `No items found for order on ${validated.past_order_date}. Make sure the date matches exactly.`,
|
|
432
|
+
},
|
|
433
|
+
],
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
const formattedResults = results
|
|
437
|
+
.map((item, i) => `${i + 1}. **${item.name}**\n Brand: ${item.brand || 'N/A'}\n Price: ${item.price || 'N/A'}\n URL: ${item.url}`)
|
|
438
|
+
.join('\n\n');
|
|
439
|
+
return {
|
|
440
|
+
content: [
|
|
441
|
+
{
|
|
442
|
+
type: 'text',
|
|
443
|
+
text: `Found ${results.length} items from order on ${validated.past_order_date}:\n\n${formattedResults}`,
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
return {
|
|
450
|
+
content: [
|
|
451
|
+
{
|
|
452
|
+
type: 'text',
|
|
453
|
+
text: `Error getting past order groceries: ${error instanceof Error ? error.message : String(error)}`,
|
|
454
|
+
},
|
|
455
|
+
],
|
|
456
|
+
isError: true,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
name: 'add_favorite',
|
|
463
|
+
description: ADD_FAVORITE_DESCRIPTION,
|
|
464
|
+
inputSchema: {
|
|
465
|
+
type: 'object',
|
|
466
|
+
properties: {
|
|
467
|
+
grocery_url: {
|
|
468
|
+
type: 'string',
|
|
469
|
+
description: 'The Good Eggs URL of the grocery item to add to favorites',
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
required: ['grocery_url'],
|
|
473
|
+
},
|
|
474
|
+
handler: async (args) => {
|
|
475
|
+
try {
|
|
476
|
+
const validated = AddFavoriteSchema.parse(args);
|
|
477
|
+
const goodEggsClient = await getClient();
|
|
478
|
+
const result = await goodEggsClient.addFavorite(validated.grocery_url);
|
|
479
|
+
return {
|
|
480
|
+
content: [
|
|
481
|
+
{
|
|
482
|
+
type: 'text',
|
|
483
|
+
text: result.success
|
|
484
|
+
? result.message
|
|
485
|
+
: `Failed to add to favorites: ${result.message}`,
|
|
486
|
+
},
|
|
487
|
+
],
|
|
488
|
+
isError: !result.success,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
catch (error) {
|
|
492
|
+
return {
|
|
493
|
+
content: [
|
|
494
|
+
{
|
|
495
|
+
type: 'text',
|
|
496
|
+
text: `Error adding to favorites: ${error instanceof Error ? error.message : String(error)}`,
|
|
497
|
+
},
|
|
498
|
+
],
|
|
499
|
+
isError: true,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
name: 'remove_favorite',
|
|
506
|
+
description: REMOVE_FAVORITE_DESCRIPTION,
|
|
507
|
+
inputSchema: {
|
|
508
|
+
type: 'object',
|
|
509
|
+
properties: {
|
|
510
|
+
grocery_url: {
|
|
511
|
+
type: 'string',
|
|
512
|
+
description: 'The Good Eggs URL of the grocery item to remove from favorites',
|
|
513
|
+
},
|
|
514
|
+
},
|
|
515
|
+
required: ['grocery_url'],
|
|
516
|
+
},
|
|
517
|
+
handler: async (args) => {
|
|
518
|
+
try {
|
|
519
|
+
const validated = RemoveFavoriteSchema.parse(args);
|
|
520
|
+
const goodEggsClient = await getClient();
|
|
521
|
+
const result = await goodEggsClient.removeFavorite(validated.grocery_url);
|
|
522
|
+
return {
|
|
523
|
+
content: [
|
|
524
|
+
{
|
|
525
|
+
type: 'text',
|
|
526
|
+
text: result.success
|
|
527
|
+
? result.message
|
|
528
|
+
: `Failed to remove from favorites: ${result.message}`,
|
|
529
|
+
},
|
|
530
|
+
],
|
|
531
|
+
isError: !result.success,
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
catch (error) {
|
|
535
|
+
return {
|
|
536
|
+
content: [
|
|
537
|
+
{
|
|
538
|
+
type: 'text',
|
|
539
|
+
text: `Error removing from favorites: ${error instanceof Error ? error.message : String(error)}`,
|
|
540
|
+
},
|
|
541
|
+
],
|
|
542
|
+
isError: true,
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
name: 'remove_from_cart',
|
|
549
|
+
description: REMOVE_FROM_CART_DESCRIPTION,
|
|
550
|
+
inputSchema: {
|
|
551
|
+
type: 'object',
|
|
552
|
+
properties: {
|
|
553
|
+
grocery_url: {
|
|
554
|
+
type: 'string',
|
|
555
|
+
description: 'The Good Eggs URL of the grocery item to remove from cart',
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
required: ['grocery_url'],
|
|
559
|
+
},
|
|
560
|
+
handler: async (args) => {
|
|
561
|
+
try {
|
|
562
|
+
const validated = RemoveFromCartSchema.parse(args);
|
|
563
|
+
const goodEggsClient = await getClient();
|
|
564
|
+
const result = await goodEggsClient.removeFromCart(validated.grocery_url);
|
|
565
|
+
return {
|
|
566
|
+
content: [
|
|
567
|
+
{
|
|
568
|
+
type: 'text',
|
|
569
|
+
text: result.success
|
|
570
|
+
? result.message
|
|
571
|
+
: `Failed to remove from cart: ${result.message}`,
|
|
572
|
+
},
|
|
573
|
+
],
|
|
574
|
+
isError: !result.success,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
catch (error) {
|
|
578
|
+
return {
|
|
579
|
+
content: [
|
|
580
|
+
{
|
|
581
|
+
type: 'text',
|
|
582
|
+
text: `Error removing from cart: ${error instanceof Error ? error.message : String(error)}`,
|
|
583
|
+
},
|
|
584
|
+
],
|
|
585
|
+
isError: true,
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
},
|
|
590
|
+
];
|
|
591
|
+
return (server) => {
|
|
592
|
+
// List available tools
|
|
593
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
594
|
+
return {
|
|
595
|
+
tools: tools.map((tool) => ({
|
|
596
|
+
name: tool.name,
|
|
597
|
+
description: tool.description,
|
|
598
|
+
inputSchema: tool.inputSchema,
|
|
599
|
+
})),
|
|
600
|
+
};
|
|
601
|
+
});
|
|
602
|
+
// Handle tool calls
|
|
603
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
604
|
+
const { name, arguments: args } = request.params;
|
|
605
|
+
const tool = tools.find((t) => t.name === name);
|
|
606
|
+
if (!tool) {
|
|
607
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
608
|
+
}
|
|
609
|
+
return await tool.handler(args);
|
|
610
|
+
});
|
|
611
|
+
};
|
|
612
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export interface GroceryItem {
|
|
3
|
+
url: string;
|
|
4
|
+
name: string;
|
|
5
|
+
brand: string;
|
|
6
|
+
price: string;
|
|
7
|
+
originalPrice?: string;
|
|
8
|
+
discount?: string;
|
|
9
|
+
unit?: string;
|
|
10
|
+
imageUrl?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface GroceryDetails {
|
|
13
|
+
url: string;
|
|
14
|
+
name: string;
|
|
15
|
+
brand: string;
|
|
16
|
+
price: string;
|
|
17
|
+
originalPrice?: string;
|
|
18
|
+
discount?: string;
|
|
19
|
+
unit?: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
productDetails?: string;
|
|
22
|
+
availability?: string[];
|
|
23
|
+
imageUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface PastOrder {
|
|
26
|
+
date: string;
|
|
27
|
+
orderNumber?: string;
|
|
28
|
+
total?: string;
|
|
29
|
+
itemCount?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface CartResult {
|
|
32
|
+
success: boolean;
|
|
33
|
+
message: string;
|
|
34
|
+
itemName?: string;
|
|
35
|
+
quantity?: number;
|
|
36
|
+
}
|
|
37
|
+
export declare const SearchGrocerySchema: z.ZodObject<{
|
|
38
|
+
query: z.ZodString;
|
|
39
|
+
}, "strip", z.ZodTypeAny, {
|
|
40
|
+
query: string;
|
|
41
|
+
}, {
|
|
42
|
+
query: string;
|
|
43
|
+
}>;
|
|
44
|
+
export declare const GetGroceryDetailsSchema: z.ZodObject<{
|
|
45
|
+
grocery_url: z.ZodEffects<z.ZodString, string, string>;
|
|
46
|
+
}, "strip", z.ZodTypeAny, {
|
|
47
|
+
grocery_url: string;
|
|
48
|
+
}, {
|
|
49
|
+
grocery_url: string;
|
|
50
|
+
}>;
|
|
51
|
+
export declare const AddToCartSchema: z.ZodObject<{
|
|
52
|
+
grocery_url: z.ZodEffects<z.ZodString, string, string>;
|
|
53
|
+
quantity: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
54
|
+
}, "strip", z.ZodTypeAny, {
|
|
55
|
+
grocery_url: string;
|
|
56
|
+
quantity: number;
|
|
57
|
+
}, {
|
|
58
|
+
grocery_url: string;
|
|
59
|
+
quantity?: number | undefined;
|
|
60
|
+
}>;
|
|
61
|
+
export declare const GetPastOrderGroceriesSchema: z.ZodObject<{
|
|
62
|
+
past_order_date: z.ZodString;
|
|
63
|
+
}, "strip", z.ZodTypeAny, {
|
|
64
|
+
past_order_date: string;
|
|
65
|
+
}, {
|
|
66
|
+
past_order_date: string;
|
|
67
|
+
}>;
|
|
68
|
+
export declare const AddFavoriteSchema: z.ZodObject<{
|
|
69
|
+
grocery_url: z.ZodEffects<z.ZodString, string, string>;
|
|
70
|
+
}, "strip", z.ZodTypeAny, {
|
|
71
|
+
grocery_url: string;
|
|
72
|
+
}, {
|
|
73
|
+
grocery_url: string;
|
|
74
|
+
}>;
|
|
75
|
+
export declare const RemoveFavoriteSchema: z.ZodObject<{
|
|
76
|
+
grocery_url: z.ZodEffects<z.ZodString, string, string>;
|
|
77
|
+
}, "strip", z.ZodTypeAny, {
|
|
78
|
+
grocery_url: string;
|
|
79
|
+
}, {
|
|
80
|
+
grocery_url: string;
|
|
81
|
+
}>;
|
|
82
|
+
export declare const RemoveFromCartSchema: z.ZodObject<{
|
|
83
|
+
grocery_url: z.ZodEffects<z.ZodString, string, string>;
|
|
84
|
+
}, "strip", z.ZodTypeAny, {
|
|
85
|
+
grocery_url: string;
|
|
86
|
+
}, {
|
|
87
|
+
grocery_url: string;
|
|
88
|
+
}>;
|
|
89
|
+
export interface GoodEggsConfig {
|
|
90
|
+
username: string;
|
|
91
|
+
password: string;
|
|
92
|
+
headless: boolean;
|
|
93
|
+
timeout: number;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=types.d.ts.map
|