continentept-mcp 0.2.0 → 0.3.1
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/CHANGELOG.md +16 -1
- package/README.md +23 -10
- package/dist/cli.js +2 -9
- package/dist/clients/policy.d.ts +2 -2
- package/dist/clients/storefront.js +12 -13
- package/dist/domain/errors.d.ts +2 -0
- package/dist/domain/errors.js +1 -1
- package/dist/domain/models.d.ts +2 -0
- package/dist/domain/outcomes.d.ts +3 -0
- package/dist/mcp/contracts.d.ts +25 -0
- package/dist/parsers/cart.d.ts +2 -2
- package/dist/parsers/catalog.d.ts +1 -1
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +10 -1
- package/dist/services/catalog.d.ts +2 -2
- package/dist/session/chromium.d.ts +25 -0
- package/dist/session/chromium.js +74 -0
- package/docs/configuration.md +3 -1
- package/docs/tools.md +1 -0
- package/docs/troubleshooting.md +2 -1
- package/package.json +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,19 @@ All notable changes to this project are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.1] - 2026-10-15
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Listed in the official [MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.andredelgado/continente-mcp`, with both the npm package and the Claude Desktop extension. Every release updates the listing.
|
|
14
|
+
|
|
15
|
+
## [0.3.0] - 2026-10-15
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- One-click Claude Desktop extension (`continente-mcp.mcpb`) attached to every release. It asks for your email and password at install time.
|
|
20
|
+
- Chromium downloads automatically the first time it is needed; `install-browser` is now optional. While it downloads, tools return a retryable `browser_unavailable` error explaining the wait.
|
|
21
|
+
|
|
9
22
|
## [0.2.0] - 2026-10-15
|
|
10
23
|
|
|
11
24
|
### Added
|
|
@@ -28,6 +41,8 @@ All notable changes to this project are documented here. The format follows
|
|
|
28
41
|
- Automatic sign-in from environment variables or a private credentials file, and a `login` command.
|
|
29
42
|
- The `basket-planner` skill for planning a shopping list and updating the basket.
|
|
30
43
|
|
|
31
|
-
[Unreleased]: https://github.com/andredelgado/continente-mcp/compare/v0.
|
|
44
|
+
[Unreleased]: https://github.com/andredelgado/continente-mcp/compare/v0.3.1...HEAD
|
|
45
|
+
[0.3.1]: https://github.com/andredelgado/continente-mcp/compare/v0.3.0...v0.3.1
|
|
46
|
+
[0.3.0]: https://github.com/andredelgado/continente-mcp/compare/v0.2.0...v0.3.0
|
|
32
47
|
[0.2.0]: https://github.com/andredelgado/continente-mcp/compare/v0.1.0...v0.2.0
|
|
33
48
|
[0.1.0]: https://github.com/andredelgado/continente-mcp/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -29,20 +29,29 @@ on the website.
|
|
|
29
29
|
|
|
30
30
|
## Requirements
|
|
31
31
|
|
|
32
|
-
- Node.js 22 or newer
|
|
33
32
|
- A Continente.pt account for account features (search and product details work without one)
|
|
33
|
+
- Claude Desktop on macOS or Windows for the one-click install, or Node.js 22 or newer for
|
|
34
|
+
any other MCP client
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
The server drives the website with Chromium, which it downloads automatically the first time
|
|
37
|
+
it needs it (about 150 MB, once).
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
## Install in Claude Desktop (one click)
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
1. Download [**continente-mcp.mcpb**](https://github.com/andredelgado/continente-mcp/releases/latest/download/continente-mcp.mcpb)
|
|
42
|
+
from the latest release.
|
|
43
|
+
2. Open it. Claude Desktop shows an install dialog; click **Install**.
|
|
44
|
+
3. Enter your Continente email and password when asked. Claude Desktop keeps the password
|
|
45
|
+
in its secure settings storage.
|
|
42
46
|
|
|
43
|
-
|
|
47
|
+
That's it. The extension updates when you install a newer `.mcpb`. The server is also listed
|
|
48
|
+
in the [MCP Registry](https://registry.modelcontextprotocol.io) as
|
|
49
|
+
`io.github.andredelgado/continente-mcp`, so clients that browse the registry can find it. To use 1Password instead
|
|
50
|
+
of storing the password in Claude Desktop, use the manual setup below.
|
|
44
51
|
|
|
45
|
-
|
|
52
|
+
## Manual setup (any MCP client)
|
|
53
|
+
|
|
54
|
+
**1. Save your credentials** in `~/.continentept-mcp/credentials.env` (see
|
|
46
55
|
[configuration](docs/configuration.md) for other options):
|
|
47
56
|
|
|
48
57
|
```sh
|
|
@@ -60,7 +69,7 @@ Optionally check that login works:
|
|
|
60
69
|
npx -y continentept-mcp login
|
|
61
70
|
```
|
|
62
71
|
|
|
63
|
-
**
|
|
72
|
+
**2. Add the server to your MCP client.**
|
|
64
73
|
|
|
65
74
|
Claude Code:
|
|
66
75
|
|
|
@@ -84,6 +93,10 @@ Claude Desktop, Cursor and other clients (`claude_desktop_config.json`, `mcp.jso
|
|
|
84
93
|
To keep the credentials file elsewhere, add
|
|
85
94
|
`"env": { "CONTINENTE_CREDENTIALS_FILE": "/absolute/path/to/credentials.env" }`.
|
|
86
95
|
|
|
96
|
+
Chromium downloads itself on first use. To fetch it ahead of time, run
|
|
97
|
+
`npx -y continentept-mcp install-browser` (on Linux, add `--with-deps` for the system
|
|
98
|
+
libraries it needs).
|
|
99
|
+
|
|
87
100
|
Then ask your assistant something like *"Add semi-skimmed milk and a dozen eggs to my
|
|
88
101
|
Continente cart"* or *"What do I usually buy? Build me a list for this week."*
|
|
89
102
|
|
|
@@ -129,7 +142,7 @@ then apply it automatically whenever you ask about groceries.
|
|
|
129
142
|
```text
|
|
130
143
|
continentept-mcp Start the MCP server on stdio
|
|
131
144
|
continentept-mcp login Sign in and save the session (--show-browser to watch)
|
|
132
|
-
continentept-mcp install-browser Download Chromium (extra arguments go to Playwright)
|
|
145
|
+
continentept-mcp install-browser Download Chromium now instead of on first use (extra arguments go to Playwright)
|
|
133
146
|
continentept-mcp --version
|
|
134
147
|
```
|
|
135
148
|
|
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
|
-
import { createRequire } from 'node:module';
|
|
4
|
-
import { dirname, join } from 'node:path';
|
|
5
|
-
import { spawnSync } from 'node:child_process';
|
|
6
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
4
|
import { createShoppingApplication } from './runtime.js';
|
|
8
5
|
import { runAutoLogin } from './auto-login.js';
|
|
9
6
|
import { isMainModule } from './main-module.js';
|
|
7
|
+
import { runChromiumInstall } from './session/chromium.js';
|
|
10
8
|
const USAGE = `Usage: continentept-mcp [command]
|
|
11
9
|
|
|
12
10
|
Commands:
|
|
@@ -57,11 +55,6 @@ export async function connectStdioApplication(application) {
|
|
|
57
55
|
throw error;
|
|
58
56
|
}
|
|
59
57
|
}
|
|
60
|
-
function installBrowser(extra) {
|
|
61
|
-
const playwright = dirname(createRequire(import.meta.url).resolve('playwright/package.json'));
|
|
62
|
-
const result = spawnSync(process.execPath, [join(playwright, 'cli.js'), 'install', 'chromium', ...extra], { stdio: 'inherit' });
|
|
63
|
-
return result.status ?? 1;
|
|
64
|
-
}
|
|
65
58
|
export async function main(args) {
|
|
66
59
|
const [command, ...rest] = args;
|
|
67
60
|
switch (command) {
|
|
@@ -78,7 +71,7 @@ export async function main(args) {
|
|
|
78
71
|
return 1;
|
|
79
72
|
}
|
|
80
73
|
case 'install-browser':
|
|
81
|
-
return
|
|
74
|
+
return runChromiumInstall(rest);
|
|
82
75
|
case '-v':
|
|
83
76
|
case '--version':
|
|
84
77
|
console.log(packageVersion());
|
package/dist/clients/policy.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface HttpResponse {
|
|
|
7
7
|
}
|
|
8
8
|
/** Only known authentication evidence triggers recovery; arbitrary upstream failures do not. */
|
|
9
9
|
export declare function responseStatus(response: HttpResponse | null, finalUrl: string): import("../domain/result.js").Result<undefined, {
|
|
10
|
-
code: "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
10
|
+
code: "browser_unavailable" | "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
11
11
|
message: string;
|
|
12
12
|
retryable: boolean;
|
|
13
13
|
issues?: {
|
|
@@ -16,7 +16,7 @@ export declare function responseStatus(response: HttpResponse | null, finalUrl:
|
|
|
16
16
|
}[] | undefined;
|
|
17
17
|
}>;
|
|
18
18
|
export declare function authenticatedPayload(input: unknown): import("../domain/result.js").Result<unknown, {
|
|
19
|
-
code: "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
19
|
+
code: "browser_unavailable" | "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
20
20
|
message: string;
|
|
21
21
|
retryable: boolean;
|
|
22
22
|
issues?: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { requestIO, requestTimeout, checkRequest, RequestStopped, reportProgress } from '../session/request.js';
|
|
2
|
+
import { BrowserUnavailable } from '../session/chromium.js';
|
|
2
3
|
import { failure, success } from '../domain/index.js';
|
|
3
4
|
import { parseProductSearchPage, parseSearchPagination, parseFavoritesPageData, STOREFRONT_ORIGIN, storefrontUrl } from '../parsers/catalog.js';
|
|
4
5
|
import { responseStatus, authenticatedPayload } from './policy.js';
|
|
@@ -6,6 +7,12 @@ import { orderHistoryUrl } from '../parsers/orders.js';
|
|
|
6
7
|
import { field } from '../parsers/records.js';
|
|
7
8
|
export const CART_SUMMARY_URL = `${STOREFRONT_ORIGIN}/on/demandware.store/Sites-continente-Site/default/Cart-MiniCartShow`;
|
|
8
9
|
const ORDER_DETAIL_PATHS = ['/conta/detalhe-encomenda/', '/detalhe-encomenda'];
|
|
10
|
+
/** Map an error from starting or using the browser; cancellation keeps propagating. */
|
|
11
|
+
function browserFailure(error) {
|
|
12
|
+
if (error instanceof RequestStopped)
|
|
13
|
+
throw error;
|
|
14
|
+
return error instanceof BrowserUnavailable ? { ok: false, error: error.toolError } : failure('upstream_unavailable');
|
|
15
|
+
}
|
|
9
16
|
const productPath = (reference) => `/produto/${reference.endsWith('.html') ? reference : `${reference}.html`}`;
|
|
10
17
|
export class StorefrontClient {
|
|
11
18
|
session;
|
|
@@ -30,9 +37,7 @@ export class StorefrontClient {
|
|
|
30
37
|
return success(lease);
|
|
31
38
|
}
|
|
32
39
|
catch (error) {
|
|
33
|
-
|
|
34
|
-
throw error;
|
|
35
|
-
return failure('upstream_unavailable');
|
|
40
|
+
return browserFailure(error);
|
|
36
41
|
}
|
|
37
42
|
}
|
|
38
43
|
async html(path, marker = 'main, [role="main"], .product-line, a[href*="/produto/"]') {
|
|
@@ -125,7 +130,7 @@ async function readContinuation(site, url) {
|
|
|
125
130
|
return status.ok ? success(await site.io(lease, () => response.text())) : status;
|
|
126
131
|
}
|
|
127
132
|
catch (error) {
|
|
128
|
-
return
|
|
133
|
+
return error instanceof RequestStopped ? failure(error.code) : browserFailure(error);
|
|
129
134
|
}
|
|
130
135
|
}
|
|
131
136
|
export class FavoritesClient {
|
|
@@ -196,9 +201,7 @@ export class CartClient {
|
|
|
196
201
|
return authenticatedPayload(data);
|
|
197
202
|
}
|
|
198
203
|
catch (error) {
|
|
199
|
-
|
|
200
|
-
throw error;
|
|
201
|
-
return failure('upstream_unavailable');
|
|
204
|
+
return browserFailure(error);
|
|
202
205
|
}
|
|
203
206
|
}
|
|
204
207
|
async fetchProductForm(reference) {
|
|
@@ -264,9 +267,7 @@ export class CartClient {
|
|
|
264
267
|
});
|
|
265
268
|
}
|
|
266
269
|
catch (error) {
|
|
267
|
-
|
|
268
|
-
throw error;
|
|
269
|
-
return failure('upstream_unavailable');
|
|
270
|
+
return browserFailure(error);
|
|
270
271
|
}
|
|
271
272
|
}
|
|
272
273
|
}
|
|
@@ -288,9 +289,7 @@ export class OrdersClient {
|
|
|
288
289
|
return success(await this.site.io(response.value, () => page.content()));
|
|
289
290
|
}
|
|
290
291
|
catch (error) {
|
|
291
|
-
|
|
292
|
-
throw error;
|
|
293
|
-
return failure('upstream_unavailable');
|
|
292
|
+
return browserFailure(error);
|
|
294
293
|
}
|
|
295
294
|
}
|
|
296
295
|
async fetchOrderLines(url) {
|
package/dist/domain/errors.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const ToolErrorCodeSchema: z.ZodEnum<{
|
|
3
|
+
browser_unavailable: "browser_unavailable";
|
|
3
4
|
cache_unavailable: "cache_unavailable";
|
|
4
5
|
cancelled: "cancelled";
|
|
5
6
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -18,6 +19,7 @@ export declare const ToolErrorCodeSchema: z.ZodEnum<{
|
|
|
18
19
|
}>;
|
|
19
20
|
export declare const ToolErrorSchema: z.ZodObject<{
|
|
20
21
|
code: z.ZodEnum<{
|
|
22
|
+
browser_unavailable: "browser_unavailable";
|
|
21
23
|
cache_unavailable: "cache_unavailable";
|
|
22
24
|
cancelled: "cancelled";
|
|
23
25
|
cart_change_rejected: "cart_change_rejected";
|
package/dist/domain/errors.js
CHANGED
|
@@ -4,7 +4,7 @@ export const ToolErrorCodeSchema = z.enum([
|
|
|
4
4
|
'not_found', 'sale_rules_unknown', 'quantity_below_minimum',
|
|
5
5
|
'cart_change_rejected', 'cart_change_unconfirmed', 'cache_unavailable',
|
|
6
6
|
'order_details_unavailable',
|
|
7
|
-
'cancelled', 'deadline_exceeded', 'server_closed', 'queue_full',
|
|
7
|
+
'cancelled', 'deadline_exceeded', 'server_closed', 'queue_full', 'browser_unavailable',
|
|
8
8
|
]);
|
|
9
9
|
export const ToolErrorSchema = z.strictObject({
|
|
10
10
|
code: ToolErrorCodeSchema,
|
package/dist/domain/models.d.ts
CHANGED
|
@@ -176,6 +176,7 @@ export declare const OrderSchema: z.ZodObject<{
|
|
|
176
176
|
status: z.ZodLiteral<"unavailable">;
|
|
177
177
|
error: z.ZodObject<{
|
|
178
178
|
code: z.ZodEnum<{
|
|
179
|
+
browser_unavailable: "browser_unavailable";
|
|
179
180
|
cache_unavailable: "cache_unavailable";
|
|
180
181
|
cancelled: "cancelled";
|
|
181
182
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -317,6 +318,7 @@ export declare const ProductDetailsSchema: z.ZodObject<{
|
|
|
317
318
|
status: z.ZodLiteral<"unavailable">;
|
|
318
319
|
error: z.ZodObject<{
|
|
319
320
|
code: z.ZodEnum<{
|
|
321
|
+
browser_unavailable: "browser_unavailable";
|
|
320
322
|
cache_unavailable: "cache_unavailable";
|
|
321
323
|
cancelled: "cancelled";
|
|
322
324
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -42,6 +42,7 @@ export declare const CartMutationResultSchema: z.ZodDiscriminatedUnion<[z.ZodObj
|
|
|
42
42
|
outcome: z.ZodLiteral<"not_applied">;
|
|
43
43
|
error: z.ZodObject<{
|
|
44
44
|
code: z.ZodEnum<{
|
|
45
|
+
browser_unavailable: "browser_unavailable";
|
|
45
46
|
cache_unavailable: "cache_unavailable";
|
|
46
47
|
cancelled: "cancelled";
|
|
47
48
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -80,6 +81,7 @@ export declare const CartMutationResultSchema: z.ZodDiscriminatedUnion<[z.ZodObj
|
|
|
80
81
|
outcome: z.ZodLiteral<"unknown">;
|
|
81
82
|
error: z.ZodObject<{
|
|
82
83
|
code: z.ZodEnum<{
|
|
84
|
+
browser_unavailable: "browser_unavailable";
|
|
83
85
|
cache_unavailable: "cache_unavailable";
|
|
84
86
|
cancelled: "cancelled";
|
|
85
87
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -119,6 +121,7 @@ export declare function pageResultSchema<T extends z.ZodType>(item: T): z.ZodObj
|
|
|
119
121
|
}>;
|
|
120
122
|
failures: z.ZodArray<z.ZodObject<{
|
|
121
123
|
code: z.ZodEnum<{
|
|
124
|
+
browser_unavailable: "browser_unavailable";
|
|
122
125
|
cache_unavailable: "cache_unavailable";
|
|
123
126
|
cancelled: "cancelled";
|
|
124
127
|
cart_change_rejected: "cart_change_rejected";
|
package/dist/mcp/contracts.d.ts
CHANGED
|
@@ -44,6 +44,7 @@ export declare const PublicErrorSchema: z.ZodObject<{
|
|
|
44
44
|
code: z.ZodString;
|
|
45
45
|
}, z.core.$strict>>>;
|
|
46
46
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
47
|
+
browser_unavailable: "browser_unavailable";
|
|
47
48
|
cache_unavailable: "cache_unavailable";
|
|
48
49
|
cancelled: "cancelled";
|
|
49
50
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -74,6 +75,7 @@ export declare const ErrorResultSchema: z.ZodObject<{
|
|
|
74
75
|
code: z.ZodString;
|
|
75
76
|
}, z.core.$strict>>>;
|
|
76
77
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
78
|
+
browser_unavailable: "browser_unavailable";
|
|
77
79
|
cache_unavailable: "cache_unavailable";
|
|
78
80
|
cancelled: "cancelled";
|
|
79
81
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -115,6 +117,7 @@ export declare const ExecutionErrorSchema: z.ZodObject<{
|
|
|
115
117
|
code: z.ZodString;
|
|
116
118
|
}, z.core.$strict>>>;
|
|
117
119
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
120
|
+
browser_unavailable: "browser_unavailable";
|
|
118
121
|
cache_unavailable: "cache_unavailable";
|
|
119
122
|
cancelled: "cancelled";
|
|
120
123
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -164,6 +167,7 @@ export declare function outputSchema<T extends z.ZodType>(data: T, extra?: z.Zod
|
|
|
164
167
|
code: z.ZodString;
|
|
165
168
|
}, z.core.$strict>>>;
|
|
166
169
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
170
|
+
browser_unavailable: "browser_unavailable";
|
|
167
171
|
cache_unavailable: "cache_unavailable";
|
|
168
172
|
cancelled: "cancelled";
|
|
169
173
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -220,6 +224,7 @@ export declare const SearchData: z.ZodObject<{
|
|
|
220
224
|
}>;
|
|
221
225
|
failures: z.ZodArray<z.ZodObject<{
|
|
222
226
|
code: z.ZodEnum<{
|
|
227
|
+
browser_unavailable: "browser_unavailable";
|
|
223
228
|
cache_unavailable: "cache_unavailable";
|
|
224
229
|
cancelled: "cancelled";
|
|
225
230
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -314,6 +319,7 @@ export declare const OrdersData: z.ZodObject<{
|
|
|
314
319
|
status: z.ZodLiteral<"unavailable">;
|
|
315
320
|
error: z.ZodObject<{
|
|
316
321
|
code: z.ZodEnum<{
|
|
322
|
+
browser_unavailable: "browser_unavailable";
|
|
317
323
|
cache_unavailable: "cache_unavailable";
|
|
318
324
|
cancelled: "cancelled";
|
|
319
325
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -348,6 +354,7 @@ export declare const OrdersData: z.ZodObject<{
|
|
|
348
354
|
}>;
|
|
349
355
|
failures: z.ZodArray<z.ZodObject<{
|
|
350
356
|
code: z.ZodEnum<{
|
|
357
|
+
browser_unavailable: "browser_unavailable";
|
|
351
358
|
cache_unavailable: "cache_unavailable";
|
|
352
359
|
cancelled: "cancelled";
|
|
353
360
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -384,6 +391,7 @@ export declare const OrdersData: z.ZodObject<{
|
|
|
384
391
|
orderNumber: z.ZodNullable<z.core.$ZodBranded<z.ZodString, "OrderNumber", "out">>;
|
|
385
392
|
error: z.ZodObject<{
|
|
386
393
|
code: z.ZodEnum<{
|
|
394
|
+
browser_unavailable: "browser_unavailable";
|
|
387
395
|
cache_unavailable: "cache_unavailable";
|
|
388
396
|
cancelled: "cancelled";
|
|
389
397
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -445,6 +453,7 @@ export declare const FrequencyData: z.ZodObject<{
|
|
|
445
453
|
orderNumber: z.ZodNullable<z.core.$ZodBranded<z.ZodString, "OrderNumber", "out">>;
|
|
446
454
|
error: z.ZodObject<{
|
|
447
455
|
code: z.ZodEnum<{
|
|
456
|
+
browser_unavailable: "browser_unavailable";
|
|
448
457
|
cache_unavailable: "cache_unavailable";
|
|
449
458
|
cancelled: "cancelled";
|
|
450
459
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -508,6 +517,7 @@ export declare const SearchOutput: z.ZodObject<{
|
|
|
508
517
|
}>;
|
|
509
518
|
failures: z.ZodArray<z.ZodObject<{
|
|
510
519
|
code: z.ZodEnum<{
|
|
520
|
+
browser_unavailable: "browser_unavailable";
|
|
511
521
|
cache_unavailable: "cache_unavailable";
|
|
512
522
|
cancelled: "cancelled";
|
|
513
523
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -543,6 +553,7 @@ export declare const SearchOutput: z.ZodObject<{
|
|
|
543
553
|
code: z.ZodString;
|
|
544
554
|
}, z.core.$strict>>>;
|
|
545
555
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
556
|
+
browser_unavailable: "browser_unavailable";
|
|
546
557
|
cache_unavailable: "cache_unavailable";
|
|
547
558
|
cancelled: "cancelled";
|
|
548
559
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -621,6 +632,7 @@ export declare const FavoritesOutput: z.ZodObject<{
|
|
|
621
632
|
code: z.ZodString;
|
|
622
633
|
}, z.core.$strict>>>;
|
|
623
634
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
635
|
+
browser_unavailable: "browser_unavailable";
|
|
624
636
|
cache_unavailable: "cache_unavailable";
|
|
625
637
|
cancelled: "cancelled";
|
|
626
638
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -715,6 +727,7 @@ export declare const CartOutput: z.ZodObject<{
|
|
|
715
727
|
code: z.ZodString;
|
|
716
728
|
}, z.core.$strict>>>;
|
|
717
729
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
730
|
+
browser_unavailable: "browser_unavailable";
|
|
718
731
|
cache_unavailable: "cache_unavailable";
|
|
719
732
|
cancelled: "cancelled";
|
|
720
733
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -792,6 +805,7 @@ export declare const MutationOutput: z.ZodObject<{
|
|
|
792
805
|
code: z.ZodString;
|
|
793
806
|
}, z.core.$strict>>>;
|
|
794
807
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
808
|
+
browser_unavailable: "browser_unavailable";
|
|
795
809
|
cache_unavailable: "cache_unavailable";
|
|
796
810
|
cancelled: "cancelled";
|
|
797
811
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -869,6 +883,7 @@ export declare const OrdersOutput: z.ZodObject<{
|
|
|
869
883
|
status: z.ZodLiteral<"unavailable">;
|
|
870
884
|
error: z.ZodObject<{
|
|
871
885
|
code: z.ZodEnum<{
|
|
886
|
+
browser_unavailable: "browser_unavailable";
|
|
872
887
|
cache_unavailable: "cache_unavailable";
|
|
873
888
|
cancelled: "cancelled";
|
|
874
889
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -903,6 +918,7 @@ export declare const OrdersOutput: z.ZodObject<{
|
|
|
903
918
|
}>;
|
|
904
919
|
failures: z.ZodArray<z.ZodObject<{
|
|
905
920
|
code: z.ZodEnum<{
|
|
921
|
+
browser_unavailable: "browser_unavailable";
|
|
906
922
|
cache_unavailable: "cache_unavailable";
|
|
907
923
|
cancelled: "cancelled";
|
|
908
924
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -939,6 +955,7 @@ export declare const OrdersOutput: z.ZodObject<{
|
|
|
939
955
|
orderNumber: z.ZodNullable<z.core.$ZodBranded<z.ZodString, "OrderNumber", "out">>;
|
|
940
956
|
error: z.ZodObject<{
|
|
941
957
|
code: z.ZodEnum<{
|
|
958
|
+
browser_unavailable: "browser_unavailable";
|
|
942
959
|
cache_unavailable: "cache_unavailable";
|
|
943
960
|
cancelled: "cancelled";
|
|
944
961
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -974,6 +991,7 @@ export declare const OrdersOutput: z.ZodObject<{
|
|
|
974
991
|
code: z.ZodString;
|
|
975
992
|
}, z.core.$strict>>>;
|
|
976
993
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
994
|
+
browser_unavailable: "browser_unavailable";
|
|
977
995
|
cache_unavailable: "cache_unavailable";
|
|
978
996
|
cancelled: "cancelled";
|
|
979
997
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -1051,6 +1069,7 @@ export declare const SingleOrderOutput: z.ZodObject<{
|
|
|
1051
1069
|
status: z.ZodLiteral<"unavailable">;
|
|
1052
1070
|
error: z.ZodObject<{
|
|
1053
1071
|
code: z.ZodEnum<{
|
|
1072
|
+
browser_unavailable: "browser_unavailable";
|
|
1054
1073
|
cache_unavailable: "cache_unavailable";
|
|
1055
1074
|
cancelled: "cancelled";
|
|
1056
1075
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -1090,6 +1109,7 @@ export declare const SingleOrderOutput: z.ZodObject<{
|
|
|
1090
1109
|
code: z.ZodString;
|
|
1091
1110
|
}, z.core.$strict>>>;
|
|
1092
1111
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
1112
|
+
browser_unavailable: "browser_unavailable";
|
|
1093
1113
|
cache_unavailable: "cache_unavailable";
|
|
1094
1114
|
cancelled: "cancelled";
|
|
1095
1115
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -1164,6 +1184,7 @@ export declare const FrequencyOutput: z.ZodObject<{
|
|
|
1164
1184
|
orderNumber: z.ZodNullable<z.core.$ZodBranded<z.ZodString, "OrderNumber", "out">>;
|
|
1165
1185
|
error: z.ZodObject<{
|
|
1166
1186
|
code: z.ZodEnum<{
|
|
1187
|
+
browser_unavailable: "browser_unavailable";
|
|
1167
1188
|
cache_unavailable: "cache_unavailable";
|
|
1168
1189
|
cancelled: "cancelled";
|
|
1169
1190
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -1205,6 +1226,7 @@ export declare const FrequencyOutput: z.ZodObject<{
|
|
|
1205
1226
|
code: z.ZodString;
|
|
1206
1227
|
}, z.core.$strict>>>;
|
|
1207
1228
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
1229
|
+
browser_unavailable: "browser_unavailable";
|
|
1208
1230
|
cache_unavailable: "cache_unavailable";
|
|
1209
1231
|
cancelled: "cancelled";
|
|
1210
1232
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -1290,6 +1312,7 @@ export declare const SessionStatusOutput: z.ZodObject<{
|
|
|
1290
1312
|
code: z.ZodString;
|
|
1291
1313
|
}, z.core.$strict>>>;
|
|
1292
1314
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
1315
|
+
browser_unavailable: "browser_unavailable";
|
|
1293
1316
|
cache_unavailable: "cache_unavailable";
|
|
1294
1317
|
cancelled: "cancelled";
|
|
1295
1318
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -1406,6 +1429,7 @@ export declare const ProductDetailsOutput: z.ZodObject<{
|
|
|
1406
1429
|
status: z.ZodLiteral<"unavailable">;
|
|
1407
1430
|
error: z.ZodObject<{
|
|
1408
1431
|
code: z.ZodEnum<{
|
|
1432
|
+
browser_unavailable: "browser_unavailable";
|
|
1409
1433
|
cache_unavailable: "cache_unavailable";
|
|
1410
1434
|
cancelled: "cancelled";
|
|
1411
1435
|
cart_change_rejected: "cart_change_rejected";
|
|
@@ -1441,6 +1465,7 @@ export declare const ProductDetailsOutput: z.ZodObject<{
|
|
|
1441
1465
|
code: z.ZodString;
|
|
1442
1466
|
}, z.core.$strict>>>;
|
|
1443
1467
|
code: z.ZodUnion<readonly [z.ZodEnum<{
|
|
1468
|
+
browser_unavailable: "browser_unavailable";
|
|
1444
1469
|
cache_unavailable: "cache_unavailable";
|
|
1445
1470
|
cancelled: "cancelled";
|
|
1446
1471
|
cart_change_rejected: "cart_change_rejected";
|
package/dist/parsers/cart.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export declare function parseProductForm(input: unknown, expectedId: ProductId):
|
|
|
21
21
|
csrf: string;
|
|
22
22
|
sale: SaleMetadata;
|
|
23
23
|
}, {
|
|
24
|
-
code: "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
24
|
+
code: "browser_unavailable" | "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
25
25
|
message: string;
|
|
26
26
|
retryable: boolean;
|
|
27
27
|
issues?: {
|
|
@@ -37,7 +37,7 @@ export declare function parseCartControls(html: string, productId: ProductId, ca
|
|
|
37
37
|
measureOptions: string;
|
|
38
38
|
gtmIndex: string;
|
|
39
39
|
}, {
|
|
40
|
-
code: "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
40
|
+
code: "browser_unavailable" | "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
41
41
|
message: string;
|
|
42
42
|
retryable: boolean;
|
|
43
43
|
issues?: {
|
|
@@ -5,7 +5,7 @@ export declare function productReferenceFromUrl(href: string): Result<{
|
|
|
5
5
|
productId: string & import("zod").$brand<"ProductId">;
|
|
6
6
|
productSlug: (string & import("zod").$brand<"ProductSlug">) | null;
|
|
7
7
|
}, {
|
|
8
|
-
code: "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
8
|
+
code: "browser_unavailable" | "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
9
9
|
message: string;
|
|
10
10
|
retryable: boolean;
|
|
11
11
|
issues?: {
|
package/dist/runtime.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { CookieStore } from './stores/files.js';
|
|
|
4
4
|
import type { BrowserLauncher, StorefrontSession } from './session/browser.js';
|
|
5
5
|
import type { ShoppingServices } from './mcp/shopping.js';
|
|
6
6
|
export declare const systemClock: Clock;
|
|
7
|
+
/** Launch Playwright's Chromium, downloading it first if this machine does not have it yet. */
|
|
7
8
|
export declare const launchBrowser: BrowserLauncher;
|
|
8
9
|
export interface RuntimeOptions {
|
|
9
10
|
env?: Environment;
|
package/dist/runtime.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createApplication } from './application.js';
|
|
|
2
2
|
import { favoritesScope, loadSettings } from './config.js';
|
|
3
3
|
import { FileCookieStore, FileFavoritesStore } from './stores/files.js';
|
|
4
4
|
import { BrowserSession } from './session/browser.js';
|
|
5
|
+
import { ChromiumInstaller, runChromiumInstall } from './session/chromium.js';
|
|
5
6
|
import { AuthenticationClient } from './clients/authentication.js';
|
|
6
7
|
import { StorefrontClient, CatalogClient, FavoritesClient, CartClient, OrdersClient } from './clients/storefront.js';
|
|
7
8
|
import { CatalogService, FavoritesService } from './services/catalog.js';
|
|
@@ -10,7 +11,15 @@ import { OrderService, PurchaseHistoryService } from './services/orders.js';
|
|
|
10
11
|
import { registerShoppingTools } from './mcp/shopping.js';
|
|
11
12
|
import { SERVER_INSTRUCTIONS, basketPlannerPrompt } from './mcp/guide.js';
|
|
12
13
|
export const systemClock = { now: () => new Date() };
|
|
13
|
-
|
|
14
|
+
const chromiumInstaller = new ChromiumInstaller(async () => {
|
|
15
|
+
// Skip per-percent progress lines; keep the start, finish and any errors.
|
|
16
|
+
const code = await runChromiumInstall([], line => { if (!line.includes('%'))
|
|
17
|
+
console.error(`[chromium] ${line}`); });
|
|
18
|
+
if (code !== 0)
|
|
19
|
+
throw new Error(`Chromium download exited with code ${code}`);
|
|
20
|
+
}, message => console.error(message));
|
|
21
|
+
/** Launch Playwright's Chromium, downloading it first if this machine does not have it yet. */
|
|
22
|
+
export const launchBrowser = chromiumInstaller.launcher(async (options) => (await import('playwright')).chromium.launch(options));
|
|
14
23
|
/** Build the shopping services. Nothing is read or launched until this is called. */
|
|
15
24
|
export function createShoppingServices(options = {}) {
|
|
16
25
|
const settings = loadSettings(options.env ?? process.env);
|
|
@@ -67,7 +67,7 @@ export declare class CatalogService {
|
|
|
67
67
|
} | {
|
|
68
68
|
status: "unavailable";
|
|
69
69
|
error: {
|
|
70
|
-
code: "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
70
|
+
code: "browser_unavailable" | "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
71
71
|
message: string;
|
|
72
72
|
retryable: boolean;
|
|
73
73
|
issues?: {
|
|
@@ -77,7 +77,7 @@ export declare class CatalogService {
|
|
|
77
77
|
};
|
|
78
78
|
};
|
|
79
79
|
}, {
|
|
80
|
-
code: "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
80
|
+
code: "browser_unavailable" | "cache_unavailable" | "cancelled" | "cart_change_rejected" | "cart_change_unconfirmed" | "deadline_exceeded" | "invalid_data" | "invalid_input" | "not_authenticated" | "not_found" | "order_details_unavailable" | "quantity_below_minimum" | "queue_full" | "sale_rules_unknown" | "server_closed" | "upstream_unavailable";
|
|
81
81
|
message: string;
|
|
82
82
|
retryable: boolean;
|
|
83
83
|
issues?: {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ToolError } from '../domain/index.js';
|
|
2
|
+
import type { Logger } from '../ports.js';
|
|
3
|
+
import type { BrowserLauncher } from './browser.js';
|
|
4
|
+
/** The browser cannot be used yet; carries the message to show instead of a generic failure. */
|
|
5
|
+
export declare class BrowserUnavailable extends Error {
|
|
6
|
+
readonly toolError: ToolError;
|
|
7
|
+
constructor(toolError: ToolError);
|
|
8
|
+
}
|
|
9
|
+
export declare const isMissingBrowserError: (error: unknown) => boolean;
|
|
10
|
+
/** Run Playwright's installer for Chromium. With `onOutput`, its output is captured instead of inherited. */
|
|
11
|
+
export declare function runChromiumInstall(extraArgs?: readonly string[], onOutput?: (line: string) => void): Promise<number>;
|
|
12
|
+
/**
|
|
13
|
+
* Downloads Chromium the first time a launch finds it missing. Concurrent requests share one
|
|
14
|
+
* download, and a request that would run past its budget gets a "try again shortly" error.
|
|
15
|
+
*/
|
|
16
|
+
export declare class ChromiumInstaller {
|
|
17
|
+
private readonly install;
|
|
18
|
+
private readonly logger;
|
|
19
|
+
private readonly maxWaitMs;
|
|
20
|
+
private pending;
|
|
21
|
+
constructor(install: () => Promise<void>, logger: Logger, maxWaitMs?: number);
|
|
22
|
+
private start;
|
|
23
|
+
private waitForInstall;
|
|
24
|
+
launcher(launch: BrowserLauncher): BrowserLauncher;
|
|
25
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { requestTimeout } from './request.js';
|
|
5
|
+
/** The browser cannot be used yet; carries the message to show instead of a generic failure. */
|
|
6
|
+
export class BrowserUnavailable extends Error {
|
|
7
|
+
toolError;
|
|
8
|
+
constructor(toolError) {
|
|
9
|
+
super(toolError.message);
|
|
10
|
+
this.toolError = toolError;
|
|
11
|
+
this.name = 'BrowserUnavailable';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const unavailable = (message) => new BrowserUnavailable({ code: 'browser_unavailable', message, retryable: true });
|
|
15
|
+
export const isMissingBrowserError = (error) => error instanceof Error && /Executable doesn't exist/i.test(error.message);
|
|
16
|
+
/** Run Playwright's installer for Chromium. With `onOutput`, its output is captured instead of inherited. */
|
|
17
|
+
export function runChromiumInstall(extraArgs = [], onOutput) {
|
|
18
|
+
const cli = join(dirname(createRequire(import.meta.url).resolve('playwright/package.json')), 'cli.js');
|
|
19
|
+
const child = spawn(process.execPath, [cli, 'install', 'chromium', ...extraArgs], { stdio: onOutput ? ['ignore', 'pipe', 'pipe'] : 'inherit' });
|
|
20
|
+
if (onOutput) {
|
|
21
|
+
const forward = (chunk) => chunk.toString().split(/\r?\n|\r/).map(line => line.trim()).filter(Boolean).forEach(onOutput);
|
|
22
|
+
child.stdout?.on('data', forward);
|
|
23
|
+
child.stderr?.on('data', forward);
|
|
24
|
+
}
|
|
25
|
+
return new Promise(resolve => { child.on('error', () => resolve(1)); child.on('close', code => resolve(code ?? 1)); });
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Downloads Chromium the first time a launch finds it missing. Concurrent requests share one
|
|
29
|
+
* download, and a request that would run past its budget gets a "try again shortly" error.
|
|
30
|
+
*/
|
|
31
|
+
export class ChromiumInstaller {
|
|
32
|
+
install;
|
|
33
|
+
logger;
|
|
34
|
+
maxWaitMs;
|
|
35
|
+
pending;
|
|
36
|
+
constructor(install, logger, maxWaitMs = 25000) {
|
|
37
|
+
this.install = install;
|
|
38
|
+
this.logger = logger;
|
|
39
|
+
this.maxWaitMs = maxWaitMs;
|
|
40
|
+
}
|
|
41
|
+
start() {
|
|
42
|
+
this.pending ??= this.install().then(() => this.logger('Chromium is ready.'), error => { this.pending = undefined; throw error; });
|
|
43
|
+
return this.pending;
|
|
44
|
+
}
|
|
45
|
+
async waitForInstall() {
|
|
46
|
+
const pending = this.start();
|
|
47
|
+
// Leave time to launch the browser and do the actual work within the same request.
|
|
48
|
+
const budget = Math.max(0, requestTimeout(this.maxWaitMs + 10000) - 10000);
|
|
49
|
+
let timer;
|
|
50
|
+
const outcome = await Promise.race([pending.then(() => 'ready', () => 'failed'),
|
|
51
|
+
new Promise(resolve => { timer = setTimeout(() => resolve('waiting'), budget); })]);
|
|
52
|
+
clearTimeout(timer);
|
|
53
|
+
if (outcome === 'failed')
|
|
54
|
+
throw unavailable('Chromium could not be downloaded. Check the internet connection, or run `continentept-mcp install-browser`.');
|
|
55
|
+
if (outcome === 'waiting')
|
|
56
|
+
throw unavailable('Chromium is being downloaded for first use (about 150 MB). Try again in a minute.');
|
|
57
|
+
}
|
|
58
|
+
launcher(launch) {
|
|
59
|
+
return async (options) => {
|
|
60
|
+
if (this.pending)
|
|
61
|
+
await this.waitForInstall();
|
|
62
|
+
try {
|
|
63
|
+
return await launch(options);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (!isMissingBrowserError(error))
|
|
67
|
+
throw error;
|
|
68
|
+
this.logger('Chromium is not installed; downloading it now. This happens once.');
|
|
69
|
+
await this.waitForInstall();
|
|
70
|
+
return launch(options);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
package/docs/configuration.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# Configuration
|
|
2
2
|
|
|
3
3
|
Settings come from environment variables and an optional private credentials file. They are
|
|
4
|
-
read when the server starts.
|
|
4
|
+
read when the server starts. The Claude Desktop extension asks for your email and password
|
|
5
|
+
when you install it and passes them to the server for you; the rest of this page is for
|
|
6
|
+
manual setups.
|
|
5
7
|
|
|
6
8
|
## Variables
|
|
7
9
|
|
package/docs/tools.md
CHANGED
|
@@ -195,6 +195,7 @@ credentials, cookies or file paths.
|
|
|
195
195
|
| `cart_change_rejected` | The website rejected the cart change. |
|
|
196
196
|
| `cart_change_unconfirmed` | The cart change could not be confirmed. |
|
|
197
197
|
| `cache_unavailable` | The local favorites snapshot could not be read or written. |
|
|
198
|
+
| `browser_unavailable` | Chromium is still downloading for first use, or the download failed. Retryable. |
|
|
198
199
|
| `cancelled`, `deadline_exceeded`, `server_closed`, `queue_full` | The request stopped before completing. |
|
|
199
200
|
| `internal_error`, `invalid_result` | Unexpected server failure. Details are not exposed. |
|
|
200
201
|
|
package/docs/troubleshooting.md
CHANGED
|
@@ -5,7 +5,8 @@ without contacting the website.
|
|
|
5
5
|
|
|
6
6
|
| Symptom | What to do |
|
|
7
7
|
| --- | --- |
|
|
8
|
-
| `
|
|
8
|
+
| `browser_unavailable`: Chromium is being downloaded | The first use downloads Chromium (about 150 MB). Wait a minute and try again. |
|
|
9
|
+
| `browser_unavailable`: Chromium could not be downloaded | Check the internet connection, then run `npx -y continentept-mcp install-browser` to see the download output. On Linux, add `--with-deps` to install system libraries. |
|
|
9
10
|
| `not_authenticated` | Check that `get_session_status` reports credentials as configured, then run `continentept-mcp login` to test them. See [configuration](configuration.md). |
|
|
10
11
|
| Sign-in keeps failing | Run `continentept-mcp login --show-browser` to watch the browser and complete any extra verification the website asks for. |
|
|
11
12
|
| Status shows `authentication: unknown` | Nothing has been observed since the server started or since the saved session changed. Any account tool will establish it. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "continentept-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"mcpName": "io.github.andredelgado/continente-mcp",
|
|
4
5
|
"description": "MCP server for Continente.pt: search products, check sale rules, read favorites and orders, and make verified cart changes.",
|
|
5
6
|
"keywords": [
|
|
6
7
|
"mcp",
|
|
@@ -62,7 +63,8 @@
|
|
|
62
63
|
"test": "node build/tools/run-tests.js",
|
|
63
64
|
"test:browser": "npm run build && tsc -p tsconfig.tests.json && node build/tools/run-tests.js --browser",
|
|
64
65
|
"test:package": "npm run build:tools && node build/tools/package-smoke.js",
|
|
65
|
-
"prepack": "npm run build"
|
|
66
|
+
"prepack": "npm run build",
|
|
67
|
+
"build:bundle": "npm run build && node build/tools/build-bundle.js"
|
|
66
68
|
},
|
|
67
69
|
"dependencies": {
|
|
68
70
|
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
@@ -71,6 +73,7 @@
|
|
|
71
73
|
"zod": "4.6.7"
|
|
72
74
|
},
|
|
73
75
|
"devDependencies": {
|
|
76
|
+
"@anthropic-ai/mcpb": "2.1.2",
|
|
74
77
|
"@types/node": "^22.18.0",
|
|
75
78
|
"typescript": "^7.0.2"
|
|
76
79
|
}
|