webcake-landing-mcp 1.0.9 → 1.0.11

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 CHANGED
@@ -54,80 +54,18 @@ valid element/page skeletons, a page validator, and tools to create or edit page
54
54
  The AI agent produces the full `{ page, popup, settings, options, cartConfigs }` JSON; `create_page`
55
55
  persists it (source-only — the page opens in the editor where re-saving renders it).
56
56
 
57
- ## Setup methods (pick one)
57
+ ## Two ways to run
58
58
 
59
- | # | Method | Best for | Auth | Jump to |
60
- |---|--------|----------|------|---------|
61
- | 1 | **Local stdio** — add to an IDE (Claude Desktop / Cursor / …) via `npx` or a built file | Daily use on your machine | env `WEBCAKE_JWT`, or `login`, or none (reference tools) | [IDE config](#configuration-by-ide--ai-tool) |
62
- | 2 | **`login`**grab the token through the browser (no copy-paste) | Avoiding a manual token paste (stdio / single-user remote) | browser session → saved `auth.json` | [Connect once](#connect-once--grab-your-token-automatically-login) |
63
- | 3 | **Remote HTTP (`serve`)** — run as an HTTP server, test with MCP Inspector / `mcp-remote` / curl | Trying the remote transport locally | per-request `x-webcake-jwt` header, or env | [Remote](#run-as-a-remote-connector-streamable-http) |
64
- | 4 | **VPS + claude.ai connector** — deploy public HTTPS, add as a custom connector | Sharing one hosted server | single-account (env token); per-user needs OAuth (not implemented) | [Deploy on a VPS](#deploy-on-a-vps) |
65
-
66
- Two **run forms** apply to any method: **`npx -y webcake-landing-mcp …`** (no clone, auto-updates) or **`node /abs/path/dist/index.js …`** (a cloned build — run `npm run build` first). The IDE configs below show the local form; swap `command`/`args` for the npx form to use CDN mode.
59
+ | Method | Best for | Auth |
60
+ |--------|----------|------|
61
+ | **npx (local stdio)** — add to an IDE with one command | Daily use on your machine | browser `login`, a JWT, or none (reference tools) |
62
+ | **Remote HTTP (`serve`)**run as a connector behind a URL | A hosted/shared server (e.g. Coolify) | per-request `x-webcake-jwt` header / `?jwt=` |
67
63
 
68
64
  The **reference + generation tools** (`get_generation_guide`, `list_elements`, `validate_page`, …) work with **zero config**; only the **persistence tools** (`create_page`, `update_page`, `list_pages`, `get_page`, `list_organizations`) need a token. Credentials resolve in order: **per-request header → env var → saved `auth.json`** (`login`).
69
65
 
70
- ## Quick Install (Recommended)
71
-
72
- Run the auto-install script — it handles everything: clone, install dependencies, build, and configure your IDE.
73
-
74
- ### macOS / Linux
75
-
76
- If you already cloned the repo:
77
- ```bash
78
- ./install.sh
79
- ```
80
-
81
- Or download and run directly:
82
- ```bash
83
- curl -fsSL https://raw.githubusercontent.com/vuluu2k/webcake-landing-mcp/main/install.sh -o install.sh && bash install.sh
84
- ```
85
-
86
- The installer is interactive: it asks where to install (default `~/.webcake-landing-mcp`), prompts for
87
- the env vars (`WEBCAKE_API_BASE`, `WEBCAKE_JWT`, `WEBCAKE_ORG_ID` — all optional, Enter to skip), then
88
- lets you pick which IDE(s) to configure: `claude-desktop`, `claude-code`, `cursor`, `windsurf`, `augment`,
89
- `codex`, or all.
66
+ > 🛠️ Prefer a shell-script installer (`install.sh`/`install.ps1`), a cloned local build, or hand-written per-IDE config? See **[docs/manual-install.md](docs/manual-install.md)**.
90
67
 
91
- Uninstall (removes the MCP server entry from every configured IDE):
92
- ```bash
93
- ./install.sh --uninstall
94
- ```
95
-
96
- ### Windows (PowerShell)
97
-
98
- If you already cloned the repo:
99
- ```powershell
100
- .\install.ps1
101
- ```
102
-
103
- Or download and run directly:
104
- ```powershell
105
- irm https://raw.githubusercontent.com/vuluu2k/webcake-landing-mcp/main/install.ps1 -OutFile install.ps1; .\install.ps1
106
- ```
107
-
108
- Uninstall:
109
- ```powershell
110
- .\install.ps1 --uninstall
111
- ```
112
-
113
- ---
114
-
115
- ## Update
116
-
117
- Update to the latest version:
118
-
119
- ```bash
120
- cd ~/.webcake-landing-mcp # or wherever you installed it
121
- git pull
122
- npm install
123
- npm run build
124
- ```
125
-
126
- Then restart your IDE.
127
-
128
- ---
129
-
130
- ## Run without cloning (npx)
68
+ ## Install (npx)
131
69
 
132
70
  Once published to npm, the server runs straight from the registry — no clone, no build:
133
71
 
@@ -143,18 +81,18 @@ npx -y github:vuluu2k/webcake-landing-mcp
143
81
 
144
82
  ### Auto-configure your IDE (`install` subcommand)
145
83
 
146
- `npx` only **runs** the server — unlike `install.sh`/`install.ps1`, it does not write the MCP
147
- config into your IDE. The bundled `install` subcommand does that step for you, no clone needed:
84
+ `npx` only **runs** the server — unlike the [shell installers](docs/manual-install.md), it does not
85
+ write the MCP config into your IDE. The bundled `install` subcommand does that step for you, no clone needed:
148
86
 
149
87
  ```bash
150
- # Interactive — asks for env + which IDE(s) step by step
88
+ # Interactive — pick environment, log in via browser (or paste a JWT), pick IDE(s)
151
89
  npx -y webcake-landing-mcp install
152
90
 
153
- # Non-interactive — configure every supported IDE at once
154
- npx -y webcake-landing-mcp install --ide all --jwt <your-jwt> --api-base http://localhost:5800
91
+ # Non-interactive — configure every supported IDE at once (env + token via flags)
92
+ npx -y webcake-landing-mcp install --ide all --env prod --jwt <your-jwt>
155
93
 
156
- # Just one IDE
157
- npx -y webcake-landing-mcp install --ide cursor --jwt <your-jwt>
94
+ # Local dev — point at your local stack (localhost:5800 / :5173)
95
+ npx -y webcake-landing-mcp install --ide cursor --env local --jwt <your-jwt>
158
96
 
159
97
  # Remove the server from every IDE config
160
98
  npx -y webcake-landing-mcp uninstall
@@ -162,8 +100,10 @@ npx -y webcake-landing-mcp uninstall
162
100
 
163
101
  It writes a `webcake-landing` entry (using the `npx` launch form below) into the right config file
164
102
  for each target: `claude-desktop`, `claude-code`, `cursor`, `windsurf`, `augment` (VS Code), `codex`,
165
- or `all`. Flags: `--ide`, `--api-base`, `--jwt`, `--org-id`, `--host`, `--app-base`, `--npx`/`--local`,
166
- `-y`. Run `npx -y webcake-landing-mcp --help` for the full list.
103
+ or `all`. Interactively it asks for the **environment** (`local`/`staging`/`prod`, which sets the API +
104
+ app URLs) and whether to **log in via the browser or paste a JWT**. Flags: `--ide`, `--env`, `--jwt`,
105
+ `--org-id`, `--api-base`/`--app-base` (advanced overrides), `--npx`/`--local`, `-y`. Run
106
+ `npx -y webcake-landing-mcp install --help` for the full list.
167
107
 
168
108
  ### Manual config
169
109
 
@@ -176,7 +116,7 @@ The MCP config is the same as the local one, but `command`/`args` point at `npx`
176
116
  "command": "npx",
177
117
  "args": ["-y", "webcake-landing-mcp"],
178
118
  "env": {
179
- "WEBCAKE_API_BASE": "http://localhost:5800",
119
+ "WEBCAKE_ENV": "prod",
180
120
  "WEBCAKE_JWT": "<your-jwt>"
181
121
  }
182
122
  }
@@ -219,10 +159,10 @@ via headers, so a hosted server is multi-user and never bakes in a shared secret
219
159
  | Header | Maps to | Notes |
220
160
  |--------|---------|-------|
221
161
  | `x-webcake-jwt` (or `Authorization: Bearer <jwt>`) | `WEBCAKE_JWT` | the account token — sent per request |
162
+ | `x-webcake-env` | `WEBCAKE_ENV` | named environment (`local`/`staging`/`prod`) |
222
163
  | `x-webcake-org-id` | `WEBCAKE_ORG_ID` | default org |
223
- | `x-webcake-api-base` | `WEBCAKE_API_BASE` | usually set once via env on the host instead |
224
- | `x-webcake-host` | `WEBCAKE_HOST` | Phoenix host-routing header |
225
- | `x-webcake-app-base` | `WEBCAKE_APP_BASE` | editor/preview URL base |
164
+ | `x-webcake-api-base` | `WEBCAKE_API_BASE` | overrides the env preset's API base |
165
+ | `x-webcake-app-base` | `WEBCAKE_APP_BASE` | overrides the env preset's app base |
226
166
 
227
167
  Any header that is absent falls back to the corresponding env var — so you can also run it **single-user**
228
168
  by setting `WEBCAKE_API_BASE` + `WEBCAKE_JWT` in the host's env and keeping the URL private.
@@ -280,19 +220,6 @@ running `serve` server on your machine:
280
220
  through the dialog, but the token appears in logs), or use a header-capable client (`mcp-remote --header …`),
281
221
  or add **OAuth** (not implemented) for the cleanest flow.
282
222
 
283
- ## Manual Setup (local)
284
-
285
- ```bash
286
- git clone https://github.com/vuluu2k/webcake-landing-mcp.git
287
- cd webcake-landing-mcp
288
- npm install # postinstall `prepare` builds dist/ automatically
289
- npm run build # (re)build: tsc -> dist/ + copies src/**/*.json (page-schema.json) into dist/
290
- npm run smoke # offline self-test of factory + validator (prints "ALL GOOD")
291
- ```
292
-
293
- The reference/validation tools work with **zero config**. Env vars are only needed for the persistence
294
- tools (`create_page`, `update_page`, `list_pages`, `get_page`, `list_organizations`).
295
-
296
223
  ## Connect once — grab your token automatically (`login`)
297
224
 
298
225
  Instead of copying a JWT by hand, run:
@@ -301,7 +228,11 @@ Instead of copying a JWT by hand, run:
301
228
  # Production — zero config (defaults: connect via webcake.io, API via api.webcake.io):
302
229
  npx -y webcake-landing-mcp login
303
230
 
304
- # Local dev — point at your local SPA (5173) + API (5800):
231
+ # Local dev / staging pick a named environment (see Environments below):
232
+ node dist/index.js login --env local # SPA :5173 + API :5800
233
+ node dist/index.js login --env staging # staging.webcake.io + api.staging.webcake.io
234
+
235
+ # …or point at custom URLs explicitly (these override --env):
305
236
  node dist/index.js login \
306
237
  --connect-url http://localhost:5173/mcp-connect \
307
238
  --api-base http://localhost:5800
@@ -317,9 +248,8 @@ deployment (env vars still take precedence). The landing JWT lasts ~90 days, so
317
248
 
318
249
  Two URLs, don't mix them up:
319
250
 
320
- - **Connect page = the SPA** (`--connect-url` / `WEBCAKE_CONNECT_URL`): `https://webcake.io/mcp-connect`
321
- in prod, `http://localhost:5173/mcp-connect` locally. Otherwise derived from `WEBCAKE_APP_BASE` +
322
- `/mcp-connect`, defaulting to `https://webcake.io/mcp-connect`.
251
+ - **Connect page = the SPA** (`--connect-url`): derived from the `--env` app base + `/mcp-connect`
252
+ (`https://webcake.io/mcp-connect` for prod, `http://localhost:5173/mcp-connect` for local). Override with `--connect-url`.
323
253
  - **API base = the backend** (`--api-base` / `WEBCAKE_API_BASE`): `https://api.webcake.io` in prod,
324
254
  `http://localhost:5800` locally. Defaults to `https://api.webcake.io`.
325
255
 
@@ -346,12 +276,11 @@ flow can also be done entirely in the SPA, no backend route needed.)
346
276
 
347
277
  | Variable | Required | Description |
348
278
  |----------|----------|-------------|
349
- | `WEBCAKE_API_BASE` | No* | Backend base URL, e.g. `http://localhost:5800`. Required to persist. |
279
+ | `WEBCAKE_ENV` | No | Named environment: `local` \| `staging` \| `prod`. Fills in `WEBCAKE_API_BASE` + `WEBCAKE_APP_BASE` from a preset (see table below). Also settable with the `--env <name>` flag. Explicit vars win. |
280
+ | `WEBCAKE_API_BASE` | No* | Backend base URL, e.g. `http://localhost:5800`. Required to persist (or set `WEBCAKE_ENV`). |
350
281
  | `WEBCAKE_JWT` | No* | Account JWT (dashboard auth). Required to persist — expires, refresh when needed. |
351
282
  | `WEBCAKE_ORG_ID` | No | Default organization id for `create_page` (overridden by its `organization_id` arg). Omit → personal page. |
352
- | `WEBCAKE_HOST` | No | Optional `Host` header (Phoenix routes by host, e.g. `builder.localhost`). |
353
283
  | `WEBCAKE_APP_BASE` | No | Optional base used to build editor/preview URLs in the result. |
354
- | `WEBCAKE_CONNECT_URL` | No | The SPA "connect" page for `login` (default `https://webcake.io/mcp-connect`; else `WEBCAKE_APP_BASE` + `/mcp-connect`). |
355
284
  | `WEBCAKE_CONFIG_DIR` | No | Dir for the saved `auth.json` written by `login` (default `~/.webcake-landing-mcp`). |
356
285
 
357
286
  > \* `WEBCAKE_API_BASE` and `WEBCAKE_JWT` are only needed for the persistence tools. The reference and
@@ -360,183 +289,44 @@ flow can also be done entirely in the SPA, no backend route needed.)
360
289
  > Persisting writes a real page to whatever `WEBCAKE_API_BASE` points at, using the JWT as that account.
361
290
  > Start against local/staging.
362
291
 
363
- ### How to get `WEBCAKE_JWT`
364
-
365
- 1. Open the WebCake builder dashboard and log in
366
- 2. Open DevTools (`F12` or `Cmd + Option + I`)
367
- 3. Go to the **Network** tab > click any page
368
- 4. Find an API request (e.g. `@me`, `organizations`…)
369
- 5. In **Request Headers**, copy the value after `Authorization: Bearer ` → this is your `WEBCAKE_JWT`
370
- 6. Use the `list_organizations` tool to list orgs and pick `WEBCAKE_ORG_ID`
371
-
372
- ---
373
-
374
- ## Configuration by IDE / AI Tool
292
+ ### Environments (`--env` / `WEBCAKE_ENV`)
375
293
 
376
- > Replace `/absolute-path/webcake-landing-mcp/dist/index.js` below with the actual path where you
377
- > cloned/built the repo. Example: `/Users/username/webcake-landing-mcp/dist/index.js`.
378
- > Run `npm run build` first so `dist/` exists.
294
+ Instead of setting both base URLs by hand, pick a named environment — one source of
295
+ truth for the API + app bases:
379
296
 
380
- ### 1. Claude Desktop
381
-
382
- Open Settings > Developer > Edit Config, or edit the file directly:
383
-
384
- - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
385
- - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
386
- - **Linux**: `~/.config/Claude/claude_desktop_config.json`
387
-
388
- ```json
389
- {
390
- "mcpServers": {
391
- "webcake-landing": {
392
- "command": "node",
393
- "args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
394
- "env": {
395
- "WEBCAKE_API_BASE": "http://localhost:5800",
396
- "WEBCAKE_JWT": "<your-jwt>",
397
- "WEBCAKE_HOST": "builder.localhost",
398
- "WEBCAKE_APP_BASE": "http://builder.localhost:5800"
399
- }
400
- }
401
- }
402
- }
403
- ```
404
-
405
- Restart Claude Desktop. The MCP tools will appear in the chat input (hammer icon).
406
-
407
- ---
408
-
409
- ### 2. Claude Code (CLI)
410
-
411
- Run in terminal — **local** build:
297
+ | `--env` / `WEBCAKE_ENV` | API base (`WEBCAKE_API_BASE`) | App base (`WEBCAKE_APP_BASE`) |
298
+ |-------------------------|-------------------------------|-------------------------------|
299
+ | `local` | `http://localhost:5800` | `http://localhost:5173` |
300
+ | `staging` | `https://api.staging.webcake.io` | `https://staging.webcake.io` |
301
+ | `prod` | `https://api.webcake.io` | `https://webcake.io` |
412
302
 
413
303
  ```bash
414
- claude mcp add webcake-landing \
415
- -e WEBCAKE_API_BASE=http://localhost:5800 \
416
- -e WEBCAKE_JWT=<your-jwt> \
417
- -e WEBCAKE_HOST=builder.localhost \
418
- -- node /absolute-path/webcake-landing-mcp/dist/index.js
304
+ node dist/index.js serve --env staging # remote server on the staging backend
305
+ node dist/index.js login --env local # connect against your local SPA + API
306
+ WEBCAKE_ENV=prod node dist/index.js # stdio, prod (env var form)
419
307
  ```
420
308
 
421
- Or **CDN / npx** (no clone):
309
+ Explicit `WEBCAKE_API_BASE` / `WEBCAKE_APP_BASE` (or `--api-base`) still override the
310
+ preset, field by field. On the remote HTTP server a client can override the server's
311
+ environment per request with the **`x-webcake-env`** header or **`?env=`** query
312
+ (e.g. `…/mcp?jwt=<token>&env=staging`) — so one server can serve multiple environments.
422
313
 
423
- ```bash
424
- claude mcp add webcake-landing \
425
- -e WEBCAKE_API_BASE=http://localhost:5800 \
426
- -e WEBCAKE_JWT=<your-jwt> \
427
- -- npx -y webcake-landing-mcp
428
- ```
429
-
430
- Or create `.claude.json` at project root (or `~/.claude.json` globally):
431
-
432
- ```json
433
- {
434
- "mcpServers": {
435
- "webcake-landing": {
436
- "command": "node",
437
- "args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
438
- "env": {
439
- "WEBCAKE_API_BASE": "http://localhost:5800",
440
- "WEBCAKE_JWT": "<your-jwt>"
441
- }
442
- }
443
- }
444
- }
445
- ```
446
-
447
- Verify:
448
- ```bash
449
- claude mcp list
450
- ```
451
-
452
- ---
453
-
454
- ### 3. Cursor
455
-
456
- Create `.cursor/mcp.json` at project root (or `~/.cursor/mcp.json` globally):
457
-
458
- ```json
459
- {
460
- "mcpServers": {
461
- "webcake-landing": {
462
- "command": "node",
463
- "args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
464
- "env": {
465
- "WEBCAKE_API_BASE": "http://localhost:5800",
466
- "WEBCAKE_JWT": "<your-jwt>"
467
- }
468
- }
469
- }
470
- }
471
- ```
472
-
473
- Restart Cursor and check Settings > MCP Servers for **"Connected"** status.
474
-
475
- ---
476
-
477
- ### 4. Windsurf
478
-
479
- Create `~/.codeium/windsurf/mcp_config.json`:
480
-
481
- ```json
482
- {
483
- "mcpServers": {
484
- "webcake-landing": {
485
- "command": "node",
486
- "args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
487
- "env": {
488
- "WEBCAKE_API_BASE": "http://localhost:5800",
489
- "WEBCAKE_JWT": "<your-jwt>"
490
- }
491
- }
492
- }
493
- }
494
- ```
495
-
496
- Restart Windsurf. Type `@` in Cascade chat to see `webcake-landing` tools.
497
-
498
- ---
499
-
500
- ### 5. Augment (VS Code Extension)
501
-
502
- Open Command Palette: `Cmd + Shift + P` > **"Augment: Edit MCP Settings"**, then add:
503
-
504
- ```json
505
- {
506
- "mcpServers": {
507
- "webcake-landing": {
508
- "command": "node",
509
- "args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
510
- "env": {
511
- "WEBCAKE_API_BASE": "http://localhost:5800",
512
- "WEBCAKE_JWT": "<your-jwt>"
513
- }
514
- }
515
- }
516
- }
517
- ```
314
+ ### How to get `WEBCAKE_JWT`
518
315
 
519
- Restart VS Code.
316
+ 1. Open the WebCake builder dashboard and log in
317
+ 2. Open DevTools (`F12` or `Cmd + Option + I`)
318
+ 3. Go to the **Network** tab > click any page
319
+ 4. Find an API request (e.g. `@me`, `organizations`…)
320
+ 5. In **Request Headers**, copy the value after `Authorization: Bearer ` → this is your `WEBCAKE_JWT`
321
+ 6. Use the `list_organizations` tool to list orgs and pick `WEBCAKE_ORG_ID`
520
322
 
521
323
  ---
522
324
 
523
- ### 6. Codex (OpenAI CLI)
524
-
525
- Add to `~/.codex/config.toml`:
526
-
527
- ```toml
528
- [mcp_servers.webcake-landing]
529
- command = "node"
530
- args = ["/absolute-path/webcake-landing-mcp/dist/index.js"]
531
- env = { "WEBCAKE_API_BASE" = "http://localhost:5800", "WEBCAKE_JWT" = "<your-jwt>" }
532
- ```
325
+ ## Per-IDE config
533
326
 
534
- Verify:
535
- ```bash
536
- codex mcp list
537
- ```
538
-
539
- ---
327
+ The npx **`install`** subcommand (above) writes the right config for each IDE automatically. For
328
+ hand-written config (Claude Desktop, Claude Code, Cursor, Windsurf, Augment, Codex) and the
329
+ cloned-build variants, see **[docs/manual-install.md](docs/manual-install.md#configuration-by-ide--ai-tool)**.
540
330
 
541
331
  ## Usage Examples
542
332
 
package/README.vi.md CHANGED
@@ -55,79 +55,18 @@ element/trang hợp lệ, bộ kiểm tra trang, và các tool để tạo/sửa
55
55
  `{ page, popup, settings, options, cartConfigs }`; `create_page` lưu nó (chỉ-source — trang mở trong editor,
56
56
  lưu lại sẽ render).
57
57
 
58
- ## Các cách setup (chọn một)
58
+ ## Hai cách chạy
59
59
 
60
- | # | Cách | Hợp cho | Auth | Xem |
61
- |---|------|---------|------|-----|
62
- | 1 | **Local stdio** — gắn vào IDE (Claude Desktop / Cursor / …) qua `npx` hoặc file build | Dùng hằng ngày trên máy | env `WEBCAKE_JWT`, hoặc `login`, hoặc không cần (tool tham chiếu) | [Cấu hình IDE](#cấu-hình-theo-ide--công-cụ-ai) |
63
- | 2 | **`login`**tự lấy token qua browser (khỏi copy-paste) | Khỏi dán token tay (stdio / remote 1 người) | session browser → file `auth.json` | [Kết nối một lần](#kết-nối-một-lần--tự-lấy-token-login) |
64
- | 3 | **Remote HTTP (`serve`)** — chạy như HTTP server, test bằng MCP Inspector / `mcp-remote` / curl | Thử transport remote ở local | header `x-webcake-jwt` mỗi request, hoặc env | [Remote](#chạy-như-remote-connector-streamable-http) |
65
- | 4 | **VPS + claude.ai connector** — deploy HTTPS public, thêm làm custom connector | Chia sẻ 1 server hosted | single-account (token env); per-user cần OAuth (chưa có) | [Deploy lên VPS](#deploy-lên-vps) |
66
-
67
- Hai **dạng chạy** áp dụng cho mọi cách: **`npx -y webcake-landing-mcp …`** (không clone, tự cập nhật) hoặc **`node /abs/path/dist/index.js …`** (bản đã clone & build — chạy `npm run build` trước). Cấu hình IDE bên dưới dùng dạng local; đổi `command`/`args` sang dạng npx để dùng CDN.
60
+ | Cách | Hợp cho | Auth |
61
+ |------|---------|------|
62
+ | **npx (local stdio)** — gắn vào IDE bằng một lệnh | Dùng hằng ngày trên máy | browser `login`, JWT, hoặc không cần (tool tham chiếu) |
63
+ | **Remote HTTP (`serve`)**chạy như connector sau một URL | Server hosted/chia sẻ (vd Coolify) | header `x-webcake-jwt` mỗi request / `?jwt=` |
68
64
 
69
65
  Các **tool tham chiếu + generation** (`get_generation_guide`, `list_elements`, `validate_page`, …) chạy **zero config**; chỉ **tool lưu trữ** (`create_page`, `update_page`, `list_pages`, `get_page`, `list_organizations`) mới cần token. Token ưu tiên theo thứ tự: **header mỗi request → biến env → file `auth.json`** (`login`).
70
66
 
71
- ## Cài nhanh (Khuyến nghị)
72
-
73
- Chạy script tự cài — lo trọn gói: clone, cài dependencies, build, và cấu hình IDE của bạn.
74
-
75
- ### macOS / Linux
76
-
77
- Nếu bạn đã clone repo:
78
- ```bash
79
- ./install.sh
80
- ```
81
-
82
- Hoặc tải & chạy trực tiếp:
83
- ```bash
84
- curl -fsSL https://raw.githubusercontent.com/vuluu2k/webcake-landing-mcp/main/install.sh -o install.sh && bash install.sh
85
- ```
86
-
87
- Trình cài tương tác: hỏi nơi cài (mặc định `~/.webcake-landing-mcp`), hỏi các biến môi trường
88
- (`WEBCAKE_API_BASE`, `WEBCAKE_JWT`, `WEBCAKE_ORG_ID` — đều tuỳ chọn, Enter để bỏ qua), rồi cho bạn chọn
89
- IDE cần cấu hình: `claude-desktop`, `claude-code`, `cursor`, `windsurf`, `augment`, `codex`, hoặc tất cả.
67
+ > 🛠️ Cần script cài (install.sh/.ps1), build từ clone, hay cấu hình IDE thủ công? Xem **[docs/manual-install.vi.md](docs/manual-install.vi.md)**.
90
68
 
91
- Gỡ cài (xoá entry MCP server khỏi mọi IDE đã cấu hình):
92
- ```bash
93
- ./install.sh --uninstall
94
- ```
95
-
96
- ### Windows (PowerShell)
97
-
98
- Nếu bạn đã clone repo:
99
- ```powershell
100
- .\install.ps1
101
- ```
102
-
103
- Hoặc tải & chạy trực tiếp:
104
- ```powershell
105
- irm https://raw.githubusercontent.com/vuluu2k/webcake-landing-mcp/main/install.ps1 -OutFile install.ps1; .\install.ps1
106
- ```
107
-
108
- Gỡ cài:
109
- ```powershell
110
- .\install.ps1 --uninstall
111
- ```
112
-
113
- ---
114
-
115
- ## Cập nhật
116
-
117
- Cập nhật lên bản mới nhất:
118
-
119
- ```bash
120
- cd ~/.webcake-landing-mcp # hoặc nơi bạn đã cài
121
- git pull
122
- npm install
123
- npm run build
124
- ```
125
-
126
- Rồi khởi động lại IDE.
127
-
128
- ---
129
-
130
- ## Chạy không cần clone (npx)
69
+ ## Cài đặt (npx)
131
70
 
132
71
  Sau khi đã publish lên npm, server chạy thẳng từ registry — không clone, không build:
133
72
 
@@ -143,27 +82,29 @@ npx -y github:vuluu2k/webcake-landing-mcp
143
82
 
144
83
  ### Tự cấu hình IDE (lệnh con `install`)
145
84
 
146
- `npx` chỉ **chạy** server — khác với `install.sh`/`install.ps1`, nó không ghi cấu hình MCP vào IDE.
85
+ `npx` chỉ **chạy** server — khác với [script cài đặt](docs/manual-install.vi.md), nó không ghi cấu hình MCP vào IDE.
147
86
  Lệnh con `install` đi kèm sẽ làm hộ bạn bước đó, không cần clone:
148
87
 
149
88
  ```bash
150
- # Tương tác — hỏi env + chọn IDE từng bước
89
+ # Tương tác — chọn môi trường, đăng nhập qua trình duyệt (hoặc dán JWT), chọn IDE
151
90
  npx -y webcake-landing-mcp install
152
91
 
153
- # Không tương tác — cấu hình mọi IDE hỗ trợ cùng lúc
154
- npx -y webcake-landing-mcp install --ide all --jwt <your-jwt> --api-base http://localhost:5800
92
+ # Không tương tác — cấu hình mọi IDE hỗ trợ cùng lúc (env + token qua cờ)
93
+ npx -y webcake-landing-mcp install --ide all --env prod --jwt <your-jwt>
155
94
 
156
- # Chỉ một IDE
157
- npx -y webcake-landing-mcp install --ide cursor --jwt <your-jwt>
95
+ # Local dev — trỏ vào stack local của bạn (localhost:5800 / :5173)
96
+ npx -y webcake-landing-mcp install --ide cursor --env local --jwt <your-jwt>
158
97
 
159
98
  # Gỡ server khỏi mọi cấu hình IDE
160
99
  npx -y webcake-landing-mcp uninstall
161
100
  ```
162
101
 
163
102
  Nó ghi entry `webcake-landing` (dùng dạng khởi chạy `npx` bên dưới) vào đúng file cấu hình của từng IDE:
164
- `claude-desktop`, `claude-code`, `cursor`, `windsurf`, `augment` (VS Code), `codex`, hoặc `all`. Cờ:
165
- `--ide`, `--api-base`, `--jwt`, `--org-id`, `--host`, `--app-base`, `--npx`/`--local`, `-y`. Chạy
166
- `npx -y webcake-landing-mcp --help` để xem đầy đủ.
103
+ `claude-desktop`, `claude-code`, `cursor`, `windsurf`, `augment` (VS Code), `codex`, hoặc `all`. Khi tương
104
+ tác, hỏi **môi trường** (`local`/`staging`/`prod` — mặc định `prod`, dùng để đặt API + app URL) cho
105
+ chọn **đăng nhập qua trình duyệt hay dán JWT**. Cờ: `--ide`, `--env`, `--jwt`, `--org-id`,
106
+ `--api-base`/`--app-base` (ghi đè nâng cao), `--npx`/`--local`, `-y`. Chạy
107
+ `npx -y webcake-landing-mcp install --help` để xem đầy đủ.
167
108
 
168
109
  ### Cấu hình thủ công
169
110
 
@@ -176,7 +117,7 @@ Cấu hình MCP giống bản local, chỉ khác `command`/`args` trỏ tới `n
176
117
  "command": "npx",
177
118
  "args": ["-y", "webcake-landing-mcp"],
178
119
  "env": {
179
- "WEBCAKE_API_BASE": "http://localhost:5800",
120
+ "WEBCAKE_ENV": "prod",
180
121
  "WEBCAKE_JWT": "<your-jwt>"
181
122
  }
182
123
  }
@@ -219,9 +160,10 @@ nên server hosted là đa người dùng và không nhúng secret chung:
219
160
  | Header | Tương ứng | Ghi chú |
220
161
  |--------|-----------|---------|
221
162
  | `x-webcake-jwt` (hoặc `Authorization: Bearer <jwt>`) | `WEBCAKE_JWT` | token tài khoản — gửi mỗi request |
163
+ | `x-webcake-env` | `WEBCAKE_ENV` | môi trường có tên (`local`/`staging`/`prod`) |
222
164
  | `x-webcake-org-id` | `WEBCAKE_ORG_ID` | org mặc định |
223
- | `x-webcake-api-base` | `WEBCAKE_API_BASE` | thường set 1 lần qua env trên host |
224
- | `x-webcake-app-base` | `WEBCAKE_APP_BASE` | base URL editor/preview |
165
+ | `x-webcake-api-base` | `WEBCAKE_API_BASE` | ghi đè API base của preset |
166
+ | `x-webcake-app-base` | `WEBCAKE_APP_BASE` | ghi đè app base của preset |
225
167
 
226
168
  Header nào thiếu thì fallback về biến env tương ứng — nên cũng chạy **một người dùng** được bằng cách đặt
227
169
  `WEBCAKE_API_BASE` + `WEBCAKE_JWT` trong env của host và giữ URL riêng tư.
@@ -278,19 +220,6 @@ chạy trên máy:
278
220
  nhưng token lộ trong log), hoặc dùng client hỗ trợ header (`mcp-remote --header …`), hoặc thêm **OAuth**
279
221
  (chưa làm) cho gọn nhất.
280
222
 
281
- ## Cài thủ công (local)
282
-
283
- ```bash
284
- git clone https://github.com/vuluu2k/webcake-landing-mcp.git
285
- cd webcake-landing-mcp
286
- npm install # postinstall `prepare` tự build dist/
287
- npm run build # (re)build: tsc -> dist/ + copy src/**/*.json (page-schema.json) vào dist/
288
- npm run smoke # self-test offline của factory + validator (in "ALL GOOD")
289
- ```
290
-
291
- Các tool tham chiếu/kiểm tra chạy với **zero config**. Biến môi trường chỉ cần cho các tool lưu trữ
292
- (`create_page`, `update_page`, `list_pages`, `get_page`, `list_organizations`).
293
-
294
223
  ## Kết nối một lần — tự lấy token (`login`)
295
224
 
296
225
  Thay vì copy JWT bằng tay, chạy:
@@ -315,9 +244,8 @@ ngày nên hiếm khi phải kết nối lại.
315
244
 
316
245
  Hai URL, đừng nhầm:
317
246
 
318
- - **Trang connect = SPA** (`--connect-url` / `WEBCAKE_CONNECT_URL`): `https://webcake.io/mcp-connect` ở prod,
319
- `http://localhost:5173/mcp-connect` ở local. Nếu không, suy ra từ `WEBCAKE_APP_BASE` + `/mcp-connect`,
320
- mặc định `https://webcake.io/mcp-connect`.
247
+ - **Trang connect = SPA** (`--connect-url`): suy ra từ app base của `--env` + `/mcp-connect`
248
+ (`https://webcake.io/mcp-connect` ở prod, `http://localhost:5173/mcp-connect` ở local). Ghi đè bằng `--connect-url`.
321
249
  - **API base = backend** (`--api-base` / `WEBCAKE_API_BASE`): `https://api.webcake.io` ở prod,
322
250
  `http://localhost:5800` ở local. Mặc định `https://api.webcake.io`.
323
251
 
@@ -344,12 +272,11 @@ SPA cũng được, khỏi cần route backend.)
344
272
 
345
273
  | Biến | Bắt buộc | Mô tả |
346
274
  |----------|----------|-------------|
347
- | `WEBCAKE_API_BASE` | Không* | Base URL backend, dụ `http://localhost:5800`. Cần để lưu trang. |
275
+ | `WEBCAKE_ENV` | Không | Môi trường tên: `local` \| `staging` \| `prod`. Điền sẵn `WEBCAKE_API_BASE` + `WEBCAKE_APP_BASE` từ preset (xem bảng bên dưới). Cũng đặt được qua cờ `--env <name>`. Biến tường minh sẽ thắng. |
276
+ | `WEBCAKE_API_BASE` | Không* | Base URL backend, ví dụ `http://localhost:5800`. Cần để lưu trang (hoặc đặt `WEBCAKE_ENV`). |
348
277
  | `WEBCAKE_JWT` | Không* | JWT tài khoản (auth dashboard). Cần để lưu trang — sẽ hết hạn, làm mới khi cần. |
349
278
  | `WEBCAKE_ORG_ID` | Không | Organization mặc định cho `create_page` (bị ghi đè bởi tham số `organization_id`). Bỏ trống → trang cá nhân. |
350
- | `WEBCAKE_HOST` | Không | Header `Host` tuỳ chọn (Phoenix route theo host, ví dụ `builder.localhost`). |
351
279
  | `WEBCAKE_APP_BASE` | Không | Base tuỳ chọn để dựng URL editor/preview trong kết quả. |
352
- | `WEBCAKE_CONNECT_URL` | Không | Trang "connect" (SPA) cho `login` (mặc định `https://webcake.io/mcp-connect`; nếu không thì `WEBCAKE_APP_BASE` + `/mcp-connect`). |
353
280
  | `WEBCAKE_CONFIG_DIR` | Không | Thư mục chứa `auth.json` do `login` ghi (mặc định `~/.webcake-landing-mcp`). |
354
281
 
355
282
  > \* `WEBCAKE_API_BASE` và `WEBCAKE_JWT` chỉ cần cho các tool lưu trữ. Các tool tham chiếu và kiểm tra
@@ -358,183 +285,42 @@ SPA cũng được, khỏi cần route backend.)
358
285
  > Lưu trang sẽ ghi một trang thật vào nơi `WEBCAKE_API_BASE` trỏ tới, dùng JWT làm tài khoản đó.
359
286
  > Hãy bắt đầu với local/staging.
360
287
 
361
- ### Cách lấy `WEBCAKE_JWT`
362
-
363
- 1. Mở dashboard builder WebCake và đăng nhập
364
- 2. Mở DevTools (`F12` hoặc `Cmd + Option + I`)
365
- 3. Vào tab **Network** > click một trang bất kỳ
366
- 4. Tìm một request API (ví dụ `@me`, `organizations`…)
367
- 5. Trong **Request Headers**, copy giá trị sau `Authorization: Bearer ` → đó là `WEBCAKE_JWT`
368
- 6. Dùng tool `list_organizations` để liệt kê org và chọn `WEBCAKE_ORG_ID`
369
-
370
- ---
371
-
372
- ## Cấu hình theo IDE / công cụ AI
373
-
374
- > Thay `/absolute-path/webcake-landing-mcp/dist/index.js` bên dưới bằng đường dẫn thật nơi bạn đã
375
- > clone/build repo. Ví dụ: `/Users/username/webcake-landing-mcp/dist/index.js`.
376
- > Chạy `npm run build` trước để `dist/` tồn tại.
377
-
378
- ### 1. Claude Desktop
379
-
380
- Mở Settings > Developer > Edit Config, hoặc sửa file trực tiếp:
381
-
382
- - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
383
- - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
384
- - **Linux**: `~/.config/Claude/claude_desktop_config.json`
385
-
386
- ```json
387
- {
388
- "mcpServers": {
389
- "webcake-landing": {
390
- "command": "node",
391
- "args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
392
- "env": {
393
- "WEBCAKE_API_BASE": "http://localhost:5800",
394
- "WEBCAKE_JWT": "<your-jwt>",
395
- "WEBCAKE_HOST": "builder.localhost",
396
- "WEBCAKE_APP_BASE": "http://builder.localhost:5800"
397
- }
398
- }
399
- }
400
- }
401
- ```
402
-
403
- Khởi động lại Claude Desktop. Các tool MCP sẽ hiện trong ô chat (biểu tượng búa).
404
-
405
- ---
406
-
407
- ### 2. Claude Code (CLI)
408
-
409
- Chạy trong terminal — bản **local**:
410
-
411
- ```bash
412
- claude mcp add webcake-landing \
413
- -e WEBCAKE_API_BASE=http://localhost:5800 \
414
- -e WEBCAKE_JWT=<your-jwt> \
415
- -e WEBCAKE_HOST=builder.localhost \
416
- -- node /absolute-path/webcake-landing-mcp/dist/index.js
417
- ```
418
-
419
- Hoặc **CDN / npx** (không clone):
420
-
421
- ```bash
422
- claude mcp add webcake-landing \
423
- -e WEBCAKE_API_BASE=http://localhost:5800 \
424
- -e WEBCAKE_JWT=<your-jwt> \
425
- -- npx -y webcake-landing-mcp
426
- ```
288
+ ### Môi trường (`--env` / `WEBCAKE_ENV`)
427
289
 
428
- Hoặc tạo `.claude.json` thư mục gốc dự án (hoặc `~/.claude.json` toàn cục):
290
+ Thay đặt thủ công cả hai base URL, hãy chọn một môi trường có tên — một nguồn sự thật duy nhất
291
+ cho API + app base (mặc định là `prod`):
429
292
 
430
- ```json
431
- {
432
- "mcpServers": {
433
- "webcake-landing": {
434
- "command": "node",
435
- "args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
436
- "env": {
437
- "WEBCAKE_API_BASE": "http://localhost:5800",
438
- "WEBCAKE_JWT": "<your-jwt>"
439
- }
440
- }
441
- }
442
- }
443
- ```
293
+ | `--env` / `WEBCAKE_ENV` | API base (`WEBCAKE_API_BASE`) | App base (`WEBCAKE_APP_BASE`) |
294
+ |-------------------------|-------------------------------|-------------------------------|
295
+ | `local` | `http://localhost:5800` | `http://localhost:5173` |
296
+ | `staging` | `https://api.staging.webcake.io` | `https://staging.webcake.io` |
297
+ | `prod` *(mặc định)* | `https://api.webcake.io` | `https://webcake.io` |
444
298
 
445
- Kiểm tra:
446
299
  ```bash
447
- claude mcp list
300
+ node dist/index.js serve --env staging # server remote trỏ backend staging
301
+ node dist/index.js login --env local # đăng nhập vào SPA + API local
302
+ WEBCAKE_ENV=prod node dist/index.js # stdio, prod (dạng biến môi trường)
448
303
  ```
449
304
 
450
- ---
451
-
452
- ### 3. Cursor
305
+ `WEBCAKE_API_BASE` / `WEBCAKE_APP_BASE` (hoặc `--api-base`) tường minh vẫn ghi đè preset theo từng
306
+ trường. Trên server HTTP remote, client có thể ghi đè môi trường của server theo từng request bằng
307
+ header **`x-webcake-env`** hoặc query **`?env=`** (ví dụ `…/mcp?jwt=<token>&env=staging`) — nên một
308
+ server phục vụ được nhiều môi trường.
453
309
 
454
- Tạo `.cursor/mcp.json` gốc dự án (hoặc `~/.cursor/mcp.json` toàn cục):
455
-
456
- ```json
457
- {
458
- "mcpServers": {
459
- "webcake-landing": {
460
- "command": "node",
461
- "args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
462
- "env": {
463
- "WEBCAKE_API_BASE": "http://localhost:5800",
464
- "WEBCAKE_JWT": "<your-jwt>"
465
- }
466
- }
467
- }
468
- }
469
- ```
470
-
471
- Khởi động lại Cursor và xem Settings > MCP Servers để thấy trạng thái **"Connected"**.
472
-
473
- ---
474
-
475
- ### 4. Windsurf
476
-
477
- Tạo `~/.codeium/windsurf/mcp_config.json`:
478
-
479
- ```json
480
- {
481
- "mcpServers": {
482
- "webcake-landing": {
483
- "command": "node",
484
- "args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
485
- "env": {
486
- "WEBCAKE_API_BASE": "http://localhost:5800",
487
- "WEBCAKE_JWT": "<your-jwt>"
488
- }
489
- }
490
- }
491
- }
492
- ```
493
-
494
- Khởi động lại Windsurf. Gõ `@` trong chat Cascade để thấy các tool `webcake-landing`.
495
-
496
- ---
497
-
498
- ### 5. Augment (Extension VS Code)
499
-
500
- Mở Command Palette: `Cmd + Shift + P` > **"Augment: Edit MCP Settings"**, rồi thêm:
501
-
502
- ```json
503
- {
504
- "mcpServers": {
505
- "webcake-landing": {
506
- "command": "node",
507
- "args": ["/absolute-path/webcake-landing-mcp/dist/index.js"],
508
- "env": {
509
- "WEBCAKE_API_BASE": "http://localhost:5800",
510
- "WEBCAKE_JWT": "<your-jwt>"
511
- }
512
- }
513
- }
514
- }
515
- ```
310
+ ### Cách lấy `WEBCAKE_JWT`
516
311
 
517
- Khởi động lại VS Code.
312
+ 1. Mở dashboard builder WebCake và đăng nhập
313
+ 2. Mở DevTools (`F12` hoặc `Cmd + Option + I`)
314
+ 3. Vào tab **Network** > click một trang bất kỳ
315
+ 4. Tìm một request API (ví dụ `@me`, `organizations`…)
316
+ 5. Trong **Request Headers**, copy giá trị sau `Authorization: Bearer ` → đó là `WEBCAKE_JWT`
317
+ 6. Dùng tool `list_organizations` để liệt kê org và chọn `WEBCAKE_ORG_ID`
518
318
 
519
319
  ---
520
320
 
521
- ### 6. Codex (OpenAI CLI)
522
-
523
- Thêm vào `~/.codex/config.toml`:
524
-
525
- ```toml
526
- [mcp_servers.webcake-landing]
527
- command = "node"
528
- args = ["/absolute-path/webcake-landing-mcp/dist/index.js"]
529
- env = { "WEBCAKE_API_BASE" = "http://localhost:5800", "WEBCAKE_JWT" = "<your-jwt>" }
530
- ```
321
+ ## Cấu hình theo IDE
531
322
 
532
- Kiểm tra:
533
- ```bash
534
- codex mcp list
535
- ```
536
-
537
- ---
323
+ Lệnh con `install` của npx (xem trên) tự ghi cấu hình đúng cho từng IDE. Nếu muốn tự viết tay cấu hình cho Claude Desktop, Claude Code, Cursor, Windsurf, Augment, hay Codex — và cả dạng dùng file build từ clone — xem **[docs/manual-install.vi.md](docs/manual-install.vi.md#cấu-hình-theo-ide--công-cụ-ai)**.
538
324
 
539
325
  ## Ví dụ sử dụng
540
326
 
@@ -11,7 +11,7 @@
11
11
  * which the stdio/http server then reads automatically.
12
12
  *
13
13
  * Backend contract (added to landing_page_backend — owned by the user):
14
- * GET {WEBCAKE_CONNECT_URL}?redirect_uri=<loopback>&state=<s>
14
+ * GET <connect-url>?redirect_uri=<loopback>&state=<s> (connect-url = appBase + /mcp-connect)
15
15
  * → read cookie `jwt` → 302 to <redirect_uri>?token=<jwt>&state=<s>
16
16
  * (or 302 to the login page first, then back). Restrict redirect_uri to
17
17
  * http://127.0.0.1:* / http://localhost:* for safety.
@@ -19,13 +19,7 @@
19
19
  import { createServer } from "node:http";
20
20
  import { randomBytes } from "node:crypto";
21
21
  import { spawn } from "node:child_process";
22
- import { saveSavedConfig } from "../persistence/config.js";
23
- // Production defaults — the connect page lives on the SPA (webcake.io), the API
24
- // lives on api.webcake.io. For local dev override with --connect-url / --api-base
25
- // (e.g. http://localhost:5173/mcp-connect and http://localhost:5800) or the
26
- // WEBCAKE_APP_BASE / WEBCAKE_API_BASE env vars.
27
- const DEFAULT_CONNECT_URL = "https://webcake.io/mcp-connect";
28
- const DEFAULT_API_BASE = "https://api.webcake.io";
22
+ import { saveSavedConfig, resolveEnv, ENVIRONMENTS } from "../persistence/config.js";
29
23
  function parseArgs(argv) {
30
24
  const get = (name) => {
31
25
  const i = argv.indexOf(name);
@@ -53,21 +47,20 @@ function openBrowser(url) {
53
47
  const SUCCESS_HTML = `<!doctype html><meta charset="utf-8"><title>Connected</title>
54
48
  <body style="font-family:system-ui;text-align:center;padding:48px">
55
49
  <h2>✓ Connected to Webcake</h2><p>You can close this tab and return to your terminal.</p></body>`;
56
- function resolveConnectUrl(opts) {
50
+ function resolveConnectUrl(opts, appBase) {
57
51
  if (opts.connectUrl)
58
- return opts.connectUrl;
59
- if (process.env.WEBCAKE_CONNECT_URL)
60
- return process.env.WEBCAKE_CONNECT_URL;
61
- // The connect page is on the SPA (WEBCAKE_APP_BASE), NOT the API base.
62
- const appBase = process.env.WEBCAKE_APP_BASE;
63
- if (appBase)
64
- return `${appBase.replace(/\/+$/, "")}/mcp-connect`;
65
- return DEFAULT_CONNECT_URL;
52
+ return opts.connectUrl; // explicit --connect-url override
53
+ // The connect page is on the SPA (appBase, from the env preset), NOT the API base.
54
+ return `${appBase.replace(/\/+$/, "")}/mcp-connect`;
66
55
  }
67
56
  export async function runLogin(argv) {
68
57
  const opts = parseArgs(argv);
69
- const connectUrl = resolveConnectUrl(opts);
70
- const apiBase = opts.apiBase || process.env.WEBCAKE_API_BASE || DEFAULT_API_BASE;
58
+ // Named environment (set by the global --env flag / WEBCAKE_ENV); prod is the
59
+ // zero-config default. Explicit --api-base / WEBCAKE_APP_BASE still win per field.
60
+ const preset = resolveEnv(process.env.WEBCAKE_ENV) ?? ENVIRONMENTS.prod;
61
+ const apiBase = opts.apiBase || process.env.WEBCAKE_API_BASE || preset.apiBase;
62
+ const appBase = process.env.WEBCAKE_APP_BASE || preset.appBase;
63
+ const connectUrl = resolveConnectUrl(opts, appBase);
71
64
  const state = randomBytes(16).toString("hex");
72
65
  await new Promise((resolve, reject) => {
73
66
  const server = createServer((req, res) => {
@@ -83,15 +76,13 @@ export async function runLogin(argv) {
83
76
  }
84
77
  const path = saveSavedConfig({
85
78
  jwt: token,
86
- ...(apiBase ? { base: apiBase.replace(/\/+$/, "") } : {}),
79
+ base: apiBase.replace(/\/+$/, ""),
80
+ appBase: appBase.replace(/\/+$/, ""),
87
81
  ...(opts.orgId ? { orgId: opts.orgId } : {}),
88
82
  savedAt: new Date().toISOString(),
89
83
  });
90
84
  res.writeHead(200, { "content-type": "text/html" }).end(SUCCESS_HTML);
91
- console.error(`\n✓ Connected. Token saved to ${path}`);
92
- if (!apiBase) {
93
- console.error(" tip: also set WEBCAKE_API_BASE (or pass --api-base) so the server knows the backend URL.");
94
- }
85
+ console.error(`\n✓ Connected. Token saved to ${path} (api ${apiBase}).`);
95
86
  server.close();
96
87
  resolve();
97
88
  });
package/dist/http.js CHANGED
@@ -39,9 +39,9 @@ async function readBody(req) {
39
39
  // require HTTPS, and disable query-string logging on your reverse proxy.
40
40
  const QUERY_AUTH = {
41
41
  jwt: "x-webcake-jwt",
42
+ env: "x-webcake-env",
42
43
  api_base: "x-webcake-api-base",
43
44
  org_id: "x-webcake-org-id",
44
- host: "x-webcake-host",
45
45
  app_base: "x-webcake-app-base",
46
46
  };
47
47
  function applyQueryAuth(req) {
package/dist/index.js CHANGED
@@ -17,7 +17,40 @@
17
17
  */
18
18
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
19
19
  import { createServer } from "./server.js";
20
+ import { ENVIRONMENTS, ENV_NAMES, isEnvName } from "./persistence/config.js";
21
+ /**
22
+ * Global `--env <local|staging|prod>` flag (or `--env=<name>`): selects the API +
23
+ * app base URLs from a named preset by setting WEBCAKE_ENV, which readConfig + login
24
+ * then pick up. Explicit WEBCAKE_API_BASE / WEBCAKE_APP_BASE still win. An unknown
25
+ * value from the flag fails fast; an unknown WEBCAKE_ENV is dropped so explicit
26
+ * bases (or per-request headers) still resolve. stderr only — stdout is the MCP channel.
27
+ */
28
+ function applyEnvFlag(argv) {
29
+ let fromFlag;
30
+ for (let i = 2; i < argv.length; i++) {
31
+ const a = argv[i];
32
+ if (a === "--env")
33
+ fromFlag = argv[i + 1];
34
+ else if (a.startsWith("--env="))
35
+ fromFlag = a.slice("--env=".length);
36
+ }
37
+ const name = fromFlag ?? process.env.WEBCAKE_ENV;
38
+ if (!name)
39
+ return;
40
+ if (!isEnvName(name)) {
41
+ console.error(`[webcake] unknown environment "${name}". Valid: ${ENV_NAMES.join(", ")}.`);
42
+ if (fromFlag)
43
+ process.exit(1); // explicit flag typo → fail fast
44
+ delete process.env.WEBCAKE_ENV; // bad WEBCAKE_ENV → ignore, fall through to explicit bases
45
+ return;
46
+ }
47
+ process.env.WEBCAKE_ENV = name;
48
+ const p = ENVIRONMENTS[name];
49
+ console.error(`[webcake] environment "${name}" — api ${p.apiBase}, app ${p.appBase}`);
50
+ }
20
51
  async function main() {
52
+ // Resolve the named environment (--env / WEBCAKE_ENV) before any config is read.
53
+ applyEnvFlag(process.argv);
21
54
  // Subcommand dispatch: `webcake-landing-mcp install|uninstall` runs the
22
55
  // bundled IDE installer instead of starting the MCP server. Default (no
23
56
  // subcommand) starts the stdio server as usual.
package/dist/install.js CHANGED
@@ -22,6 +22,8 @@ import { dirname, join } from "node:path";
22
22
  import { fileURLToPath } from "node:url";
23
23
  import { spawnSync } from "node:child_process";
24
24
  import { createInterface } from "node:readline";
25
+ import { ENVIRONMENTS, isEnvName } from "./persistence/config.js";
26
+ import { runLogin } from "./auth/login.js";
25
27
  const NAME = "webcake-landing";
26
28
  const PKG = "webcake-landing-mcp";
27
29
  const HOME = homedir();
@@ -63,8 +65,6 @@ function parseArgs(argv) {
63
65
  o.jwt = next();
64
66
  else if (a.startsWith("--org-id") || a.startsWith("--org"))
65
67
  o.orgId = next();
66
- else if (a.startsWith("--host"))
67
- o.host = next();
68
68
  else if (a.startsWith("--app-base"))
69
69
  o.appBase = next();
70
70
  else if (a === "--help" || a === "-h")
@@ -290,18 +290,18 @@ function printHelp() {
290
290
  ${c.bold}webcake-landing-mcp install${c.reset} — configure the MCP server in your IDE(s)
291
291
 
292
292
  ${c.bold}Usage${c.reset}
293
- npx -y ${PKG} install # interactive (asks step by step)
294
- npx -y ${PKG} install --ide all # non-interactive, all IDEs
295
- npx -y ${PKG} install --ide claude-code --jwt <JWT> --api-base http://localhost:5800
293
+ npx -y ${PKG} install # interactive: pick environment, log in (or paste a JWT), pick IDEs
294
+ npx -y ${PKG} install --ide all # non-interactive, all IDEs (defaults to --env prod)
295
+ npx -y ${PKG} install --ide claude-code --env local --jwt <JWT>
296
296
  npx -y ${PKG} uninstall # remove from every IDE config
297
297
 
298
298
  ${c.bold}Flags${c.reset}
299
299
  --ide <list> comma list: claude-desktop, claude-code, cursor, windsurf, augment, codex, all
300
- --api-base <url> WEBCAKE_API_BASE (default http://localhost:5800)
301
- --jwt <token> WEBCAKE_JWT (account token; optional, needed to persist)
302
- --org-id <id> WEBCAKE_ORG_ID (optional)
303
- --host <host> WEBCAKE_HOST (optional)
304
- --app-base <url> WEBCAKE_APP_BASE (optional)
300
+ --env <name> WEBCAKE_ENV: local | staging | prod (default prod) — sets the API + app base URLs
301
+ --jwt <token> WEBCAKE_JWT (account token; optional or log in via the browser interactively)
302
+ --org-id <id> WEBCAKE_ORG_ID (optional default organization)
303
+ --api-base <url> override the --env API base (advanced)
304
+ --app-base <url> override the --env app base (advanced)
305
305
  --npx | --local force the launch command form (default: auto-detect)
306
306
  -y, --yes accept defaults, skip confirmations
307
307
  --uninstall remove the server from all IDE configs
@@ -317,36 +317,70 @@ export async function runInstaller(argv) {
317
317
  log(`\n${c.cyan}${c.bold}Webcake Landing MCP — installer${c.reset}`);
318
318
  log(`${c.gray}Build & edit Webcake landing pages from a prompt. 12 tools.${c.reset}`);
319
319
  const interactive = !o.ide && process.stdin.isTTY && process.stdout.isTTY;
320
- // 1) env
321
- const env = {};
322
- let apiBase = o.apiBase ?? process.env.WEBCAKE_API_BASE ?? "";
323
- let jwt = o.jwt ?? process.env.WEBCAKE_JWT ?? "";
324
- let orgId = o.orgId ?? process.env.WEBCAKE_ORG_ID ?? "";
325
- const host = o.host ?? process.env.WEBCAKE_HOST ?? "";
326
- const appBase = o.appBase ?? process.env.WEBCAKE_APP_BASE ?? "";
327
- if (interactive) {
328
- log(`\n${c.bold}1) Config${c.reset} ${c.gray}(Enter to skip — reference tools work with no creds)${c.reset}`);
329
- apiBase =
330
- (await ask(` WEBCAKE_API_BASE [${apiBase || "http://localhost:5800"}]: `)) ||
331
- apiBase ||
332
- "http://localhost:5800";
333
- jwt = (await ask(` WEBCAKE_JWT (account token, optional): `)) || jwt;
334
- orgId = (await ask(` WEBCAKE_ORG_ID (optional): `)) || orgId;
320
+ // 1) environment — one choice sets the API + app base URLs (replaces the old
321
+ // separate WEBCAKE_API_BASE / WEBCAKE_APP_BASE prompts). The global --env flag
322
+ // / WEBCAKE_ENV is already validated in index.ts (applyEnvFlag).
323
+ let envName = isEnvName(process.env.WEBCAKE_ENV) ? process.env.WEBCAKE_ENV : "prod";
324
+ if (interactive && !isEnvName(process.env.WEBCAKE_ENV)) {
325
+ log(`\n${c.bold}1) Environment${c.reset} ${c.gray}(sets the Webcake API + app URLs)${c.reset}`);
326
+ log(` 1) prod ${c.gray}${ENVIRONMENTS.prod.apiBase}${c.reset} ${c.gray}(default)${c.reset}`);
327
+ log(` 2) staging ${c.gray}${ENVIRONMENTS.staging.apiBase}${c.reset}`);
328
+ log(` 3) local ${c.gray}${ENVIRONMENTS.local.apiBase}${c.reset}`);
329
+ const pick = (await ask(" Select [1=prod, Enter to accept]: ")).trim();
330
+ envName = { "1": "prod", "2": "staging", "3": "local" }[pick] ?? "prod";
331
+ }
332
+ process.env.WEBCAKE_ENV = envName; // so `login` below connects to the same environment
333
+ const preset = ENVIRONMENTS[envName];
334
+ // 2) authentication interactively ASK how to authenticate: browser login (token
335
+ // saved to ~/.webcake-landing-mcp/auth.json) or a pasted JWT. An explicit --jwt
336
+ // skips the prompt; a non-TTY falls back to the WEBCAKE_JWT env var (for scripted
337
+ // installs). Reference/validation tools work with no auth at all.
338
+ let jwt = o.jwt ?? "";
339
+ let authNote = jwt ? "JWT (from --jwt)" : "";
340
+ if (interactive && !jwt) {
341
+ log(`\n${c.bold}2) Authentication${c.reset} ${c.gray}(only needed to save pages to your account)${c.reset}`);
342
+ log(` 1) Log in via browser ${c.gray}(recommended — opens Webcake, saves a token)${c.reset}`);
343
+ log(` 2) Paste a JWT token`);
344
+ log(` 3) Skip for now ${c.gray}(reference/validation tools still work)${c.reset}`);
345
+ const pick = (await ask(" Select [1]: ")).trim() || "1";
346
+ if (pick === "1") {
347
+ info(`Connecting to ${preset.appBase} …`);
348
+ try {
349
+ await runLogin([]); // reads WEBCAKE_ENV for the connect URL + API base; saves auth.json
350
+ authNote = "browser login (saved to auth.json)";
351
+ }
352
+ catch (e) {
353
+ warn(`Login didn't complete (${e?.message ?? e}). Paste a JWT now, or run \`${PKG} login\` later.`);
354
+ jwt = (await ask(" WEBCAKE_JWT (or Enter to skip): ")).trim();
355
+ }
356
+ }
357
+ else if (pick === "2") {
358
+ jwt = (await ask(" WEBCAKE_JWT: ")).trim();
359
+ }
335
360
  }
336
- else if (!apiBase) {
337
- apiBase = "http://localhost:5800";
361
+ else if (!interactive) {
362
+ jwt = jwt || process.env.WEBCAKE_JWT || ""; // scripted / CI: fall back to ambient env
363
+ }
364
+ if (!authNote)
365
+ authNote = jwt ? "JWT" : "none — reference tools only";
366
+ // 3) optional default organization for create_page
367
+ let orgId = o.orgId ?? process.env.WEBCAKE_ORG_ID ?? "";
368
+ if (interactive && !orgId) {
369
+ orgId = (await ask(`\n${c.bold}3) WEBCAKE_ORG_ID${c.reset} ${c.gray}(optional, Enter to skip): ${c.reset}`)).trim();
338
370
  }
339
- if (apiBase)
340
- env.WEBCAKE_API_BASE = apiBase;
371
+ // env block written into IDE configs: WEBCAKE_ENV drives the URLs. A pasted JWT is
372
+ // written too; a browser login lives in auth.json instead. --api-base/--app-base/
373
+ // --host stay as advanced overrides for non-standard setups.
374
+ const env = { WEBCAKE_ENV: envName };
341
375
  if (jwt)
342
376
  env.WEBCAKE_JWT = jwt;
343
377
  if (orgId)
344
378
  env.WEBCAKE_ORG_ID = orgId;
345
- if (host)
346
- env.WEBCAKE_HOST = host;
347
- if (appBase)
348
- env.WEBCAKE_APP_BASE = appBase;
349
- // 2) which IDEs
379
+ if (o.apiBase)
380
+ env.WEBCAKE_API_BASE = o.apiBase;
381
+ if (o.appBase)
382
+ env.WEBCAKE_APP_BASE = o.appBase;
383
+ // 4) which IDEs
350
384
  let ides = [];
351
385
  if (o.ide) {
352
386
  ides = o.ide
@@ -355,7 +389,7 @@ export async function runInstaller(argv) {
355
389
  .filter(Boolean);
356
390
  }
357
391
  else if (interactive) {
358
- log(`\n${c.bold}2) Which IDE(s) to configure?${c.reset}`);
392
+ log(`\n${c.bold}4) Which IDE(s) to configure?${c.reset}`);
359
393
  log(" 1) Claude Desktop 2) Claude Code (CLI) 3) Cursor");
360
394
  log(" 4) Windsurf 5) Augment (VS Code) 6) Codex");
361
395
  log(" 7) All 0) Skip");
@@ -383,13 +417,13 @@ export async function runInstaller(argv) {
383
417
  warn("No IDE selected — skipping configuration.");
384
418
  return;
385
419
  }
386
- // 3) write
420
+ // 5) write
387
421
  const launch = resolveLaunch(o);
388
- log(`\n${c.bold}3) Writing config${c.reset} ${c.gray}(launch: ${launch.command} ${launch.args.join(" ")})${c.reset}`);
422
+ log(`\n${c.bold}5) Writing config${c.reset} ${c.gray}(launch: ${launch.command} ${launch.args.join(" ")})${c.reset}`);
389
423
  runConfigure(ides, launch, env);
390
- // 4) summary
424
+ // 6) summary
391
425
  log(`\n${c.green}${c.bold}✓ Done.${c.reset}`);
392
- log(` ${c.gray}API base : ${apiBase || "(unset)"}${c.reset}`);
393
- log(` ${c.gray}JWT : ${jwt ? jwt.slice(0, 8) + "…" : "(unset — reference tools still work)"}${c.reset}`);
426
+ log(` ${c.gray}Environment : ${envName} (api ${o.apiBase || preset.apiBase})${c.reset}`);
427
+ log(` ${c.gray}Auth : ${authNote}${c.reset}`);
394
428
  log(` Restart your IDE, then ask the AI: “Build a Webcake landing page”.\n`);
395
429
  }
@@ -12,19 +12,44 @@
12
12
  * { config: null, missing } when required values are absent so the persistence
13
13
  * tools can report exactly what to provide.
14
14
  *
15
+ * WEBCAKE_ENV optional named environment (local|staging|prod) — fills in the
16
+ * API + app base URLs from a preset (see ENVIRONMENTS below). An
17
+ * explicit WEBCAKE_API_BASE / WEBCAKE_APP_BASE still wins over it.
15
18
  * WEBCAKE_API_BASE e.g. http://localhost:5800 (required to call the backend)
16
19
  * WEBCAKE_JWT the account JWT (required to call the backend)
17
20
  * WEBCAKE_ORG_ID optional default organization id for create_page
18
- * WEBCAKE_HOST optional Host header override (Phoenix routes by host)
19
21
  * WEBCAKE_APP_BASE optional base for editor/preview URLs in the result
20
22
  * WEBCAKE_CONFIG_DIR optional dir for the saved auth.json (default ~/.webcake-landing-mcp)
21
23
  */
22
24
  import { homedir } from "node:os";
23
25
  import { join } from "node:path";
24
26
  import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
27
+ /**
28
+ * Named deployment environments — the single source of truth for the API + app
29
+ * base URLs. Selecting one (via the `--env` flag, WEBCAKE_ENV, the `x-webcake-env`
30
+ * header, or `?env=` in the URL) fills in both bases so callers don't repeat them.
31
+ * Explicit WEBCAKE_API_BASE / WEBCAKE_APP_BASE (or per-request overrides) win over
32
+ * the preset. `apiBase` is the backend; `appBase` is the SPA (editor/preview/connect).
33
+ */
34
+ export const ENVIRONMENTS = {
35
+ local: { apiBase: "http://localhost:5800", appBase: "http://localhost:5173" },
36
+ staging: { apiBase: "https://api.staging.webcake.io", appBase: "https://staging.webcake.io" },
37
+ prod: { apiBase: "https://api.webcake.io", appBase: "https://webcake.io" },
38
+ };
39
+ export const ENV_NAMES = Object.keys(ENVIRONMENTS);
40
+ /** True when `v` names a known environment (local|staging|prod). */
41
+ export function isEnvName(v) {
42
+ return typeof v === "string" && Object.prototype.hasOwnProperty.call(ENVIRONMENTS, v);
43
+ }
44
+ /** The base URLs for a named environment, or undefined when the name is absent/unknown. */
45
+ export function resolveEnv(name) {
46
+ return isEnvName(name) ? ENVIRONMENTS[name] : undefined;
47
+ }
25
48
  export function readConfig(overrides = {}) {
26
49
  const saved = readSavedConfig();
27
- const base = overrides.base ?? process.env.WEBCAKE_API_BASE ?? saved.base;
50
+ // A named environment supplies default base URLs; explicit values still win.
51
+ const preset = resolveEnv(overrides.env ?? process.env.WEBCAKE_ENV);
52
+ const base = overrides.base ?? process.env.WEBCAKE_API_BASE ?? preset?.apiBase ?? saved.base;
28
53
  const jwt = overrides.jwt ?? process.env.WEBCAKE_JWT ?? saved.jwt;
29
54
  const missing = [];
30
55
  if (!base)
@@ -38,8 +63,7 @@ export function readConfig(overrides = {}) {
38
63
  base: base.replace(/\/+$/, ""),
39
64
  jwt: jwt,
40
65
  orgId: overrides.orgId ?? process.env.WEBCAKE_ORG_ID ?? saved.orgId,
41
- host: overrides.host ?? process.env.WEBCAKE_HOST ?? saved.host,
42
- appBase: (overrides.appBase ?? process.env.WEBCAKE_APP_BASE ?? saved.appBase)?.replace(/\/+$/, ""),
66
+ appBase: (overrides.appBase ?? process.env.WEBCAKE_APP_BASE ?? preset?.appBase ?? saved.appBase)?.replace(/\/+$/, ""),
43
67
  },
44
68
  missing: [],
45
69
  };
@@ -53,9 +77,9 @@ function header(headers, name) {
53
77
  * send its own credentials per request instead of a server-wide env token:
54
78
  * x-webcake-jwt the account JWT (or `Authorization: Bearer <jwt>`)
55
79
  * x-webcake-org-id organization id
56
- * x-webcake-api-base backend base URL (usually set once via env instead)
57
- * x-webcake-host Host header override
58
- * x-webcake-app-base editor/preview URL base
80
+ * x-webcake-env named environment (local|staging|prod) for the base URLs
81
+ * x-webcake-api-base backend base URL (overrides the env preset)
82
+ * x-webcake-app-base editor/preview URL base (overrides the env preset)
59
83
  * Any header that is absent falls back to the corresponding env var in readConfig.
60
84
  */
61
85
  export function configFromHeaders(headers) {
@@ -65,8 +89,8 @@ export function configFromHeaders(headers) {
65
89
  base: header(headers, "x-webcake-api-base"),
66
90
  jwt: header(headers, "x-webcake-jwt") ?? bearer,
67
91
  orgId: header(headers, "x-webcake-org-id"),
68
- host: header(headers, "x-webcake-host"),
69
92
  appBase: header(headers, "x-webcake-app-base"),
93
+ env: header(headers, "x-webcake-env"),
70
94
  };
71
95
  }
72
96
  /** Directory for the saved auth file (override with WEBCAKE_CONFIG_DIR). */
@@ -10,8 +10,6 @@ function authHeaders(config, orgId) {
10
10
  Authorization: `Bearer ${config.jwt}`,
11
11
  Cookie: `jwt=${config.jwt}`,
12
12
  };
13
- if (config.host)
14
- headers["Host"] = config.host;
15
13
  const org = orgId ?? config.orgId;
16
14
  if (org != null && `${org}` !== "")
17
15
  headers["x-org-id"] = `${org}`;
package/dist/smoke.js CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { createElement, CONTAINER_TYPES, FIELD_TYPES, LIBRARY, ELEMENT_TYPES, ELEMENTS, } from "./domains/landing/elements/index.js";
6
6
  import { validatePage, pageSchema } from "./domains/landing/validate.js";
7
+ import { readConfig, resolveEnv, ENV_NAMES } from "./persistence/config.js";
7
8
  let failures = 0;
8
9
  const check = (name, cond, extra) => {
9
10
  if (cond) {
@@ -208,5 +209,21 @@ const bindingsGood = {
208
209
  };
209
210
  const rbg = validatePage(bindingsGood);
210
211
  check("clean form has no binding warnings", rbg.warnings.length === 0, rbg.warnings);
212
+ console.log("== config: named environment presets (local/staging/prod) ==");
213
+ {
214
+ // Deterministic: isolate from any ambient WEBCAKE_* and the saved auth.json on the dev box.
215
+ for (const k of ["WEBCAKE_API_BASE", "WEBCAKE_APP_BASE", "WEBCAKE_ENV", "WEBCAKE_JWT", "WEBCAKE_ORG_ID"])
216
+ delete process.env[k];
217
+ process.env.WEBCAKE_CONFIG_DIR = "/nonexistent/webcake-smoke";
218
+ check("env names are local/staging/prod", setEq(new Set(ENV_NAMES), ["local", "staging", "prod"]), ENV_NAMES);
219
+ check("staging preset resolves to api+app bases", resolveEnv("staging")?.apiBase === "https://api.staging.webcake.io" && resolveEnv("staging")?.appBase === "https://staging.webcake.io");
220
+ check("unknown env name → undefined", resolveEnv("bogus") === undefined);
221
+ const prod = readConfig({ env: "prod", jwt: "t" }).config;
222
+ check("readConfig(env=prod) fills api+app base", prod?.base === "https://api.webcake.io" && prod?.appBase === "https://webcake.io", prod);
223
+ const local = readConfig({ env: "local", jwt: "t" }).config;
224
+ check("readConfig(env=local) fills api+app base", local?.base === "http://localhost:5800" && local?.appBase === "http://localhost:5173", local);
225
+ check("explicit base overrides the preset", readConfig({ env: "prod", base: "http://x:1", jwt: "t" }).config?.base === "http://x:1");
226
+ check("unknown env leaves base missing", readConfig({ env: "bogus", jwt: "t" }).missing.includes("WEBCAKE_API_BASE"));
227
+ }
211
228
  console.log(`\n${failures === 0 ? "ALL GOOD" : failures + " FAILURE(S)"}`);
212
229
  process.exit(failures === 0 ? 0 : 1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webcake-landing-mcp",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "MCP server exposing Webcake landing-page element schemas + AI usage hints, and persisting LLM-generated page sources to a Webcake backend.",
5
5
  "type": "module",
6
6
  "bin": {