webcake-storefront-mcp 1.32.0 → 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.
@@ -1,4 +1,11 @@
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
+ },
2
9
  {
3
10
  "v": "1.32.0",
4
11
  "d": "14/10/2026",
@@ -33,12 +40,5 @@
33
40
  "type": "Added",
34
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.",
35
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."
36
- },
37
- {
38
- "v": "1.31.9",
39
- "d": "07/09/2026",
40
- "type": "Added",
41
- "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…",
42
- "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ó…"
43
43
  }
44
44
  ]
@@ -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
- ["web", registerImageTools],
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
- }, async ({ name, arguments: args }) => {
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webcake-storefront-mcp",
3
- "version": "1.32.0",
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",