webcake-landing-mcp 1.0.13 → 1.0.15
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 +72 -176
- package/README.vi.md +69 -174
- package/dist/branding.js +29 -0
- package/dist/http.js +18 -0
- package/dist/server.js +10 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# <img src="docs/assets/webcake-icon.svg" alt="Webcake" width="26" height="26" align="absmiddle"> WebCake Landing MCP
|
|
2
2
|
|
|
3
3
|
**English** · [Tiếng Việt](./README.vi.md)
|
|
4
4
|
|
|
@@ -58,13 +58,53 @@ persists it (source-only — the page opens in the editor where re-saving render
|
|
|
58
58
|
|
|
59
59
|
| Method | Best for | Auth |
|
|
60
60
|
|--------|----------|------|
|
|
61
|
-
| **npx (local
|
|
62
|
-
| **
|
|
61
|
+
| **npx (local)** — runs on your machine | Personal daily use, full control | browser `login`, a JWT, or none (reference tools) |
|
|
62
|
+
| **Hosted URL** — use our live server, nothing to install | No Node.js, teams, the claude.ai dialog | your personal `?jwt=` link / `x-webcake-jwt` header |
|
|
63
63
|
|
|
64
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`).
|
|
65
65
|
|
|
66
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)**.
|
|
67
67
|
|
|
68
|
+
## 🚀 Get connected — the 2 main ways
|
|
69
|
+
|
|
70
|
+
Pick **one**. Both hand your AI tool (Claude, Cursor, …) the full Webcake landing toolkit. No coding.
|
|
71
|
+
|
|
72
|
+
### ① `npx` — runs on your machine (recommended for personal use)
|
|
73
|
+
|
|
74
|
+
Zero install, always the latest version. **One line** grabs your token *and* writes the IDE config:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npx -y webcake-landing-mcp install
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Just want to run the server (configure by hand later)?
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx -y webcake-landing-mcp
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
✅ Best for: daily personal use, local development, full control. Needs Node.js 18+.
|
|
87
|
+
|
|
88
|
+
### ② Remote URL `…/mcp?jwt=` — hosted, nothing to install
|
|
89
|
+
|
|
90
|
+
Use the server we already host. Grab **your personal link** (your token is baked in) and paste it into your client's *Add custom connector* / config:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
https://mcp.toolvn.io.vn/mcp?jwt=<YOUR_TOKEN>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Two ways to get the link:
|
|
97
|
+
- **Easiest** — open **<https://webcake.io/mcp-remote>** in your Webcake dashboard → it builds & copies the link for you.
|
|
98
|
+
- **By hand** — see the step-by-step guide below.
|
|
99
|
+
|
|
100
|
+
You can also add extra params: `&env=prod`, `&org_id=…`, `&api_base=…`.
|
|
101
|
+
|
|
102
|
+
✅ Best for: no Node.js, team/shared use, the **claude.ai** connector dialog (URL-only, no headers).
|
|
103
|
+
⚠️ The link contains your personal token — treat it like a password, always use **HTTPS**.
|
|
104
|
+
|
|
105
|
+
> 📖 **Full hand-config for every IDE** (Claude Desktop, Claude Code, Cursor, Windsurf, claude.ai…) is in the
|
|
106
|
+
> step-by-step guide → **[docs/connect-mcp.md](docs/connect-mcp.md)** · Tiếng Việt: **[docs/ket-noi-mcp.md](docs/ket-noi-mcp.md)**.
|
|
107
|
+
|
|
68
108
|
## Install (npx)
|
|
69
109
|
|
|
70
110
|
Once published to npm, the server runs straight from the registry — no clone, no build:
|
|
@@ -127,34 +167,25 @@ The MCP config is the same as the local one, but `command`/`args` point at `npx`
|
|
|
127
167
|
> npx caches the package after the first run, so subsequent launches are fast. Use a pinned version
|
|
128
168
|
> (`webcake-landing-mcp@1.0.0`) if you need a reproducible build.
|
|
129
169
|
|
|
130
|
-
##
|
|
170
|
+
## Use the hosted server — nothing to install
|
|
131
171
|
|
|
132
|
-
|
|
133
|
-
|
|
172
|
+
It's **already live** at **`https://mcp.toolvn.io.vn/mcp`** — we run it for you. No server to set up, no
|
|
173
|
+
machine to keep awake. Just point your AI client at the URL and go.
|
|
134
174
|
|
|
135
|
-
|
|
175
|
+
**Grab your personal link** (your token is baked in) the easy way → open **<https://webcake.io/mcp-remote>**
|
|
176
|
+
and hit **Copy**:
|
|
136
177
|
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
# → MCP endpoint at http://localhost:8787/mcp (GET / or /health returns a status JSON)
|
|
178
|
+
```
|
|
179
|
+
https://mcp.toolvn.io.vn/mcp?jwt=<YOUR_TOKEN>
|
|
140
180
|
```
|
|
141
181
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
- **Name**: `webcake-landing`
|
|
146
|
-
- **Remote MCP server URL**: `https://<your-host>/mcp`
|
|
147
|
-
|
|
148
|
-
The dialog has no header field, so to pass a token through it, **put it in the URL**:
|
|
149
|
-
`https://<your-host>/mcp?jwt=<ljwt>` (also accepts `&api_base=…`, `&org_id=…`, `&host=…`, `&app_base=…`).
|
|
150
|
-
Give each person a URL with their own `jwt` → **per-user without OAuth**. An explicit `x-webcake-jwt` header
|
|
151
|
-
still wins over the query. ⚠️ A token in a URL can land in access/proxy logs — require **HTTPS** and disable
|
|
152
|
-
query-string logging on your reverse proxy; a header (or OAuth) is safer when the client supports it.
|
|
182
|
+
Optional extras: `&env=prod`, `&org_id=…`, `&api_base=…`. Hand each teammate a link with their own `jwt` →
|
|
183
|
+
per-user, no OAuth. ⚠️ The link carries your personal token — treat it like a password, always over **HTTPS**.
|
|
153
184
|
|
|
154
|
-
###
|
|
185
|
+
### Sending the token as a header (safer)
|
|
155
186
|
|
|
156
|
-
|
|
157
|
-
|
|
187
|
+
Clients that support headers should send the token as a header instead of putting it in the URL (so it never
|
|
188
|
+
lands in logs). Any header that's missing falls back to the matching env var:
|
|
158
189
|
|
|
159
190
|
| Header | Maps to | Notes |
|
|
160
191
|
|--------|---------|-------|
|
|
@@ -164,61 +195,12 @@ via headers, so a hosted server is multi-user and never bakes in a shared secret
|
|
|
164
195
|
| `x-webcake-api-base` | `WEBCAKE_API_BASE` | overrides the env preset's API base |
|
|
165
196
|
| `x-webcake-app-base` | `WEBCAKE_APP_BASE` | overrides the env preset's app base |
|
|
166
197
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
>
|
|
172
|
-
>
|
|
173
|
-
>
|
|
174
|
-
> Note: the claude.ai connector dialog has **no header field** (only OAuth, which this server does not
|
|
175
|
-
> implement yet). Two ways around it: put the token in the URL as `?jwt=<ljwt>` (above — per-user, but the
|
|
176
|
-
> token shows up in logs), or use a header-capable client (`mcp-remote --header …`, below). A token in the
|
|
177
|
-
> server's env instead gives a shared **single-account** for everyone on that URL.
|
|
178
|
-
|
|
179
|
-
### Test it locally (no public URL needed)
|
|
180
|
-
|
|
181
|
-
`localhost` can't be used in the claude.ai dialog (Anthropic fetches the URL from its own servers). To try the
|
|
182
|
-
running `serve` server on your machine:
|
|
183
|
-
|
|
184
|
-
- **MCP Inspector** (GUI — easiest): `npx @modelcontextprotocol/inspector` → Transport **Streamable HTTP** →
|
|
185
|
-
URL `http://localhost:8787/mcp` → under Headers add `x-webcake-jwt` (+ `x-webcake-api-base`) → Connect → call tools.
|
|
186
|
-
- **`mcp-remote`** (use the remote server from a stdio client like Claude Desktop, with headers):
|
|
187
|
-
```json
|
|
188
|
-
{ "mcpServers": { "webcake-remote": { "command": "npx",
|
|
189
|
-
"args": ["-y", "mcp-remote", "http://localhost:8787/mcp",
|
|
190
|
-
"--header", "x-webcake-jwt:<ljwt>",
|
|
191
|
-
"--header", "x-webcake-api-base:https://api.webcake.io"] } } }
|
|
192
|
-
```
|
|
193
|
-
- **curl**: `initialize` (read the `mcp-session-id` response header) → `tools/list` → `tools/call`, all with
|
|
194
|
-
`Accept: application/json, text/event-stream`.
|
|
195
|
-
|
|
196
|
-
### Deploy on a VPS
|
|
197
|
-
|
|
198
|
-
1. **Build + run as a service** — `/etc/systemd/system/webcake-mcp.service`:
|
|
199
|
-
```ini
|
|
200
|
-
[Service]
|
|
201
|
-
WorkingDirectory=/opt/webcake-landing-mcp
|
|
202
|
-
ExecStart=/usr/bin/node dist/index.js serve --port 8787
|
|
203
|
-
Environment=WEBCAKE_API_BASE=https://api.webcake.io
|
|
204
|
-
Environment=WEBCAKE_JWT=<ljwt> # single-account only — see auth note below
|
|
205
|
-
Restart=always
|
|
206
|
-
[Install]
|
|
207
|
-
WantedBy=multi-user.target
|
|
208
|
-
```
|
|
209
|
-
`sudo systemctl enable --now webcake-mcp` (build once: `npm install && npm run build`).
|
|
210
|
-
2. **HTTPS + domain** (claude.ai requires https) — e.g. Caddy auto-TLS, `/etc/caddy/Caddyfile`:
|
|
211
|
-
```
|
|
212
|
-
mcp.yourdomain.com { reverse_proxy localhost:8787 }
|
|
213
|
-
```
|
|
214
|
-
3. **Add to claude.ai** → Remote MCP server URL = `https://mcp.yourdomain.com/mcp`.
|
|
215
|
-
|
|
216
|
-
**Auth on a shared server:**
|
|
217
|
-
- **Single-account** (works with the dialog today): `WEBCAKE_JWT` in the service env → everyone using the
|
|
218
|
-
connector shares that one Webcake account. Keep the URL private / gated; the token expires (~90 days).
|
|
219
|
-
- **Per-user** (each person their own account): give each person a URL with their own `?jwt=<ljwt>` (works
|
|
220
|
-
through the dialog, but the token appears in logs), or use a header-capable client (`mcp-remote --header …`),
|
|
221
|
-
or add **OAuth** (not implemented) for the cleanest flow.
|
|
198
|
+
> The reference + generation tools (`get_generation_guide`, `list_elements`, `validate_page`, …) need **no
|
|
199
|
+
> token** — only the persistence tools (`create_page`, `update_page`, …) use it. Without a JWT, those return
|
|
200
|
+
> `missing_env` instead of touching the network.
|
|
201
|
+
|
|
202
|
+
> 📖 **Full step-by-step for every IDE** (Claude Desktop, Claude Code, Cursor, Windsurf, claude.ai) →
|
|
203
|
+
> **[docs/connect-mcp.md](docs/connect-mcp.md)** · Tiếng Việt: **[docs/ket-noi-mcp.md](docs/ket-noi-mcp.md)**.
|
|
222
204
|
|
|
223
205
|
## Connect once — grab your token automatically (`login`)
|
|
224
206
|
|
|
@@ -243,8 +225,8 @@ It opens your browser → (log into Webcake if needed) → the token is saved to
|
|
|
243
225
|
|
|
244
226
|
You're already logged in to Webcake in your browser, so `login` just opens a Webcake "connect"
|
|
245
227
|
page that reads your **`ljwt`** (landing) cookie and hands the token back to a localhost callback —
|
|
246
|
-
no copy-paste. The saved token is
|
|
247
|
-
|
|
228
|
+
no copy-paste. The saved token is then read automatically (env vars still take precedence).
|
|
229
|
+
The landing JWT lasts ~90 days, so you rarely reconnect.
|
|
248
230
|
|
|
249
231
|
Two URLs, don't mix them up:
|
|
250
232
|
|
|
@@ -270,7 +252,7 @@ For safety, only honor `redirect_uri` values on `http://127.0.0.1:*` / `http://l
|
|
|
270
252
|
flow can also be done entirely in the SPA, no backend route needed.)
|
|
271
253
|
|
|
272
254
|
> Multi-user remote (the claude.ai connector dialog) can't do this browser loopback — there each
|
|
273
|
-
> user sends their own token via the `x-webcake-jwt` header (see the
|
|
255
|
+
> user sends their own token via the `x-webcake-jwt` header (see the hosted-server section above).
|
|
274
256
|
|
|
275
257
|
## Environment Variables
|
|
276
258
|
|
|
@@ -301,15 +283,14 @@ truth for the API + app bases:
|
|
|
301
283
|
| `prod` | `https://api.webcake.io` | `https://webcake.io` |
|
|
302
284
|
|
|
303
285
|
```bash
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
WEBCAKE_ENV=prod
|
|
286
|
+
npx -y webcake-landing-mcp login --env local # connect against your local SPA + API
|
|
287
|
+
WEBCAKE_ENV=staging npx -y webcake-landing-mcp # run against the staging backend
|
|
288
|
+
WEBCAKE_ENV=prod npx -y webcake-landing-mcp # prod (env var form)
|
|
307
289
|
```
|
|
308
290
|
|
|
309
|
-
Explicit `WEBCAKE_API_BASE` / `WEBCAKE_APP_BASE` (or `--api-base`) still override the
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
(e.g. `…/mcp?jwt=<token>&env=staging`) — so one server can serve multiple environments.
|
|
291
|
+
Explicit `WEBCAKE_API_BASE` / `WEBCAKE_APP_BASE` (or `--api-base`) still override the preset, field
|
|
292
|
+
by field. On the hosted server you can override the environment per request with the
|
|
293
|
+
**`x-webcake-env`** header or **`?env=`** query (e.g. `…/mcp?jwt=<token>&env=staging`).
|
|
313
294
|
|
|
314
295
|
### How to get `WEBCAKE_JWT`
|
|
315
296
|
|
|
@@ -330,93 +311,8 @@ cloned-build variants, see **[docs/manual-install.md](docs/manual-install.md#con
|
|
|
330
311
|
|
|
331
312
|
## Usage Examples
|
|
332
313
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
**Prompt:**
|
|
336
|
-
```
|
|
337
|
-
Build me a WebCake landing page for "Acme Coffee" — a hero with a CTA, a 3-feature
|
|
338
|
-
section, and a signup form. Persist it to my default org.
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
**AI agent will automatically:**
|
|
342
|
-
|
|
343
|
-
**Step 1** — Call `get_generation_guide` to learn conventions (canvas, coordinate system, events, workflow)
|
|
344
|
-
|
|
345
|
-
**Step 2** — Call `new_page_skeleton` for an empty top-level source, then `get_element` for each type it uses:
|
|
346
|
-
|
|
347
|
-
```
|
|
348
|
-
get_element({ type: "section" })
|
|
349
|
-
get_element({ type: "text-block" })
|
|
350
|
-
get_element({ type: "button" })
|
|
351
|
-
get_element({ type: "form" })
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
**Step 3** — Assemble the full `{ page, popup, settings, options, cartConfigs }` JSON, then validate:
|
|
355
|
-
|
|
356
|
-
```
|
|
357
|
-
validate_page({ source })
|
|
358
|
-
→ { ok: false, errors: ["BUTTON-2: event target 'POPUP-9' not found"] } # fix every error, re-validate
|
|
359
|
-
validate_page({ source })
|
|
360
|
-
→ { ok: true, errors: [] }
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
**Step 4** — Persist (dry-run first, then for real):
|
|
364
|
-
|
|
365
|
-
```
|
|
366
|
-
list_organizations({}) → pick the org
|
|
367
|
-
create_page({ source }) → dry-run preview (JWT masked)
|
|
368
|
-
create_page({ source, dry_run: false }) → { page_id, editor_url, preview_url }
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
Open the page in the editor and re-save to render `app`/`app_css`.
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
### Example 2: Edit an existing page
|
|
376
|
-
|
|
377
|
-
**Prompt:**
|
|
378
|
-
```
|
|
379
|
-
On my "Acme Coffee" landing page, change the hero headline to "Freshly Roasted Daily"
|
|
380
|
-
and make the CTA button green.
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
**AI agent edits surgically — never regenerates the whole tree:**
|
|
384
|
-
|
|
385
|
-
```
|
|
386
|
-
# Step 1: find the page
|
|
387
|
-
list_pages({})
|
|
388
|
-
→ [{ id: "page_42", name: "Acme Coffee", organization_id: "org_1", ... }]
|
|
389
|
-
|
|
390
|
-
# Step 2: fetch its decoded source tree
|
|
391
|
-
get_page({ page_id: "page_42" })
|
|
392
|
-
|
|
393
|
-
# Step 3: change ONLY the headline text + button color, keep every other id/coordinate,
|
|
394
|
-
# then validate and write back
|
|
395
|
-
validate_page({ source }) → ok
|
|
396
|
-
update_page({ page_id: "page_42", source }) → dry-run preview
|
|
397
|
-
update_page({ page_id: "page_42", source, dry_run: false })
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
---
|
|
401
|
-
|
|
402
|
-
### Example 3: Inspect an element type before using it
|
|
403
|
-
|
|
404
|
-
**Prompt:**
|
|
405
|
-
```
|
|
406
|
-
What specials does a form element need, and show me a valid example.
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
**AI agent calls:**
|
|
410
|
-
|
|
411
|
-
```
|
|
412
|
-
get_element({ type: "form" })
|
|
413
|
-
→ {
|
|
414
|
-
hints: "Each input needs a unique specials.field_name…",
|
|
415
|
-
specials: { ... },
|
|
416
|
-
skeleton: { ... }, # structurally-valid default node
|
|
417
|
-
example: { ... } # filled, realistic example
|
|
418
|
-
}
|
|
419
|
-
```
|
|
314
|
+
Three end-to-end walkthroughs — build a page from a brief, edit one surgically, and inspect
|
|
315
|
+
an element type — live in **[docs/usage-examples.md](docs/usage-examples.md)**.
|
|
420
316
|
|
|
421
317
|
---
|
|
422
318
|
|
package/README.vi.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# <img src="docs/assets/webcake-icon.svg" alt="Webcake" width="26" height="26" align="absmiddle"> WebCake Landing MCP
|
|
2
2
|
|
|
3
3
|
[English](./README.md) · **Tiếng Việt**
|
|
4
4
|
|
|
@@ -59,13 +59,53 @@ lưu lại sẽ render).
|
|
|
59
59
|
|
|
60
60
|
| Cách | Hợp cho | Auth |
|
|
61
61
|
|------|---------|------|
|
|
62
|
-
| **npx (local
|
|
63
|
-
| **
|
|
62
|
+
| **npx (local)** — chạy trên máy bạn | Dùng cá nhân hằng ngày, toàn quyền | browser `login`, JWT, hoặc không cần (tool tham chiếu) |
|
|
63
|
+
| **URL đã host sẵn** — dùng server tụi mình, không cài gì | Máy không có Node.js, dùng nhóm, dialog claude.ai | link `?jwt=` cá nhân / header `x-webcake-jwt` |
|
|
64
64
|
|
|
65
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`).
|
|
66
66
|
|
|
67
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)**.
|
|
68
68
|
|
|
69
|
+
## 🚀 Kết nối — 2 cách chính
|
|
70
|
+
|
|
71
|
+
Chọn **một** trong hai. Cả hai đều đưa toàn bộ bộ công cụ dựng landing Webcake vào AI của bạn (Claude, Cursor, …). Không cần code.
|
|
72
|
+
|
|
73
|
+
### ① `npx` — chạy ngay trên máy bạn (nên dùng cho cá nhân)
|
|
74
|
+
|
|
75
|
+
Không cần cài đặt, luôn bản mới nhất. **Một dòng** vừa lấy token vừa ghi cấu hình IDE:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx -y webcake-landing-mcp install
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Chỉ muốn chạy server (tự cấu hình sau)?
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npx -y webcake-landing-mcp
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
✅ Hợp cho: dùng cá nhân hằng ngày, dev local, toàn quyền kiểm soát. Cần Node.js 18+.
|
|
88
|
+
|
|
89
|
+
### ② URL remote `…/mcp?jwt=` — đã host sẵn, không cần cài gì
|
|
90
|
+
|
|
91
|
+
Dùng server tụi mình đã host. Lấy **link cá nhân của bạn** (token gắn sẵn trong link) rồi dán vào ô *Add custom connector* / file cấu hình của client:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
https://mcp.toolvn.io.vn/mcp?jwt=<TOKEN_CỦA_BẠN>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Hai cách lấy link:
|
|
98
|
+
- **Dễ nhất** — mở **<https://webcake.io/mcp-remote>** trong dashboard Webcake → nó tự tạo & copy link cho bạn.
|
|
99
|
+
- **Thủ công** — xem hướng dẫn từng bước bên dưới.
|
|
100
|
+
|
|
101
|
+
Có thể thêm tham số: `&env=prod`, `&org_id=…`, `&api_base=…`.
|
|
102
|
+
|
|
103
|
+
✅ Hợp cho: máy không có Node.js, dùng nhóm/chia sẻ, và **dialog connector của claude.ai** (chỉ nhập URL, không có header).
|
|
104
|
+
⚠️ Link chứa token cá nhân — coi như mật khẩu, luôn dùng **HTTPS**.
|
|
105
|
+
|
|
106
|
+
> 📖 **Hướng dẫn cấu hình thủ công đầy đủ cho mọi IDE** (Claude Desktop, Claude Code, Cursor, Windsurf, claude.ai…)
|
|
107
|
+
> ở file riêng → **[docs/ket-noi-mcp.md](docs/ket-noi-mcp.md)** · English: **[docs/connect-mcp.md](docs/connect-mcp.md)**.
|
|
108
|
+
|
|
69
109
|
## Cài đặt (npx)
|
|
70
110
|
|
|
71
111
|
Sau khi đã publish lên npm, server chạy thẳng từ registry — không clone, không build:
|
|
@@ -128,34 +168,24 @@ Cấu hình MCP giống bản local, chỉ khác `command`/`args` trỏ tới `n
|
|
|
128
168
|
> npx cache lại package sau lần chạy đầu, nên các lần sau khởi động nhanh. Dùng phiên bản ghim
|
|
129
169
|
> (`webcake-landing-mcp@1.0.0`) nếu cần build tái lập được.
|
|
130
170
|
|
|
131
|
-
##
|
|
171
|
+
## Dùng server đã host sẵn — không cần cài gì
|
|
132
172
|
|
|
133
|
-
Server
|
|
134
|
-
|
|
173
|
+
Server **đã chạy sẵn** tại **`https://mcp.toolvn.io.vn/mcp`** — tụi mình lo hết. Không phải dựng server,
|
|
174
|
+
không phải giữ máy luôn bật. Chỉ cần trỏ AI của bạn vào URL là xong.
|
|
135
175
|
|
|
136
|
-
|
|
176
|
+
**Lấy link cá nhân** (token gắn sẵn) cách dễ nhất → mở **<https://webcake.io/mcp-remote>** rồi bấm **Copy**:
|
|
137
177
|
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
# → endpoint MCP tại http://localhost:8787/mcp (GET / hoặc /health trả JSON trạng thái)
|
|
178
|
+
```
|
|
179
|
+
https://mcp.toolvn.io.vn/mcp?jwt=<TOKEN_CỦA_BẠN>
|
|
141
180
|
```
|
|
142
181
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
- **Name**: `webcake-landing`
|
|
147
|
-
- **Remote MCP server URL**: `https://<host-của-bạn>/mcp`
|
|
148
|
-
|
|
149
|
-
Dialog không có ô header, nên muốn truyền token qua đó thì **để vào URL**:
|
|
150
|
-
`https://<host-của-bạn>/mcp?jwt=<ljwt>` (nhận thêm `&api_base=…`, `&org_id=…`, `&host=…`, `&app_base=…`).
|
|
151
|
-
Mỗi người một URL với `jwt` riêng → **per-user mà không cần OAuth**. Header `x-webcake-jwt` thật vẫn ưu tiên
|
|
152
|
-
hơn query. ⚠️ Token nằm trong URL có thể lọt vào access/proxy log — **bắt buộc HTTPS** và tắt log query ở
|
|
153
|
-
reverse proxy; dùng header (hoặc OAuth) an toàn hơn nếu client hỗ trợ.
|
|
182
|
+
Tham số thêm: `&env=prod`, `&org_id=…`, `&api_base=…`. Mỗi đồng đội một link với `jwt` riêng → mỗi người một
|
|
183
|
+
tài khoản, không cần OAuth. ⚠️ Link chứa token cá nhân — coi như mật khẩu, luôn dùng **HTTPS**.
|
|
154
184
|
|
|
155
|
-
###
|
|
185
|
+
### Gửi token qua header (an toàn hơn)
|
|
156
186
|
|
|
157
|
-
|
|
158
|
-
|
|
187
|
+
Client nào set được header thì nên gửi token qua header thay vì nhét vào URL (token không lọt vào log).
|
|
188
|
+
Header nào thiếu sẽ fallback về biến env tương ứng:
|
|
159
189
|
|
|
160
190
|
| Header | Tương ứng | Ghi chú |
|
|
161
191
|
|--------|-----------|---------|
|
|
@@ -165,60 +195,12 @@ nên server hosted là đa người dùng và không nhúng secret chung:
|
|
|
165
195
|
| `x-webcake-api-base` | `WEBCAKE_API_BASE` | ghi đè API base của preset |
|
|
166
196
|
| `x-webcake-app-base` | `WEBCAKE_APP_BASE` | ghi đè app base của preset |
|
|
167
197
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
>
|
|
173
|
-
>
|
|
174
|
-
>
|
|
175
|
-
> Lưu ý: dialog claude.ai **không có ô header** (chỉ có OAuth, mà server này **chưa làm**). Hai cách lách:
|
|
176
|
-
> để token vào URL dạng `?jwt=<ljwt>` (như trên — per-user, nhưng token lộ trong log), hoặc dùng client hỗ trợ
|
|
177
|
-
> header (`mcp-remote --header …`, bên dưới). Đặt token ở env server thì thành **single-account** chung cho mọi người trên URL đó.
|
|
178
|
-
|
|
179
|
-
### Test ở local (không cần URL public)
|
|
180
|
-
|
|
181
|
-
`localhost` không dùng được trong dialog claude.ai (Anthropic gọi URL từ server của họ). Để thử server `serve`
|
|
182
|
-
chạy trên máy:
|
|
183
|
-
|
|
184
|
-
- **MCP Inspector** (GUI — dễ nhất): `npx @modelcontextprotocol/inspector` → Transport **Streamable HTTP** →
|
|
185
|
-
URL `http://localhost:8787/mcp` → mục Headers thêm `x-webcake-jwt` (+ `x-webcake-api-base`) → Connect → bấm gọi tool.
|
|
186
|
-
- **`mcp-remote`** (dùng server remote từ client stdio như Claude Desktop, kèm header):
|
|
187
|
-
```json
|
|
188
|
-
{ "mcpServers": { "webcake-remote": { "command": "npx",
|
|
189
|
-
"args": ["-y", "mcp-remote", "http://localhost:8787/mcp",
|
|
190
|
-
"--header", "x-webcake-jwt:<ljwt>",
|
|
191
|
-
"--header", "x-webcake-api-base:https://api.webcake.io"] } } }
|
|
192
|
-
```
|
|
193
|
-
- **curl**: `initialize` (đọc header `mcp-session-id` trả về) → `tools/list` → `tools/call`, tất cả kèm
|
|
194
|
-
`Accept: application/json, text/event-stream`.
|
|
195
|
-
|
|
196
|
-
### Deploy lên VPS
|
|
197
|
-
|
|
198
|
-
1. **Build + chạy như service** — `/etc/systemd/system/webcake-mcp.service`:
|
|
199
|
-
```ini
|
|
200
|
-
[Service]
|
|
201
|
-
WorkingDirectory=/opt/webcake-landing-mcp
|
|
202
|
-
ExecStart=/usr/bin/node dist/index.js serve --port 8787
|
|
203
|
-
Environment=WEBCAKE_API_BASE=https://api.webcake.io
|
|
204
|
-
Environment=WEBCAKE_JWT=<ljwt> # chỉ cho single-account — xem ghi chú auth dưới
|
|
205
|
-
Restart=always
|
|
206
|
-
[Install]
|
|
207
|
-
WantedBy=multi-user.target
|
|
208
|
-
```
|
|
209
|
-
`sudo systemctl enable --now webcake-mcp` (build 1 lần: `npm install && npm run build`).
|
|
210
|
-
2. **HTTPS + domain** (claude.ai bắt buộc https) — vd Caddy tự cấp TLS, `/etc/caddy/Caddyfile`:
|
|
211
|
-
```
|
|
212
|
-
mcp.yourdomain.com { reverse_proxy localhost:8787 }
|
|
213
|
-
```
|
|
214
|
-
3. **Thêm vào claude.ai** → Remote MCP server URL = `https://mcp.yourdomain.com/mcp`.
|
|
215
|
-
|
|
216
|
-
**Auth trên server chia sẻ:**
|
|
217
|
-
- **Single-account** (dùng được với dialog ngay): đặt `WEBCAKE_JWT` ở env service → mọi người dùng connector
|
|
218
|
-
chung 1 tài khoản Webcake. Giữ URL riêng tư / có cổng chặn; token hết hạn (~90 ngày).
|
|
219
|
-
- **Per-user** (mỗi người 1 account): cho mỗi người một URL với `?jwt=<ljwt>` riêng (chạy được qua dialog,
|
|
220
|
-
nhưng token lộ trong log), hoặc dùng client hỗ trợ header (`mcp-remote --header …`), hoặc thêm **OAuth**
|
|
221
|
-
(chưa làm) cho gọn nhất.
|
|
198
|
+
> Tool tham chiếu + generation (`get_generation_guide`, `list_elements`, `validate_page`, …) **không cần
|
|
199
|
+
> token** — chỉ tool lưu trữ (`create_page`, `update_page`, …) mới dùng. Không có JWT thì các tool đó trả
|
|
200
|
+
> `missing_env` chứ không gọi mạng.
|
|
201
|
+
|
|
202
|
+
> 📖 **Hướng dẫn từng bước cho mọi IDE** (Claude Desktop, Claude Code, Cursor, Windsurf, claude.ai) →
|
|
203
|
+
> **[docs/ket-noi-mcp.md](docs/ket-noi-mcp.md)** · English: **[docs/connect-mcp.md](docs/connect-mcp.md)**.
|
|
222
204
|
|
|
223
205
|
## Kết nối một lần — tự lấy token (`login`)
|
|
224
206
|
|
|
@@ -239,8 +221,7 @@ Nó mở browser → (đăng nhập Webcake nếu cần) → token được lưu
|
|
|
239
221
|
|
|
240
222
|
Bạn đang đăng nhập Webcake sẵn trong browser, nên `login` chỉ mở trang "connect" của Webcake — trang này
|
|
241
223
|
đọc cookie **`ljwt`** (landing) và trả token về một callback loopback nội bộ — khỏi copy-paste. Token đã lưu
|
|
242
|
-
được
|
|
243
|
-
ngày nên hiếm khi phải kết nối lại.
|
|
224
|
+
sẽ được tự đọc (env vẫn ưu tiên). Landing JWT sống ~90 ngày nên hiếm khi phải kết nối lại.
|
|
244
225
|
|
|
245
226
|
Hai URL, đừng nhầm:
|
|
246
227
|
|
|
@@ -266,7 +247,7 @@ GET /mcp-connect?redirect_uri=<loopback>&state=<s>
|
|
|
266
247
|
SPA cũng được, khỏi cần route backend.)
|
|
267
248
|
|
|
268
249
|
> Remote đa người dùng (dialog claude.ai) không làm được browser loopback này — ở đó mỗi user gửi token riêng
|
|
269
|
-
> qua header `x-webcake-jwt` (xem mục
|
|
250
|
+
> qua header `x-webcake-jwt` (xem mục server đã host sẵn ở trên).
|
|
270
251
|
|
|
271
252
|
## Biến môi trường
|
|
272
253
|
|
|
@@ -297,15 +278,14 @@ cho API + app base (mặc định là `prod`):
|
|
|
297
278
|
| `prod` *(mặc định)* | `https://api.webcake.io` | `https://webcake.io` |
|
|
298
279
|
|
|
299
280
|
```bash
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
WEBCAKE_ENV=prod
|
|
281
|
+
npx -y webcake-landing-mcp login --env local # đăng nhập vào SPA + API local
|
|
282
|
+
WEBCAKE_ENV=staging npx -y webcake-landing-mcp # chạy trỏ backend staging
|
|
283
|
+
WEBCAKE_ENV=prod npx -y webcake-landing-mcp # prod (dạng biến môi trường)
|
|
303
284
|
```
|
|
304
285
|
|
|
305
286
|
`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
|
|
307
|
-
|
|
308
|
-
server phục vụ được nhiều môi trường.
|
|
287
|
+
trường. Trên server đã host sẵn, bạn có thể ghi đè môi trường theo từng request bằng header
|
|
288
|
+
**`x-webcake-env`** hoặc query **`?env=`** (ví dụ `…/mcp?jwt=<token>&env=staging`).
|
|
309
289
|
|
|
310
290
|
### Cách lấy `WEBCAKE_JWT`
|
|
311
291
|
|
|
@@ -324,93 +304,8 @@ Lệnh con `install` của npx (xem trên) tự ghi cấu hình đúng cho từn
|
|
|
324
304
|
|
|
325
305
|
## Ví dụ sử dụng
|
|
326
306
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
**Prompt:**
|
|
330
|
-
```
|
|
331
|
-
Dựng cho tôi một landing page WebCake cho "Acme Coffee" — một hero có CTA, một mục 3 tính năng,
|
|
332
|
-
và một form đăng ký. Lưu vào org mặc định của tôi.
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
**AI sẽ tự động:**
|
|
336
|
-
|
|
337
|
-
**Bước 1** — Gọi `get_generation_guide` để học quy ước (canvas, hệ toạ độ, sự kiện, workflow)
|
|
338
|
-
|
|
339
|
-
**Bước 2** — Gọi `new_page_skeleton` để có source top-level rỗng, rồi `get_element` cho từng loại element nó dùng:
|
|
340
|
-
|
|
341
|
-
```
|
|
342
|
-
get_element({ type: "section" })
|
|
343
|
-
get_element({ type: "text-block" })
|
|
344
|
-
get_element({ type: "button" })
|
|
345
|
-
get_element({ type: "form" })
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
**Bước 3** — Lắp trọn JSON `{ page, popup, settings, options, cartConfigs }`, rồi kiểm tra:
|
|
349
|
-
|
|
350
|
-
```
|
|
351
|
-
validate_page({ source })
|
|
352
|
-
→ { ok: false, errors: ["BUTTON-2: event target 'POPUP-9' not found"] } # sửa hết lỗi, validate lại
|
|
353
|
-
validate_page({ source })
|
|
354
|
-
→ { ok: true, errors: [] }
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
**Bước 4** — Lưu (dry-run trước, rồi mới thật):
|
|
358
|
-
|
|
359
|
-
```
|
|
360
|
-
list_organizations({}) → chọn org
|
|
361
|
-
create_page({ source }) → xem trước dry-run (JWT được che)
|
|
362
|
-
create_page({ source, dry_run: false }) → { page_id, editor_url, preview_url }
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
Mở trang trong editor và lưu lại để render `app`/`app_css`.
|
|
366
|
-
|
|
367
|
-
---
|
|
368
|
-
|
|
369
|
-
### Ví dụ 2: Sửa một trang có sẵn
|
|
370
|
-
|
|
371
|
-
**Prompt:**
|
|
372
|
-
```
|
|
373
|
-
Trên landing page "Acme Coffee" của tôi, đổi headline hero thành "Freshly Roasted Daily"
|
|
374
|
-
và làm nút CTA màu xanh lá.
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
**AI sửa đúng chỗ — không bao giờ dựng lại cả cây:**
|
|
378
|
-
|
|
379
|
-
```
|
|
380
|
-
# Bước 1: tìm trang
|
|
381
|
-
list_pages({})
|
|
382
|
-
→ [{ id: "page_42", name: "Acme Coffee", organization_id: "org_1", ... }]
|
|
383
|
-
|
|
384
|
-
# Bước 2: lấy cây source đã decode
|
|
385
|
-
get_page({ page_id: "page_42" })
|
|
386
|
-
|
|
387
|
-
# Bước 3: chỉ đổi text headline + màu nút, giữ mọi id/toạ độ khác,
|
|
388
|
-
# rồi validate và ghi lại
|
|
389
|
-
validate_page({ source }) → ok
|
|
390
|
-
update_page({ page_id: "page_42", source }) → xem trước dry-run
|
|
391
|
-
update_page({ page_id: "page_42", source, dry_run: false })
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
---
|
|
395
|
-
|
|
396
|
-
### Ví dụ 3: Xem chi tiết một loại element trước khi dùng
|
|
397
|
-
|
|
398
|
-
**Prompt:**
|
|
399
|
-
```
|
|
400
|
-
Một element form cần những specials gì, và cho tôi xem một ví dụ hợp lệ.
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
**AI gọi:**
|
|
404
|
-
|
|
405
|
-
```
|
|
406
|
-
get_element({ type: "form" })
|
|
407
|
-
→ {
|
|
408
|
-
hints: "Mỗi input cần một specials.field_name duy nhất…",
|
|
409
|
-
specials: { ... },
|
|
410
|
-
skeleton: { ... }, # node mặc định hợp lệ về cấu trúc
|
|
411
|
-
example: { ... } # ví dụ đã điền, thực tế
|
|
412
|
-
}
|
|
413
|
-
```
|
|
307
|
+
Ba luồng đầy đủ — dựng trang từ brief, sửa trang đúng chỗ, và xem chi tiết một loại element —
|
|
308
|
+
nằm ở **[docs/usage-examples.vi.md](docs/usage-examples.vi.md)**.
|
|
414
309
|
|
|
415
310
|
---
|
|
416
311
|
|
package/dist/branding.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Brand icon for the MCP server, shared by both transports.
|
|
3
|
+
*
|
|
4
|
+
* Why this exists: an MCP client (e.g. the claude.ai custom-connector UI) shows
|
|
5
|
+
* a generic globe when it can't find an icon for the server. Two mechanisms can
|
|
6
|
+
* supply one, so we feed BOTH from this single source:
|
|
7
|
+
* 1. A favicon served over HTTP (`/favicon.ico` / `/favicon.svg`) — what
|
|
8
|
+
* favicon-style clients fetch from the server's origin.
|
|
9
|
+
* 2. `serverInfo.icons` in the `initialize` result (MCP spec) — a self-contained
|
|
10
|
+
* data URI so it works without the server knowing its own public URL.
|
|
11
|
+
*
|
|
12
|
+
* The mark is the official Webcake logo — the green tile with a white "W"
|
|
13
|
+
* (source: builderx_spa/src/assets/icon/webcake-small.svg).
|
|
14
|
+
*/
|
|
15
|
+
// The official Webcake icon: a Webcake-green (#1DB954) rounded tile with a white
|
|
16
|
+
// "W" letterform. Kept inline (dependency-free) so it can be served raw AND
|
|
17
|
+
// inlined as a data URI. Keep in sync with the SPA's webcake-small.svg.
|
|
18
|
+
export const ICON_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 28 28" fill="none">' +
|
|
19
|
+
'<path d="M2.8285 3.64772C2.8285 3.64772 0.40187 14.238 2.8285 25.0176C2.8285 25.0176 13.5197 27.158 25.2727 25.0176C25.2727 25.0176 27.4716 14.1507 25.2727 3.65595C25.2727 3.64772 16.0217 1.34592 2.8285 3.64772Z" fill="#1DB954"/>' +
|
|
20
|
+
'<path d="M18.5722 19.0697H15.3989L14.4468 14.9073C14.4023 14.7328 14.3309 14.3865 14.2327 13.8684C14.1345 13.3503 14.0632 12.9167 14.0187 12.5677C13.9827 12.8509 13.9228 13.2032 13.8474 13.6231C13.7721 14.0429 13.6762 14.4299 13.6059 14.7756C13.5357 15.1214 13.1967 16.5555 12.6178 19.0565H9.4394L6.97852 9.50684H9.56784L10.6536 14.3064C10.8979 15.3656 11.0657 16.2086 11.1571 16.8354C11.2153 16.3963 11.3203 15.7926 11.4722 15.0242C11.624 14.2559 11.7656 13.6247 11.8969 13.1308L12.7737 9.51671H15.2551L16.1114 13.1308C16.2569 13.7087 16.4042 14.3788 16.5532 15.1362C16.7022 15.8936 16.8032 16.4534 16.8529 16.8354C16.9065 16.3513 17.0664 15.5116 17.3324 14.3162L18.4284 9.51671H21.0177L18.5722 19.0697Z" fill="white"/>' +
|
|
21
|
+
"</svg>";
|
|
22
|
+
export const ICON_MIME = "image/svg+xml";
|
|
23
|
+
// Self-contained data URI for serverInfo.icons (no public URL required).
|
|
24
|
+
export const ICON_DATA_URI = `data:${ICON_MIME};base64,${Buffer.from(ICON_SVG).toString("base64")}`;
|
|
25
|
+
// Public-facing identity reused across the server metadata.
|
|
26
|
+
export const BRAND = {
|
|
27
|
+
title: "Webcake Landing",
|
|
28
|
+
websiteUrl: "https://webcake.io",
|
|
29
|
+
};
|
package/dist/http.js
CHANGED
|
@@ -16,6 +16,7 @@ import { createServer as createHttpServer } from "node:http";
|
|
|
16
16
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
17
17
|
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
18
18
|
import { createServer } from "./server.js";
|
|
19
|
+
import { ICON_SVG, ICON_MIME } from "./branding.js";
|
|
19
20
|
const MCP_PATH = "/mcp";
|
|
20
21
|
function sendJson(res, status, body) {
|
|
21
22
|
res.writeHead(status, { "content-type": "application/json" });
|
|
@@ -65,8 +66,25 @@ export async function startHttpServer(port) {
|
|
|
65
66
|
const transports = new Map();
|
|
66
67
|
const httpServer = createHttpServer(async (req, res) => {
|
|
67
68
|
const path = (req.url ?? "").split("?")[0];
|
|
69
|
+
// Brand icon — clients (e.g. the claude.ai connector) fetch a favicon from the
|
|
70
|
+
// server origin; without one they show a generic globe. Served raw as SVG.
|
|
71
|
+
if (req.method === "GET" && (path === "/favicon.ico" || path === "/favicon.svg" || path === "/icon.svg")) {
|
|
72
|
+
res.writeHead(200, { "content-type": ICON_MIME, "cache-control": "public, max-age=86400" });
|
|
73
|
+
return res.end(ICON_SVG);
|
|
74
|
+
}
|
|
68
75
|
// Lightweight health check for hosting platforms.
|
|
69
76
|
if (req.method === "GET" && (path === "/" || path === "/health")) {
|
|
77
|
+
// A browser/connector probing the root with `Accept: text/html` gets a tiny
|
|
78
|
+
// page that links the favicon (helps icon discovery); programmatic probes
|
|
79
|
+
// (the container healthcheck uses `Accept: */*`) still get the JSON health.
|
|
80
|
+
const accept = String(req.headers["accept"] ?? "");
|
|
81
|
+
if (path === "/" && accept.includes("text/html")) {
|
|
82
|
+
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
83
|
+
return res.end(`<!doctype html><meta charset="utf-8"><title>Webcake Landing MCP</title>` +
|
|
84
|
+
`<link rel="icon" type="${ICON_MIME}" href="/favicon.svg">` +
|
|
85
|
+
`<body style="font-family:system-ui;padding:40px">` +
|
|
86
|
+
`<h2>Webcake Landing MCP</h2><p>Streamable-HTTP MCP server. Endpoint: <code>${MCP_PATH}</code>.</p></body>`);
|
|
87
|
+
}
|
|
70
88
|
return sendJson(res, 200, { ok: true, server: "webcake-landing", transport: "streamable-http", endpoint: MCP_PATH });
|
|
71
89
|
}
|
|
72
90
|
if (path !== MCP_PATH)
|
package/dist/server.js
CHANGED
|
@@ -9,8 +9,17 @@
|
|
|
9
9
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
10
10
|
import { landingDomain } from "./domains/landing/index.js";
|
|
11
11
|
import { registerTools } from "./tools/index.js";
|
|
12
|
+
import { ICON_DATA_URI, ICON_MIME, BRAND } from "./branding.js";
|
|
12
13
|
export function createServer() {
|
|
13
|
-
const server = new McpServer({
|
|
14
|
+
const server = new McpServer({
|
|
15
|
+
name: "webcake-landing",
|
|
16
|
+
version: "1.0.0",
|
|
17
|
+
// Shown by MCP clients (e.g. the claude.ai connector) instead of a generic
|
|
18
|
+
// globe. icons is per the MCP spec; the data URI keeps it self-contained.
|
|
19
|
+
title: BRAND.title,
|
|
20
|
+
websiteUrl: BRAND.websiteUrl,
|
|
21
|
+
icons: [{ src: ICON_DATA_URI, mimeType: ICON_MIME, sizes: ["any"] }],
|
|
22
|
+
}, { instructions: landingDomain.instructions });
|
|
14
23
|
registerTools(server, landingDomain);
|
|
15
24
|
return server;
|
|
16
25
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcake-landing-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
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": {
|