webcake-storefront-mcp 1.31.13 → 1.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/changelog.json +14 -14
- package/dist/http.js +9 -2
- package/dist/icon.png +0 -0
- package/dist/server.js +9 -1
- package/dist/tools/registry.js +23 -5
- package/dist/web-guide.js +3 -0
- package/package.json +1 -1
package/dist/changelog.json
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"v": "1.33.0",
|
|
4
|
+
"d": "14/10/2026",
|
|
5
|
+
"type": "Added",
|
|
6
|
+
"en": "Every tool, whether registered natively or reached through the search gateway (search_tools/invoke_tool/list_tool_groups), now reports readOnlyHint…",
|
|
7
|
+
"vi": "Mọi tool, dù được đăng ký native hay được tiếp cận qua search gateway (search_tools/invoke_tool/list_tool_groups), nay đều có thêm annotation…"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"v": "1.32.0",
|
|
11
|
+
"d": "14/10/2026",
|
|
12
|
+
"type": "Changed",
|
|
13
|
+
"en": "The server now serves a raster PNG icon (/favicon.ico, /favicon.png, /icon.png, /apple-touch-icon.png) alongside the existing SVG favicon, and…",
|
|
14
|
+
"vi": "Server nay phục vụ thêm icon dạng raster PNG (/favicon.ico, /favicon.png, /icon.png, /apple-touch-icon.png) bên cạnh favicon SVG hiện có, và khai…"
|
|
15
|
+
},
|
|
2
16
|
{
|
|
3
17
|
"v": "1.31.13",
|
|
4
18
|
"d": "09/10/2026",
|
|
@@ -26,19 +40,5 @@
|
|
|
26
40
|
"type": "Added",
|
|
27
41
|
"en": "list_articles accepts a term parameter to search articles by title or slug, and its response now includes page and limit alongside total.",
|
|
28
42
|
"vi": "list_articles nay nhận thêm tham số term để tìm bài viết theo tiêu đề hoặc slug, và kết quả trả về nay có thêm page và limit bên cạnh total."
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
"v": "1.31.9",
|
|
32
|
-
"d": "07/09/2026",
|
|
33
|
-
"type": "Added",
|
|
34
|
-
"en": "Pages created by create_page, build_page, and commit_page_draft are now stamped with by_ai: \"mcp\" (persisted to the backend pages.by_ai column) so…",
|
|
35
|
-
"vi": "Các trang được tạo bởi create_page, build_page và commit_page_draft nay được đánh dấu by_ai: \"mcp\" (lưu vào cột pages.by_ai ở backend) để builder có…"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"v": "1.31.8",
|
|
39
|
-
"d": "29/06/2026",
|
|
40
|
-
"type": "Fixed",
|
|
41
|
-
"en": "Elements placed by new_section, new_row, and build_page that fill their grid cell (text, image, container, columns, repeaters) now receive…",
|
|
42
|
-
"vi": "Các phần tử được đặt bởi new_section, new_row và build_page mà lấp đầy ô lưới (text, image, container, columns, repeaters) nay nhận constraintX:…"
|
|
43
43
|
}
|
|
44
44
|
]
|
package/dist/http.js
CHANGED
|
@@ -11,7 +11,7 @@ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/
|
|
|
11
11
|
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
12
12
|
import { createServer } from "./server.js";
|
|
13
13
|
import { makeApi, resolveEnv, ENVIRONMENTS, DEFAULT_ENV } from "./config.js";
|
|
14
|
-
import { landingHtml, faviconSvg, ogImageSvg, normalizeLang } from "./web-guide.js";
|
|
14
|
+
import { landingHtml, faviconSvg, ogImageSvg, normalizeLang, ICON_PNG } from "./web-guide.js";
|
|
15
15
|
import { privacyHtml, termsHtml } from "./legal.js";
|
|
16
16
|
import { registerClient, startAuthorize, completeAuthorize, exchangeToken, resolveAccessToken, revokeToken, authServerMetadata, protectedResourceMetadata, } from "./auth/oauth-server.js";
|
|
17
17
|
const MCP_PATH = "/mcp";
|
|
@@ -291,7 +291,14 @@ export async function startHttpServer(port) {
|
|
|
291
291
|
const httpServer = createHttpServer(async (req, res) => {
|
|
292
292
|
const path = (req.url ?? "").split("?")[0];
|
|
293
293
|
// ---- Favicon / brand icon ----
|
|
294
|
-
|
|
294
|
+
// Google s2 (what the claude.ai connector list uses) skips SVG favicons and shows a
|
|
295
|
+
// globe, so /favicon.ico and friends serve the raster src/icon.png (→ dist/icon.png).
|
|
296
|
+
if ((req.method === "GET" || req.method === "HEAD") && ["/favicon.ico", "/favicon.png", "/icon.png", "/apple-touch-icon.png"].includes(path)) {
|
|
297
|
+
res.writeHead(200, { "content-type": "image/png", "cache-control": "public, max-age=86400" });
|
|
298
|
+
res.end(ICON_PNG);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (req.method === "GET" && path === "/favicon.svg") {
|
|
295
302
|
res.writeHead(200, { "content-type": "image/svg+xml", "cache-control": "public, max-age=86400" });
|
|
296
303
|
res.end(faviconSvg());
|
|
297
304
|
return;
|
package/dist/icon.png
ADDED
|
Binary file
|
package/dist/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { installTools, buildToolGroupIndex } from "./tools/registry.js";
|
|
4
|
+
import { ICON_PNG } from "./web-guide.js";
|
|
4
5
|
/** Server version, read from package.json so it always tracks the published release. */
|
|
5
6
|
export const SERVER_VERSION = (() => {
|
|
6
7
|
try {
|
|
@@ -36,7 +37,14 @@ function makeResult(data) {
|
|
|
36
37
|
/** Build a fully-wired MCP server bound to the given API client. */
|
|
37
38
|
export function createServer(api, opts = {}) {
|
|
38
39
|
const toolsSpec = opts.tools ?? process.env.WEBCAKE_TOOLS;
|
|
39
|
-
const server = new McpServer({
|
|
40
|
+
const server = new McpServer({
|
|
41
|
+
name: "webcake-storefront",
|
|
42
|
+
version: SERVER_VERSION,
|
|
43
|
+
// Shown by MCP clients (e.g. claude.ai connectors) instead of a generic globe.
|
|
44
|
+
title: "WebCake Storefront",
|
|
45
|
+
websiteUrl: "https://webcake.io",
|
|
46
|
+
icons: [{ src: `data:image/png;base64,${ICON_PNG.toString("base64")}`, mimeType: "image/png", sizes: ["192x192"] }],
|
|
47
|
+
}, { instructions: `${INSTRUCTIONS}\n\n${buildToolGroupIndex(toolsSpec)}` });
|
|
40
48
|
const handle = async (fn) => {
|
|
41
49
|
try {
|
|
42
50
|
return makeResult(await fn());
|
package/dist/tools/registry.js
CHANGED
|
@@ -49,6 +49,7 @@ export const GROUPS = [
|
|
|
49
49
|
{ name: "apps_advanced", title: "Advanced apps", desc: "Product design, personal product design (PPD), course app" },
|
|
50
50
|
{ name: "channels", title: "Sale channels", desc: "Sitemap sync, partner product feeds, Google merchants" },
|
|
51
51
|
{ name: "automation", title: "Automation", desc: "Marketing automations and send-mail" },
|
|
52
|
+
{ name: "image_seo", title: "Image alt / SEO audit", desc: "Scan site images, read them, bulk-fill and set alt text" },
|
|
52
53
|
];
|
|
53
54
|
/** Each tool module mapped to its group. Order matches the original registration order. */
|
|
54
55
|
const MODULES = [
|
|
@@ -80,7 +81,7 @@ const MODULES = [
|
|
|
80
81
|
["web", registerGlobalSectionTools],
|
|
81
82
|
["web", registerGlobalSectionWriteTools],
|
|
82
83
|
["session", registerResultCacheTools],
|
|
83
|
-
["
|
|
84
|
+
["image_seo", registerImageTools],
|
|
84
85
|
["web", registerBuilderTools],
|
|
85
86
|
["web", registerBuilderExtraTools],
|
|
86
87
|
["web", registerPageDraftTools],
|
|
@@ -119,6 +120,21 @@ export function resolveNativeGroups(spec) {
|
|
|
119
120
|
}
|
|
120
121
|
return set;
|
|
121
122
|
}
|
|
123
|
+
/** MCP tool annotations derived from the verb prefix, so clients can auto-allow read-only
|
|
124
|
+
* tools and warn on destructive ones. Unlisted verbs (update/upsert/set/publish…) keep the
|
|
125
|
+
* spec defaults (a non-read-only tool is assumed possibly destructive). */
|
|
126
|
+
const READ_ONLY = /^(list|get|search|read|query|find|count|semantic|check|validate|scan|fetch|new|ingest)_/;
|
|
127
|
+
const DESTRUCTIVE = /^(delete|remove|uninstall|empty|clear|block|unblock|refuse)_/;
|
|
128
|
+
const ADDITIVE = /^(create|add|upload|install|invite|duplicate|save)_/;
|
|
129
|
+
export function toolAnnotations(name) {
|
|
130
|
+
if (READ_ONLY.test(name))
|
|
131
|
+
return { readOnlyHint: true };
|
|
132
|
+
if (DESTRUCTIVE.test(name))
|
|
133
|
+
return { readOnlyHint: false, destructiveHint: true };
|
|
134
|
+
if (ADDITIVE.test(name))
|
|
135
|
+
return { readOnlyHint: false, destructiveHint: false };
|
|
136
|
+
return { readOnlyHint: false };
|
|
137
|
+
}
|
|
122
138
|
const errorResult = (text) => ({ content: [{ type: "text", text }], isError: true });
|
|
123
139
|
/** Build a compact capability index (group list with loaded/on-demand tags) to inject into the
|
|
124
140
|
* system prompt so the model always knows which domains exist and when to use search_tools. */
|
|
@@ -150,7 +166,7 @@ export function installTools(server, api, handle, opts = {}) {
|
|
|
150
166
|
let nativeCount = 0;
|
|
151
167
|
for (const e of collector.entries) {
|
|
152
168
|
if (native.has(e.group)) {
|
|
153
|
-
server.tool(e.name, e.description, e.shape, e.handler);
|
|
169
|
+
server.tool(e.name, e.description, e.shape, toolAnnotations(e.name), e.handler);
|
|
154
170
|
nativeCount++;
|
|
155
171
|
}
|
|
156
172
|
}
|
|
@@ -167,7 +183,7 @@ export function installTools(server, api, handle, opts = {}) {
|
|
|
167
183
|
}
|
|
168
184
|
return schemaCache.get(e.name);
|
|
169
185
|
};
|
|
170
|
-
server.tool("list_tool_groups", "List every WebCake tool group, how many tools it has, and whether it is loaded natively or reached on-demand via search_tools + invoke_tool.", {}, () => handle(async () => GROUPS.map((g) => ({
|
|
186
|
+
server.tool("list_tool_groups", "List every WebCake tool group, how many tools it has, and whether it is loaded natively or reached on-demand via search_tools + invoke_tool.", {}, toolAnnotations("list_tool_groups"), () => handle(async () => GROUPS.map((g) => ({
|
|
171
187
|
name: g.name,
|
|
172
188
|
title: g.title,
|
|
173
189
|
description: g.desc,
|
|
@@ -180,7 +196,7 @@ courses, sale channels, automation…). Returns name, group, description and JSO
|
|
|
180
196
|
query: z.string().describe("Keywords, e.g. 'affiliate payout', 'translate product', 'add domain ssl', 'block phone'"),
|
|
181
197
|
group: z.string().optional().describe("Restrict to a group name (see list_tool_groups)"),
|
|
182
198
|
limit: z.number().optional().describe("Max results (default 8)"),
|
|
183
|
-
}, ({ query, group, limit }) => handle(async () => {
|
|
199
|
+
}, toolAnnotations("search_tools"), ({ query, group, limit }) => handle(async () => {
|
|
184
200
|
const ql = query.toLowerCase();
|
|
185
201
|
const terms = ql.split(/\s+/).filter(Boolean);
|
|
186
202
|
const PREFIX_MIN = 4;
|
|
@@ -230,6 +246,7 @@ courses, sale channels, automation…). Returns name, group, description and JSO
|
|
|
230
246
|
name: e.name,
|
|
231
247
|
group: e.group,
|
|
232
248
|
native: native.has(e.group),
|
|
249
|
+
annotations: toolAnnotations(e.name),
|
|
233
250
|
description: e.description,
|
|
234
251
|
input_schema: jsonSchema(e),
|
|
235
252
|
}));
|
|
@@ -238,7 +255,8 @@ courses, sale channels, automation…). Returns name, group, description and JSO
|
|
|
238
255
|
Arguments are validated before running. Use this for tools that are not loaded natively.`, {
|
|
239
256
|
name: z.string().describe("Exact tool name (from search_tools)"),
|
|
240
257
|
arguments: z.record(z.any()).optional().describe("Arguments object matching the tool's input schema"),
|
|
241
|
-
},
|
|
258
|
+
}, toolAnnotations("invoke_tool"), // runs any tool, so never read-only
|
|
259
|
+
async ({ name, arguments: args }) => {
|
|
242
260
|
const e = registry.get(name);
|
|
243
261
|
if (!e)
|
|
244
262
|
return errorResult(`Error: unknown tool "${name}". Use search_tools to find available tools.`);
|
package/dist/web-guide.js
CHANGED
|
@@ -564,6 +564,7 @@ export function guideHtml(origin, lang = "vi") {
|
|
|
564
564
|
<link rel="alternate" hreflang="vi" href="${origin}/">
|
|
565
565
|
<link rel="alternate" hreflang="en" href="${origin}/?lang=en">
|
|
566
566
|
<link rel="alternate" hreflang="x-default" href="${origin}/">
|
|
567
|
+
<link rel="icon" type="image/png" sizes="192x192" href="/favicon.png">
|
|
567
568
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
568
569
|
<meta property="og:type" content="website">
|
|
569
570
|
<meta property="og:site_name" content="WebCake Storefront MCP">
|
|
@@ -1032,6 +1033,8 @@ export function ogImageSvg() {
|
|
|
1032
1033
|
* Favicon SVG — the branded "S" mark with yellow dot.
|
|
1033
1034
|
* Served at /favicon.svg and /favicon.ico by http.ts.
|
|
1034
1035
|
*/
|
|
1036
|
+
// Raster icon (192px, generated from ICON_SVG) — shared by /favicon.ico and serverInfo.icons.
|
|
1037
|
+
export const ICON_PNG = readFileSync(new URL("./icon.png", import.meta.url));
|
|
1035
1038
|
export function faviconSvg() {
|
|
1036
1039
|
return ICON_SVG;
|
|
1037
1040
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webcake-storefront-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.33.0",
|
|
4
4
|
"description": "MCP server for the WebCake/StoreCake storefront builder — page CRUD, page authoring, products, orders, and more",
|
|
5
5
|
"mcpName": "io.github.vuluu2k/webcake-storefront-mcp",
|
|
6
6
|
"license": "MIT",
|