good-eggs-mcp-server 0.1.5 → 0.1.7

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 (2) hide show
  1. package/package.json +1 -1
  2. package/shared/server.js +43 -31
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "good-eggs-mcp-server",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "MCP server for Good Eggs grocery shopping with Playwright automation",
5
5
  "main": "build/index.js",
6
6
  "type": "module",
package/shared/server.js CHANGED
@@ -559,24 +559,19 @@ export class GoodEggsClient {
559
559
  const nameEl = document.querySelector('h1, [class*="product-name"], [class*="title"]');
560
560
  return nameEl?.textContent?.trim() || 'Unknown item';
561
561
  });
562
- // Look for the favorite/heart button
563
- const favoriteButton = await page.$('button[aria-label*="favorite"], button[aria-label*="heart"], button:has([class*="heart"]), [class*="favorite"] button, button[class*="favorite"]');
564
- if (!favoriteButton) {
562
+ // Look for the favorite control - Good Eggs uses a div, not a button
563
+ const favoriteControl = await page.$('.product-detail__favorite-control');
564
+ if (!favoriteControl) {
565
565
  return {
566
566
  success: false,
567
567
  message: 'Could not find favorite button',
568
568
  itemName,
569
569
  };
570
570
  }
571
- // Check if already favorited (button might have "filled" or "active" state)
572
- const isAlreadyFavorited = await page.evaluate((btn) => {
573
- const classList = btn.className || '';
574
- const ariaPressed = btn.getAttribute('aria-pressed');
575
- return (classList.includes('active') ||
576
- classList.includes('filled') ||
577
- classList.includes('favorited') ||
578
- ariaPressed === 'true');
579
- }, favoriteButton);
571
+ // Check if already favorited by looking for 'favorited' class (vs 'not-favorited')
572
+ const isAlreadyFavorited = await page.evaluate((el) => {
573
+ return el.classList.contains('favorited');
574
+ }, favoriteControl);
580
575
  if (isAlreadyFavorited) {
581
576
  return {
582
577
  success: true,
@@ -584,7 +579,7 @@ export class GoodEggsClient {
584
579
  itemName,
585
580
  };
586
581
  }
587
- await favoriteButton.click();
582
+ await favoriteControl.click();
588
583
  await page.waitForTimeout(500);
589
584
  return {
590
585
  success: true,
@@ -609,24 +604,19 @@ export class GoodEggsClient {
609
604
  const nameEl = document.querySelector('h1, [class*="product-name"], [class*="title"]');
610
605
  return nameEl?.textContent?.trim() || 'Unknown item';
611
606
  });
612
- // Look for the favorite/heart button
613
- const favoriteButton = await page.$('button[aria-label*="favorite"], button[aria-label*="heart"], button:has([class*="heart"]), [class*="favorite"] button, button[class*="favorite"]');
614
- if (!favoriteButton) {
607
+ // Look for the favorite control - Good Eggs uses a div, not a button
608
+ const favoriteControl = await page.$('.product-detail__favorite-control');
609
+ if (!favoriteControl) {
615
610
  return {
616
611
  success: false,
617
612
  message: 'Could not find favorite button',
618
613
  itemName,
619
614
  };
620
615
  }
621
- // Check if already favorited (button might have "filled" or "active" state)
622
- const isFavorited = await page.evaluate((btn) => {
623
- const classList = btn.className || '';
624
- const ariaPressed = btn.getAttribute('aria-pressed');
625
- return (classList.includes('active') ||
626
- classList.includes('filled') ||
627
- classList.includes('favorited') ||
628
- ariaPressed === 'true');
629
- }, favoriteButton);
616
+ // Check if favorited by looking for 'favorited' class (vs 'not-favorited')
617
+ const isFavorited = await page.evaluate((el) => {
618
+ return el.classList.contains('favorited');
619
+ }, favoriteControl);
630
620
  if (!isFavorited) {
631
621
  return {
632
622
  success: true,
@@ -634,7 +624,7 @@ export class GoodEggsClient {
634
624
  itemName,
635
625
  };
636
626
  }
637
- await favoriteButton.click();
627
+ await favoriteControl.click();
638
628
  await page.waitForTimeout(500);
639
629
  return {
640
630
  success: true,
@@ -659,22 +649,27 @@ export class GoodEggsClient {
659
649
  itemName: groceryUrl,
660
650
  };
661
651
  }
662
- // Look for the item in the cart
663
- const cartItems = await page.$$('[class*="cart-item"], [class*="basket-item"], [class*="line-item"]');
652
+ // Look for the item in the cart using the same selectors as getCart()
653
+ // Good Eggs uses 'js-basket-item' class for cart items
654
+ const cartItems = await page.$$('.js-basket-item');
664
655
  let itemFound = false;
665
656
  let itemName = 'Unknown item';
666
657
  for (const cartItem of cartItems) {
667
658
  // Check if this cart item contains a link to our product
659
+ // Good Eggs uses .summary-item__name a for the product link
668
660
  const itemLink = await cartItem.$(`a[href*="${productSlug}"]`);
669
661
  if (itemLink) {
670
662
  itemFound = true;
671
- // Get the item name
672
- const nameEl = await cartItem.$('[class*="name"], [class*="title"], h3, h4');
663
+ // Get the item name using Good Eggs selector
664
+ const nameEl = await cartItem.$('.summary-item__name a');
673
665
  if (nameEl) {
674
666
  itemName = (await nameEl.textContent()) || 'Unknown item';
675
667
  }
676
668
  // Find and click the remove button
677
- const removeButton = await cartItem.$('button[aria-label*="remove"], button:has-text("Remove"), button:has-text("×"), [class*="remove"] button');
669
+ // Good Eggs may have a dedicated remove button or use a quantity dropdown
670
+ // We try the remove button first, then fall back to the quantity dropdown
671
+ // First, try to find a direct remove button (future-proofing in case Good Eggs adds one)
672
+ const removeButton = await cartItem.$('button[aria-label*="remove"], button[aria-label*="Remove"], .summary-item__remove, [class*="remove-button"]');
678
673
  if (removeButton) {
679
674
  await removeButton.click();
680
675
  await page.waitForTimeout(500);
@@ -684,6 +679,23 @@ export class GoodEggsClient {
684
679
  itemName: itemName.trim(),
685
680
  };
686
681
  }
682
+ // Fallback: use the quantity dropdown with value "0" to remove the item
683
+ // Good Eggs quantity dropdowns have a "Remove" option with value="0"
684
+ const quantitySelect = await cartItem.$('.summary-item__quantity select');
685
+ if (quantitySelect) {
686
+ try {
687
+ await quantitySelect.selectOption('0');
688
+ await page.waitForTimeout(1000);
689
+ return {
690
+ success: true,
691
+ message: `Successfully removed ${itemName.trim()} from cart`,
692
+ itemName: itemName.trim(),
693
+ };
694
+ }
695
+ catch {
696
+ // If selectOption('0') fails (e.g., no "0" option exists), continue to error path
697
+ }
698
+ }
687
699
  }
688
700
  }
689
701
  if (!itemFound) {