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/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Good Eggs MCP Server
|
|
2
|
+
|
|
3
|
+
MCP server for Good Eggs grocery shopping automation using Playwright. Search for groceries, manage favorites, add items to cart, and view past orders.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Search Groceries** - Search for any grocery item on Good Eggs
|
|
8
|
+
- **Manage Favorites** - Get, add, and remove favorite items
|
|
9
|
+
- **Get Product Details** - View detailed information about any product
|
|
10
|
+
- **Shopping Cart** - Add and remove items from your shopping cart
|
|
11
|
+
- **Find Freebies** - Find items priced at $0.00 on homepage and fresh-picks
|
|
12
|
+
- **Past Orders** - View your order history and reorder items
|
|
13
|
+
|
|
14
|
+
## Tools
|
|
15
|
+
|
|
16
|
+
| Tool | Description |
|
|
17
|
+
| ------------------------------ | --------------------------------------------------- |
|
|
18
|
+
| `search_for_grocery` | Search for groceries by keyword |
|
|
19
|
+
| `get_favorites` | Get your favorite/saved grocery items |
|
|
20
|
+
| `get_grocery_details` | Get detailed info about a specific product |
|
|
21
|
+
| `add_to_cart` | Add a product to your shopping cart |
|
|
22
|
+
| `search_for_freebie_groceries` | Find free items ($0.00) on homepage and fresh-picks |
|
|
23
|
+
| `get_list_of_past_order_dates` | Get dates of your past orders |
|
|
24
|
+
| `get_past_order_groceries` | Get items from a specific past order |
|
|
25
|
+
| `add_favorite` | Add a product to your favorites |
|
|
26
|
+
| `remove_favorite` | Remove a product from your favorites |
|
|
27
|
+
| `remove_from_cart` | Remove a product from your shopping cart |
|
|
28
|
+
|
|
29
|
+
## Quick Start
|
|
30
|
+
|
|
31
|
+
### Prerequisites
|
|
32
|
+
|
|
33
|
+
- Node.js 18+
|
|
34
|
+
- A Good Eggs account (create one at [goodeggs.com](https://www.goodeggs.com))
|
|
35
|
+
|
|
36
|
+
### Installation
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install
|
|
40
|
+
npm run build
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Configuration
|
|
44
|
+
|
|
45
|
+
Set the following environment variables:
|
|
46
|
+
|
|
47
|
+
| Variable | Required | Description | Default |
|
|
48
|
+
| -------------------- | -------- | ------------------------------- | ------- |
|
|
49
|
+
| `GOOD_EGGS_USERNAME` | Yes | Your Good Eggs account email | - |
|
|
50
|
+
| `GOOD_EGGS_PASSWORD` | Yes | Your Good Eggs account password | - |
|
|
51
|
+
| `HEADLESS` | No | Run browser in headless mode | `true` |
|
|
52
|
+
| `TIMEOUT` | No | Browser operation timeout (ms) | `30000` |
|
|
53
|
+
|
|
54
|
+
### Claude Desktop Configuration
|
|
55
|
+
|
|
56
|
+
Add to your `claude_desktop_config.json`:
|
|
57
|
+
|
|
58
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
59
|
+
|
|
60
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"mcpServers": {
|
|
65
|
+
"good-eggs": {
|
|
66
|
+
"command": "npx",
|
|
67
|
+
"args": ["-y", "good-eggs-mcp-server"],
|
|
68
|
+
"env": {
|
|
69
|
+
"GOOD_EGGS_USERNAME": "your-email@example.com",
|
|
70
|
+
"GOOD_EGGS_PASSWORD": "your-password"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Restart Claude Desktop to connect.
|
|
78
|
+
|
|
79
|
+
## Usage Examples
|
|
80
|
+
|
|
81
|
+
### Search for groceries
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
"Search for organic apples"
|
|
85
|
+
"Find gluten-free bread"
|
|
86
|
+
"Look for chicken breast"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### View and add favorites
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
"Show me my favorite items"
|
|
93
|
+
"What are my saved groceries?"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Add items to cart
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
"Add 2 of those apples to my cart"
|
|
100
|
+
"Put the organic milk in my basket"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Check deals
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
"What deals are available today?"
|
|
107
|
+
"Find any free items"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Reorder from past orders
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
"Show me my past orders"
|
|
114
|
+
"What did I order on January 3rd?"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## How It Works
|
|
118
|
+
|
|
119
|
+
This MCP server uses Playwright to automate a browser session with Good Eggs:
|
|
120
|
+
|
|
121
|
+
1. **On first tool use**: Launches a browser and logs into your Good Eggs account
|
|
122
|
+
2. **Browser session persists**: All subsequent tool calls reuse the same logged-in session
|
|
123
|
+
3. **Smart navigation**: Tools check if you're already on the right page to minimize navigation
|
|
124
|
+
4. **Stealth mode**: Uses playwright-extra with stealth plugin to avoid bot detection
|
|
125
|
+
|
|
126
|
+
## Development
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
# Install dependencies
|
|
130
|
+
npm run install-all
|
|
131
|
+
|
|
132
|
+
# Run in development mode
|
|
133
|
+
npm run dev
|
|
134
|
+
|
|
135
|
+
# Build
|
|
136
|
+
npm run build
|
|
137
|
+
|
|
138
|
+
# Run tests
|
|
139
|
+
npm test
|
|
140
|
+
|
|
141
|
+
# Lint
|
|
142
|
+
npm run lint
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Project Structure
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
good-eggs/
|
|
149
|
+
├── local/ # Local server implementation
|
|
150
|
+
│ └── src/
|
|
151
|
+
│ └── index.ts # Entry point with env validation
|
|
152
|
+
├── shared/ # Shared business logic
|
|
153
|
+
│ └── src/
|
|
154
|
+
│ ├── server.ts # GoodEggsClient with Playwright automation
|
|
155
|
+
│ ├── tools.ts # MCP tool definitions
|
|
156
|
+
│ ├── types.ts # TypeScript types
|
|
157
|
+
│ └── logging.ts # Logging utilities
|
|
158
|
+
├── tests/ # Test suites
|
|
159
|
+
├── package.json # Root workspace config
|
|
160
|
+
└── README.md
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Security Notes
|
|
164
|
+
|
|
165
|
+
- Your Good Eggs credentials are used only to log into your account
|
|
166
|
+
- The browser session runs locally on your machine
|
|
167
|
+
- No credentials are transmitted to any third-party services
|
|
168
|
+
- Consider using environment variables rather than hardcoding credentials
|
|
169
|
+
|
|
170
|
+
## Limitations
|
|
171
|
+
|
|
172
|
+
- Requires a valid Good Eggs account with delivery service in your area
|
|
173
|
+
- Browser automation may occasionally fail if Good Eggs updates their website
|
|
174
|
+
- Some operations (favorites, past orders) require account login
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
MIT
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Integration Test Server Entry Point with Mock Client Factory
|
|
4
|
+
*
|
|
5
|
+
* This file is used for integration testing with a mocked Good Eggs client.
|
|
6
|
+
* It uses the real MCP server but injects a mock client factory to avoid
|
|
7
|
+
* actual browser automation during CI tests.
|
|
8
|
+
*
|
|
9
|
+
* Note: The mock client is defined inline because TypeScript's rootDir
|
|
10
|
+
* constraints prevent importing from the tests/ directory.
|
|
11
|
+
*/
|
|
12
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
13
|
+
import { createMCPServer } from '../shared/index.js';
|
|
14
|
+
/**
|
|
15
|
+
* Creates a mock Good Eggs client for integration testing.
|
|
16
|
+
* This is kept inline to avoid TypeScript rootDir issues with importing from tests/.
|
|
17
|
+
*/
|
|
18
|
+
function createMockGoodEggsClient() {
|
|
19
|
+
const mockConfig = {
|
|
20
|
+
username: 'test@example.com',
|
|
21
|
+
password: 'testpassword',
|
|
22
|
+
headless: true,
|
|
23
|
+
timeout: 30000,
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
initialize: async () => {
|
|
27
|
+
// Mock initialization - no-op
|
|
28
|
+
},
|
|
29
|
+
searchGroceries: async (_query) => {
|
|
30
|
+
return [
|
|
31
|
+
{
|
|
32
|
+
url: 'https://www.goodeggs.com/product/123',
|
|
33
|
+
name: 'Organic Honeycrisp Apples',
|
|
34
|
+
brand: 'From Our Farmers',
|
|
35
|
+
price: '$4.99',
|
|
36
|
+
discount: '16% OFF',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
url: 'https://www.goodeggs.com/product/456',
|
|
40
|
+
name: 'Organic Fuji Apples',
|
|
41
|
+
brand: 'Hikari Farms',
|
|
42
|
+
price: '$2.99',
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
},
|
|
46
|
+
getFavorites: async () => {
|
|
47
|
+
return [
|
|
48
|
+
{
|
|
49
|
+
url: 'https://www.goodeggs.com/product/789',
|
|
50
|
+
name: 'Organic Milk',
|
|
51
|
+
brand: 'Clover',
|
|
52
|
+
price: '$6.99',
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
},
|
|
56
|
+
getGroceryDetails: async (_groceryUrl) => {
|
|
57
|
+
return {
|
|
58
|
+
url: 'https://www.goodeggs.com/product/123',
|
|
59
|
+
name: 'Organic Honeycrisp Apples',
|
|
60
|
+
brand: 'From Our Farmers',
|
|
61
|
+
price: '$4.99',
|
|
62
|
+
originalPrice: '$5.97',
|
|
63
|
+
discount: '16% OFF',
|
|
64
|
+
description: 'Delicious organic honeycrisp apples from local farmers.',
|
|
65
|
+
availability: ['Sun 1/4', 'Mon 1/5', 'Tue 1/6'],
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
addToCart: async (_groceryUrl, quantity) => {
|
|
69
|
+
return {
|
|
70
|
+
success: true,
|
|
71
|
+
message: `Successfully added ${quantity} x Organic Honeycrisp Apples to cart`,
|
|
72
|
+
itemName: 'Organic Honeycrisp Apples',
|
|
73
|
+
quantity,
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
searchFreebieGroceries: async () => {
|
|
77
|
+
return [
|
|
78
|
+
{
|
|
79
|
+
url: 'https://www.goodeggs.com/product/deal1',
|
|
80
|
+
name: 'Organic Cauliflower',
|
|
81
|
+
brand: 'Lakeside Organic Gardens',
|
|
82
|
+
price: '$3.99',
|
|
83
|
+
discount: '33% OFF',
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
},
|
|
87
|
+
getPastOrderDates: async () => {
|
|
88
|
+
return [
|
|
89
|
+
{
|
|
90
|
+
date: 'January 3, 2025',
|
|
91
|
+
total: '$45.67',
|
|
92
|
+
itemCount: 12,
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
},
|
|
96
|
+
getPastOrderGroceries: async (_orderDate) => {
|
|
97
|
+
return [
|
|
98
|
+
{
|
|
99
|
+
url: 'https://www.goodeggs.com/product/past1',
|
|
100
|
+
name: 'Celebration Truffles',
|
|
101
|
+
brand: 'Good Eggs Select',
|
|
102
|
+
price: '$34.49',
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
},
|
|
106
|
+
addFavorite: async (_groceryUrl) => {
|
|
107
|
+
return {
|
|
108
|
+
success: true,
|
|
109
|
+
message: 'Successfully added Organic Honeycrisp Apples to favorites',
|
|
110
|
+
itemName: 'Organic Honeycrisp Apples',
|
|
111
|
+
};
|
|
112
|
+
},
|
|
113
|
+
removeFavorite: async (_groceryUrl) => {
|
|
114
|
+
return {
|
|
115
|
+
success: true,
|
|
116
|
+
message: 'Successfully removed Organic Honeycrisp Apples from favorites',
|
|
117
|
+
itemName: 'Organic Honeycrisp Apples',
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
removeFromCart: async (_groceryUrl) => {
|
|
121
|
+
return {
|
|
122
|
+
success: true,
|
|
123
|
+
message: 'Successfully removed Organic Honeycrisp Apples from cart',
|
|
124
|
+
itemName: 'Organic Honeycrisp Apples',
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
getCurrentUrl: async () => {
|
|
128
|
+
return 'https://www.goodeggs.com/home';
|
|
129
|
+
},
|
|
130
|
+
close: async () => {
|
|
131
|
+
// Mock close - no-op
|
|
132
|
+
},
|
|
133
|
+
getConfig: () => {
|
|
134
|
+
return mockConfig;
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function main() {
|
|
139
|
+
const transport = new StdioServerTransport();
|
|
140
|
+
// Create client factory that returns our mock
|
|
141
|
+
const clientFactory = () => createMockGoodEggsClient();
|
|
142
|
+
const { server, registerHandlers } = createMCPServer();
|
|
143
|
+
await registerHandlers(server, clientFactory);
|
|
144
|
+
await server.connect(transport);
|
|
145
|
+
}
|
|
146
|
+
main().catch((error) => {
|
|
147
|
+
console.error('Server error:', error);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
});
|
package/build/index.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { createMCPServer } from '../shared/index.js';
|
|
4
|
+
import { logServerStart, logError, logWarning } from '../shared/logging.js';
|
|
5
|
+
// =============================================================================
|
|
6
|
+
// ENVIRONMENT VALIDATION
|
|
7
|
+
// =============================================================================
|
|
8
|
+
function validateEnvironment() {
|
|
9
|
+
const required = [
|
|
10
|
+
{
|
|
11
|
+
name: 'GOOD_EGGS_USERNAME',
|
|
12
|
+
description: 'Your Good Eggs account email address',
|
|
13
|
+
example: 'user@example.com',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'GOOD_EGGS_PASSWORD',
|
|
17
|
+
description: 'Your Good Eggs account password',
|
|
18
|
+
example: 'your-password',
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
const optional = [
|
|
22
|
+
{
|
|
23
|
+
name: 'HEADLESS',
|
|
24
|
+
description: 'Run browser in headless mode (true/false)',
|
|
25
|
+
defaultValue: 'true',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'TIMEOUT',
|
|
29
|
+
description: 'Default timeout for browser operations in milliseconds',
|
|
30
|
+
defaultValue: '30000',
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
const missing = required.filter(({ name }) => !process.env[name]);
|
|
34
|
+
if (missing.length > 0) {
|
|
35
|
+
logError('validateEnvironment', 'Missing required environment variables:');
|
|
36
|
+
missing.forEach(({ name, description, example }) => {
|
|
37
|
+
console.error(` - ${name}: ${description}`);
|
|
38
|
+
console.error(` Example: ${example}`);
|
|
39
|
+
});
|
|
40
|
+
if (optional.length > 0) {
|
|
41
|
+
console.error('\nOptional environment variables:');
|
|
42
|
+
optional.forEach(({ name, description, defaultValue }) => {
|
|
43
|
+
const defaultStr = defaultValue ? ` (default: ${defaultValue})` : '';
|
|
44
|
+
console.error(` - ${name}: ${description}${defaultStr}`);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
console.error('\n----------------------------------------');
|
|
48
|
+
console.error('Please set the required environment variables and try again.');
|
|
49
|
+
console.error('\nExample commands:');
|
|
50
|
+
missing.forEach(({ name, example }) => {
|
|
51
|
+
console.error(` export ${name}="${example}"`);
|
|
52
|
+
});
|
|
53
|
+
console.error('----------------------------------------\n');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
// Log configuration
|
|
57
|
+
const headless = process.env.HEADLESS !== 'false';
|
|
58
|
+
const timeout = process.env.TIMEOUT || '30000';
|
|
59
|
+
if (!headless) {
|
|
60
|
+
logWarning('config', 'Running in non-headless mode - browser window will be visible');
|
|
61
|
+
}
|
|
62
|
+
if (process.env.TIMEOUT) {
|
|
63
|
+
logWarning('config', `Custom timeout configured: ${timeout}ms`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// =============================================================================
|
|
67
|
+
// MAIN ENTRY POINT
|
|
68
|
+
// =============================================================================
|
|
69
|
+
async function main() {
|
|
70
|
+
// Step 1: Validate environment variables
|
|
71
|
+
validateEnvironment();
|
|
72
|
+
// Step 2: Create server using factory
|
|
73
|
+
const { server, registerHandlers, cleanup } = createMCPServer();
|
|
74
|
+
// Step 3: Register all handlers (tools)
|
|
75
|
+
await registerHandlers(server);
|
|
76
|
+
// Step 4: Set up graceful shutdown
|
|
77
|
+
const handleShutdown = async () => {
|
|
78
|
+
logWarning('shutdown', 'Received shutdown signal, closing browser...');
|
|
79
|
+
await cleanup();
|
|
80
|
+
process.exit(0);
|
|
81
|
+
};
|
|
82
|
+
process.on('SIGINT', handleShutdown);
|
|
83
|
+
process.on('SIGTERM', handleShutdown);
|
|
84
|
+
// Step 5: Start server with stdio transport
|
|
85
|
+
const transport = new StdioServerTransport();
|
|
86
|
+
await server.connect(transport);
|
|
87
|
+
logServerStart('Good Eggs');
|
|
88
|
+
}
|
|
89
|
+
// Run the server
|
|
90
|
+
main().catch((error) => {
|
|
91
|
+
logError('main', error);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "good-eggs-mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for Good Eggs grocery shopping with Playwright automation",
|
|
5
|
+
"main": "build/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"good-eggs-mcp-server": "./build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"build/**/*.js",
|
|
12
|
+
"build/**/*.d.ts",
|
|
13
|
+
"shared/**/*.js",
|
|
14
|
+
"shared/**/*.d.ts",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc && npm run build:integration",
|
|
19
|
+
"build:integration": "tsc -p tsconfig.integration.json",
|
|
20
|
+
"start": "node build/index.js",
|
|
21
|
+
"dev": "tsx src/index.ts",
|
|
22
|
+
"predev": "cd ../shared && npm run build && cd ../local && node setup-dev.js",
|
|
23
|
+
"prebuild": "cd ../shared && npm run build && cd ../local && node setup-dev.js",
|
|
24
|
+
"prepublishOnly": "node prepare-publish.js && node ../scripts/prepare-npm-readme.js",
|
|
25
|
+
"lint": "eslint . --ext .ts,.tsx",
|
|
26
|
+
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
|
27
|
+
"format": "prettier --write .",
|
|
28
|
+
"format:check": "prettier --check .",
|
|
29
|
+
"stage-publish": "npm version"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.19.1",
|
|
33
|
+
"playwright": "^1.49.1",
|
|
34
|
+
"playwright-extra": "^4.3.6",
|
|
35
|
+
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
36
|
+
"zod": "^3.24.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^22.10.6",
|
|
40
|
+
"tsx": "^4.19.4",
|
|
41
|
+
"typescript": "^5.7.3"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [],
|
|
44
|
+
"author": "PulseMCP",
|
|
45
|
+
"license": "MIT"
|
|
46
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { createMCPServer, GoodEggsClient, type IGoodEggsClient, type ClientFactory, } from './server.js';
|
|
2
|
+
export { createRegisterTools } from './tools.js';
|
|
3
|
+
export type { GroceryItem, GroceryDetails, PastOrder, CartResult, GoodEggsConfig, } from './types.js';
|
|
4
|
+
export { logServerStart, logError, logWarning, logDebug } from './logging.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
package/shared/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Core server exports
|
|
2
|
+
export { createMCPServer, GoodEggsClient, } from './server.js';
|
|
3
|
+
// Tools exports
|
|
4
|
+
export { createRegisterTools } from './tools.js';
|
|
5
|
+
// Logging exports (re-exported for convenience)
|
|
6
|
+
export { logServerStart, logError, logWarning, logDebug } from './logging.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging utilities for consistent output across MCP servers
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Log server startup message
|
|
6
|
+
*/
|
|
7
|
+
export declare function logServerStart(serverName: string, transport?: string): void;
|
|
8
|
+
/**
|
|
9
|
+
* Log an error with context
|
|
10
|
+
*/
|
|
11
|
+
export declare function logError(context: string, error: unknown): void;
|
|
12
|
+
/**
|
|
13
|
+
* Log a warning
|
|
14
|
+
*/
|
|
15
|
+
export declare function logWarning(context: string, message: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Log debug information (only in development)
|
|
18
|
+
*/
|
|
19
|
+
export declare function logDebug(context: string, message: string): void;
|
|
20
|
+
//# sourceMappingURL=logging.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logging utilities for consistent output across MCP servers
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Log server startup message
|
|
6
|
+
*/
|
|
7
|
+
export function logServerStart(serverName, transport = 'stdio') {
|
|
8
|
+
console.error(`MCP server ${serverName} running on ${transport}`);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Log an error with context
|
|
12
|
+
*/
|
|
13
|
+
export function logError(context, error) {
|
|
14
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
15
|
+
const stack = error instanceof Error ? error.stack : undefined;
|
|
16
|
+
console.error(`[ERROR] ${context}: ${message}`);
|
|
17
|
+
if (stack) {
|
|
18
|
+
console.error(stack);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Log a warning
|
|
23
|
+
*/
|
|
24
|
+
export function logWarning(context, message) {
|
|
25
|
+
console.error(`[WARN] ${context}: ${message}`);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Log debug information (only in development)
|
|
29
|
+
*/
|
|
30
|
+
export function logDebug(context, message) {
|
|
31
|
+
if (process.env.NODE_ENV === 'development' || process.env.DEBUG) {
|
|
32
|
+
console.error(`[DEBUG] ${context}: ${message}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import type { GoodEggsConfig, GroceryItem, GroceryDetails, PastOrder, CartResult } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Good Eggs client interface
|
|
5
|
+
* Defines all methods for interacting with the Good Eggs grocery store
|
|
6
|
+
*/
|
|
7
|
+
export interface IGoodEggsClient {
|
|
8
|
+
/**
|
|
9
|
+
* Initialize the browser and log in to Good Eggs
|
|
10
|
+
* Must be called before using other methods
|
|
11
|
+
*/
|
|
12
|
+
initialize(): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Search for groceries
|
|
15
|
+
*/
|
|
16
|
+
searchGroceries(query: string): Promise<GroceryItem[]>;
|
|
17
|
+
/**
|
|
18
|
+
* Get user's favorite items
|
|
19
|
+
*/
|
|
20
|
+
getFavorites(): Promise<GroceryItem[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Get detailed information about a specific grocery item
|
|
23
|
+
*/
|
|
24
|
+
getGroceryDetails(groceryUrl: string): Promise<GroceryDetails>;
|
|
25
|
+
/**
|
|
26
|
+
* Add an item to the shopping cart
|
|
27
|
+
*/
|
|
28
|
+
addToCart(groceryUrl: string, quantity: number): Promise<CartResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Search for freebie/deal groceries
|
|
31
|
+
*/
|
|
32
|
+
searchFreebieGroceries(): Promise<GroceryItem[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Get list of past order dates
|
|
35
|
+
*/
|
|
36
|
+
getPastOrderDates(): Promise<PastOrder[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Get groceries from a specific past order
|
|
39
|
+
*/
|
|
40
|
+
getPastOrderGroceries(orderDate: string): Promise<GroceryItem[]>;
|
|
41
|
+
/**
|
|
42
|
+
* Add an item to favorites
|
|
43
|
+
*/
|
|
44
|
+
addFavorite(groceryUrl: string): Promise<CartResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Remove an item from favorites
|
|
47
|
+
*/
|
|
48
|
+
removeFavorite(groceryUrl: string): Promise<CartResult>;
|
|
49
|
+
/**
|
|
50
|
+
* Remove an item from the cart
|
|
51
|
+
*/
|
|
52
|
+
removeFromCart(groceryUrl: string): Promise<CartResult>;
|
|
53
|
+
/**
|
|
54
|
+
* Get the current page URL
|
|
55
|
+
*/
|
|
56
|
+
getCurrentUrl(): Promise<string>;
|
|
57
|
+
/**
|
|
58
|
+
* Close the browser
|
|
59
|
+
*/
|
|
60
|
+
close(): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Get the configuration
|
|
63
|
+
*/
|
|
64
|
+
getConfig(): GoodEggsConfig;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Good Eggs client implementation using Playwright
|
|
68
|
+
*/
|
|
69
|
+
export declare class GoodEggsClient implements IGoodEggsClient {
|
|
70
|
+
private browser;
|
|
71
|
+
private context;
|
|
72
|
+
private page;
|
|
73
|
+
private config;
|
|
74
|
+
private isInitialized;
|
|
75
|
+
constructor(config: GoodEggsConfig);
|
|
76
|
+
private ensureBrowser;
|
|
77
|
+
initialize(): Promise<void>;
|
|
78
|
+
searchGroceries(query: string): Promise<GroceryItem[]>;
|
|
79
|
+
getFavorites(): Promise<GroceryItem[]>;
|
|
80
|
+
getGroceryDetails(groceryUrl: string): Promise<GroceryDetails>;
|
|
81
|
+
addToCart(groceryUrl: string, quantity: number): Promise<CartResult>;
|
|
82
|
+
searchFreebieGroceries(): Promise<GroceryItem[]>;
|
|
83
|
+
getPastOrderDates(): Promise<PastOrder[]>;
|
|
84
|
+
getPastOrderGroceries(orderDate: string): Promise<GroceryItem[]>;
|
|
85
|
+
addFavorite(groceryUrl: string): Promise<CartResult>;
|
|
86
|
+
removeFavorite(groceryUrl: string): Promise<CartResult>;
|
|
87
|
+
removeFromCart(groceryUrl: string): Promise<CartResult>;
|
|
88
|
+
getCurrentUrl(): Promise<string>;
|
|
89
|
+
close(): Promise<void>;
|
|
90
|
+
getConfig(): GoodEggsConfig;
|
|
91
|
+
}
|
|
92
|
+
export type ClientFactory = () => IGoodEggsClient;
|
|
93
|
+
export declare function createMCPServer(): {
|
|
94
|
+
server: Server<{
|
|
95
|
+
method: string;
|
|
96
|
+
params?: {
|
|
97
|
+
[x: string]: unknown;
|
|
98
|
+
_meta?: {
|
|
99
|
+
[x: string]: unknown;
|
|
100
|
+
progressToken?: string | number | undefined;
|
|
101
|
+
} | undefined;
|
|
102
|
+
} | undefined;
|
|
103
|
+
}, {
|
|
104
|
+
method: string;
|
|
105
|
+
params?: {
|
|
106
|
+
[x: string]: unknown;
|
|
107
|
+
_meta?: {
|
|
108
|
+
[x: string]: unknown;
|
|
109
|
+
} | undefined;
|
|
110
|
+
} | undefined;
|
|
111
|
+
}, {
|
|
112
|
+
[x: string]: unknown;
|
|
113
|
+
_meta?: {
|
|
114
|
+
[x: string]: unknown;
|
|
115
|
+
} | undefined;
|
|
116
|
+
}>;
|
|
117
|
+
registerHandlers: (server: Server, clientFactory?: ClientFactory) => Promise<void>;
|
|
118
|
+
cleanup: () => Promise<void>;
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=server.d.ts.map
|