brewpage-mcp 1.9.5 → 1.11.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.
Files changed (3) hide show
  1. package/README.md +23 -15
  2. package/dist/index.js +27 -43
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -12,7 +12,7 @@ MCP server for [BrewPage](https://brewpage.app) -- publish and manage HTML, KV,
12
12
  ## Quick Start
13
13
 
14
14
  ```bash
15
- npx -y brewpage-mcp@1.9.5
15
+ npx -y brewpage-mcp@1.11.0
16
16
  ```
17
17
 
18
18
  Requires Node.js 20 or newer. This starts the stdio server for an MCP client.
@@ -28,7 +28,7 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
28
28
  "mcpServers": {
29
29
  "brewpage": {
30
30
  "command": "npx",
31
- "args": ["-y", "brewpage-mcp@1.9.5"]
31
+ "args": ["-y", "brewpage-mcp@1.11.0"]
32
32
  }
33
33
  }
34
34
  }
@@ -39,7 +39,7 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
39
39
  Register a project-scoped stdio server:
40
40
 
41
41
  ```bash
42
- claude mcp add --transport stdio --scope project brewpage -- npx -y brewpage-mcp@1.9.5
42
+ claude mcp add --transport stdio --scope project brewpage -- npx -y brewpage-mcp@1.11.0
43
43
  ```
44
44
 
45
45
  This writes `.mcp.json` in the project root. Use `--scope user` for user-scoped registration. See the [official Claude Code MCP guide](https://code.claude.com/docs/en/mcp).
@@ -53,7 +53,7 @@ Open **Settings > MCP** and add:
53
53
  "mcpServers": {
54
54
  "brewpage": {
55
55
  "command": "npx",
56
- "args": ["-y", "brewpage-mcp@1.9.5"]
56
+ "args": ["-y", "brewpage-mcp@1.11.0"]
57
57
  }
58
58
  }
59
59
  }
@@ -67,7 +67,7 @@ Open the Cline MCP settings panel and add:
67
67
  {
68
68
  "brewpage": {
69
69
  "command": "npx",
70
- "args": ["-y", "brewpage-mcp@1.9.5"]
70
+ "args": ["-y", "brewpage-mcp@1.11.0"]
71
71
  }
72
72
  }
73
73
  ```
@@ -75,7 +75,7 @@ Open the Cline MCP settings panel and add:
75
75
  ### Global Install
76
76
 
77
77
  ```bash
78
- npm install -g brewpage-mcp@1.9.5
78
+ npm install -g brewpage-mcp@1.11.0
79
79
  brewpage-mcp
80
80
  ```
81
81
 
@@ -104,9 +104,9 @@ Sixteen tools are available. Creation returns an owner token; keep it to modify
104
104
 
105
105
  All five publish tools accept optional `deliveryMode: "path" | "subdomain"`, sent only as `X-Delivery-Mode`; authored JSON and multipart bodies keep their existing format. Visibility and password protection are separate choices. Omitted namespace still generates an unlisted `priv-<random>` namespace; anyone with an unpassworded unlisted link can read it. `public` grants gallery/search eligibility only; password-protected content remains excluded and unlisted, protected or otherwise ineligible native responses carry `noindex`; eligible public HTML, sites and files may permit indexing.
106
106
 
107
- The MCP server wraps a subset of the backend-generated public [REST contract](../openapi/openapi.json). Its inputs retain their published behavior: TTL inputs accept 1–30 days (default 15), while backend owner-specific caps and eligible automatic extensions can affect actual expiry. Use returned `expiresAt`. `get_page` reads stored rendered HTML or format-specific code/text from the API; it does not call the owner-only original-source endpoint or a browser viewer. `publish_file` uploads from a source URL and does not expose password or TTL inputs.
107
+ The MCP server wraps a subset of the backend-generated public [REST contract](../openapi/openapi.json). TTL inputs take days or a string such as `2w`/`36h` (default 15); the server rounds to whole days and clamps to 1–30 (owner-specific caps and eligible automatic extensions can differ). Use returned `expiresAt`. Every tolerated-input adjustment (TTL clamp, format alias, skipped site member, normalised namespace) comes back in the response `notices` array and is printed as `Notice (code): message`. `get_page` reads stored rendered HTML or format-specific code/text from the API; it does not call the owner-only original-source endpoint or a browser viewer. `publish_file` uploads from a source URL and does not expose password or TTL inputs.
108
108
 
109
- For a fresh publication, sites and HTML pages of format `HTML` outside `public` (including the generated unlisted namespace) require Dedicated subdomain (`subdomain`); explicit `path` is rejected. Everything else in any namespace (Markdown, code/text, files, JSON, KV, public HTML) defaults to Promotion (`path`) and may choose Dedicated subdomain, including password-protected content. Promotion uses a BrewPage path with stricter active-document restrictions. Each NEW site gets one publication-specific host for its complete bundle, preserving relative/root-relative paths; missing assets return 404, with no SPA fallback. Third-party widgets may still need provider configuration.
109
+ For a fresh publication, sites and HTML pages of format `HTML` outside `public` (including the generated unlisted namespace) always use Dedicated subdomain (`subdomain`); omit `deliveryMode` there. An explicit `path` there is not rejected: the publication is created on its subdomain and the result reports `deliveryModeMatched: false`, `deliveryModeReason: "policy:subdomain-required"` and a `Delivery notice:` line. Everything else in any namespace (Markdown, code/text, files, JSON, KV, public HTML) defaults to Promotion (`path`) and may choose Dedicated subdomain, including password-protected content. Promotion uses a BrewPage path with stricter active-document restrictions. Each NEW site gets one publication-specific host for its complete bundle, preserving relative/root-relative paths; missing assets return 404, with no SPA fallback. Third-party widgets may still need provider configuration.
110
110
 
111
111
  Responses use the server's primary `link` verbatim, including the root slash, and expose `routingCohort`, actual/requested/effective modes, `deliveryModeMatched`, `modeLocked`, `hostingVersion`, access and the trusted-apex `managementLink` when present. Never reconstruct a host from namespace or ID. NEW password links are clean URLs: do not add `?p=`; browser readers unlock through the trusted gateway. Owner tokens and API calls stay on the configured apex API origin.
112
112
 
@@ -118,9 +118,9 @@ When creation returns an existing publication, it keeps its actual URL, cohort a
118
118
 
119
119
  ### `update_hosting`
120
120
 
121
- Change an eligible NEW publication (not a site, not a non-public `html`-format HTML page) between Promotion and Dedicated subdomain. Parameters: `type` (`html` | `file` | `json` | `kv`), `namespace`, `id`, `ownerToken`, `deliveryMode` (`path` | `subdomain`), and `expectedVersion` (current server `hostingVersion`, integer ≥1).
121
+ Change an eligible NEW publication (not a site, not a non-public `html`-format HTML page) between Promotion and Dedicated subdomain. Parameters: `type` (`html` | `file` | `json` | `kv`), `namespace`, `id`, `ownerToken`, `deliveryMode` (`path` | `subdomain`), and optional `expectedVersion` (current server `hostingVersion`, integer ≥1; pass it when known).
122
122
 
123
- The tool sends owner-only `PATCH /api/{html|files|json|kv}/{namespace}/{id}/hosting` with `{deliveryMode, expectedVersion}` and `X-Owner-Token`. OLD links, sites and non-public `html`-format HTML pages are locked. The server returns 403 for invalid owner authority, 400 for locked hosting, and 409 for a stale version; reload current metadata before retrying. A paused real change returns 503. Selecting the current mode returns 200 without incrementing the version. Use the returned primary link after a successful change; the publication host identity is retained through both directions.
123
+ The tool sends owner-only `PATCH /api/{html|files|json|kv}/{namespace}/{id}/hosting` with `{deliveryMode}` plus `expectedVersion` when given, and `X-Owner-Token`. Mismatches are reported, not rejected: a stale or omitted version still applies the choice (a stale one adds `deliveryModeReason: "policy:version-stale"`); sites and non-public `html`-format HTML pages stay on their subdomain (`policy:mode-locked`) and OLD links stay unchanged (`policy:classic-link`), each answered 200 with `deliveryModeMatched: false` and a `Delivery notice:` line. Wrong owner returns 403, a malformed version (not a positive integer) 400, and a paused real change 503. Selecting the current mode returns 200 without incrementing the version. Always use the returned primary link; the publication host identity is retained through both directions.
124
124
 
125
125
  ```text
126
126
  update_hosting(type="html", namespace="public", id="aBcDeFgHiJ", ownerToken="tok_...", deliveryMode="subdomain", expectedVersion=1)
@@ -132,7 +132,7 @@ update_hosting(type="html", namespace="public", id="aBcDeFgHiJ", ownerToken="tok
132
132
 
133
133
  Publish HTML or Markdown content to BrewPage. Returns a public URL and owner token. Markdown raw HTML is rendered through an allowlist: scripts, styles, event handlers, forms, frames/embeds and `meta`/`base`/`link` are removed; links allow `http`, `https`, `mailto`, `tel` and relative URLs, images also `data:`; a lone unknown tag such as `<author>` shows as text.
134
134
 
135
- Parameters: `content` (string), `format` (`HTML` | `MARKDOWN`, default `HTML`), `namespace` (optional -- **omit for unlisted content**; pass `public` only for gallery/search eligibility, except when password-protected), `password` (optional), `ttlDays` (1--30, default 15), `filename` (optional, used as title fallback), `showTopBar` (optional boolean -- adds a toolbar with filename, Download button, and theme toggle), `deliveryMode` (optional).
135
+ Parameters: `content` (string), `format` (default `HTML`; `HTML`, `MARKDOWN` or an alias the server maps, e.g. `md`), `namespace` (optional -- **omit for unlisted content**; pass `public` only for gallery/search eligibility, except when password-protected), `password` (optional), `ttlDays` (days or a string such as `2w`; default 15; the server clamps to 1--30), `filename` (optional, used as title fallback), `showTopBar` (optional boolean -- adds a toolbar with filename, Download button, and theme toggle), `deliveryMode` (optional).
136
136
 
137
137
  The result includes `deliveryModeReason` and a `Delivery notice:` line when the server returns them (see above).
138
138
 
@@ -206,7 +206,7 @@ publish_file(url="https://example.com/diagram.png")
206
206
 
207
207
  Publish a single-page or multi-file HTML site. Pass `entryContent` for a single page or `files` (array of `{path, content}`) for a multi-file site. Supports password protection, TTL, and owner token grouping.
208
208
 
209
- Parameters: exactly one of `entryContent` (string) or non-empty `files` (array of `{path, content}`), `entry` (optional entry file path, default `index.html`), `namespace` (optional -- omit for unlisted content; `public` grants gallery eligibility except when password-protected), `password` (optional), `ttlDays` (1--30, default 15), `ownerToken` (optional, groups site under an existing owner), `deliveryMode` (optional; fresh sites require `subdomain`).
209
+ Parameters: exactly one of `entryContent` (string) or non-empty `files` (array of `{path, content}`), `entry` (optional entry file path, default `index.html`), `namespace` (optional -- omit for unlisted content; `public` grants gallery eligibility except when password-protected), `password` (optional), `ttlDays` (days or a string such as `2w`; default 15; the server clamps to 1--30), `ownerToken` (optional, groups site under an existing owner), `deliveryMode` (optional; fresh sites require `subdomain`).
210
210
 
211
211
  Example prompt:
212
212
 
@@ -222,7 +222,7 @@ publish_site(files=[{"path": "index.html", "content": "..."}, {"path": "style.cs
222
222
 
223
223
  Replace an owned site's complete file set at the same ID and primary link. Files absent from the new bundle are removed; matching files are overwritten and new files added. Hosting stays unchanged.
224
224
 
225
- Parameters: `namespace`, `id`, `ownerToken`, exactly one of `entryContent` or a non-empty `files` array of `{path, content}`, optional `entry` (default `index.html`), `ttlDays` (compatibility input 1--30; existing expiry is preserved), and `tags`.
225
+ Parameters: `namespace`, `id`, `ownerToken`, exactly one of `entryContent` or a non-empty `files` array of `{path, content}`, optional `entry` (default `index.html`), `ttlDays` (ignored; existing expiry is preserved and a `ttl-ignored` notice is returned), and `tags`.
226
226
 
227
227
  ```text
228
228
  republish_site(namespace="public", id="aBcDeFgHiJ", ownerToken="tok_...", files=[{"path":"index.html","content":"<h1>Updated site</h1>"}])
@@ -236,7 +236,7 @@ republish_site(namespace="public", id="aBcDeFgHiJ", ownerToken="tok_...", files=
236
236
 
237
237
  Publish a JSON document to BrewPage. Returns a public URL and owner token. The body may be passed as a JSON string or as a structured object.
238
238
 
239
- Parameters: `json` (string, object, or array), `namespace` (optional -- omit for unlisted content; `public` grants gallery/search eligibility, except when password-protected), `password` (optional), `ttlDays` (1--30, default 15), `tags` (optional `string[]`), `ownerToken` (optional existing owner), `deliveryMode` (optional).
239
+ Parameters: `json` (string, object, or array), `namespace` (optional -- omit for unlisted content; `public` grants gallery/search eligibility, except when password-protected), `password` (optional), `ttlDays` (days or a string such as `2w`; default 15; the server clamps to 1--30), `tags` (optional `string[]`), `ownerToken` (optional existing owner), `deliveryMode` (optional).
240
240
 
241
241
  Example prompt:
242
242
 
@@ -286,7 +286,7 @@ update_json(namespace="public", id="aBcDeFgHiJ", json={"mode": "dark", "version"
286
286
 
287
287
  Create a new KV (key/value) entry. Returns a public URL and owner token. The KV entry is addressed by `(namespace, id, key)`; this tool creates the entry and emits the generated `id` along with the owner token.
288
288
 
289
- Parameters: `key` (string), `value` (string), `namespace` (optional -- omit for unlisted content; `public` grants gallery/search eligibility, except when password-protected), `password` (optional), `ttlDays` (1--30, default 15), `tags` (optional `string[]`), `ownerToken` (optional existing owner), `deliveryMode` (optional).
289
+ Parameters: `key` (string), `value` (string), `namespace` (optional -- omit for unlisted content; `public` grants gallery/search eligibility, except when password-protected), `password` (optional), `ttlDays` (days or a string such as `2w`; default 15; the server clamps to 1--30), `tags` (optional `string[]`), `ownerToken` (optional existing owner), `deliveryMode` (optional).
290
290
 
291
291
  Example prompt:
292
292
 
@@ -433,6 +433,14 @@ Every publish response includes an **owner token** -- the only credential that a
433
433
 
434
434
  ## Changelog
435
435
 
436
+ ## 1.11.0 -- 2026-10-21
437
+
438
+ - Every publish/update tool prints server `notices` as `Notice (code): message` lines. `ttlDays` takes a positive number or a string such as `2w`; the server rounds and clamps instead of the client rejecting values above 30. `publish_html` `format` accepts any string; the server maps aliases. `republish_site` TTL is ignored with a `ttl-ignored` notice. Same sixteen tools.
439
+
440
+ ## 1.10.0 -- 2026-10-21
441
+
442
+ - `update_hosting`: `expectedVersion` is optional; a stale version, a locked mode or an OLD link answers with a successful result plus `deliveryModeReason` and a `Delivery notice:` line instead of an error. A publish request for `path` where `subdomain` is required succeeds on the subdomain and prints the notice. Same sixteen tools.
443
+
436
444
  ## 1.9.5 -- 2026-10-21
437
445
 
438
446
  - `deliveryMode`, `publish_html` and `update_hosting` describe the backend 1.117.0 delivery rule: sites and non-public HTML-format pages require `subdomain`; Markdown, code/text, files, JSON and KV default to `path` in any namespace. `publish_html` notes that Markdown raw HTML is allowlist-sanitized.
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { z } from "zod";
5
5
  const BASE_URL = process.env.BREWPAGE_URL || "https://brewpage.app";
6
6
  const server = new McpServer({
7
7
  name: "brewpage-mcp",
8
- version: "1.9.5",
8
+ version: "1.11.0",
9
9
  });
10
10
  const PUBLIC_NAMESPACE = "public";
11
11
  /**
@@ -36,8 +36,10 @@ const NAMESPACE_DESCRIPTION = "Optional. Omit to generate an unlisted namespace:
36
36
  "but it is excluded from gallery/search. Pass a custom namespace to group unlisted content, " +
37
37
  "or pass `public` ONLY when the user explicitly wants gallery/search eligibility. " +
38
38
  "Password-protected content stays excluded; unlisted, protected or otherwise ineligible native responses carry noindex; eligible public HTML, sites and files may permit indexing.";
39
+ const TTL_SCHEMA = z.union([z.number().positive(), z.string().min(1).max(32)]).optional().describe("Requested TTL: days as a number, or a string such as '2w', '36h' or '1 month' (default 15 days). " +
40
+ "The server rounds to whole days and clamps to the allowed range (1-30 by default; owner caps differ), reporting each adjustment in notices; use returned expiresAt.");
39
41
  const DELIVERY_MODE_SCHEMA = z.enum(["path", "subdomain"]).optional().describe("Optional delivery choice for a fresh publication, independent of password/namespace. " +
40
- "Fresh sites and HTML-format pages outside public (including the default unlisted namespace) require subdomain; explicit path there is rejected. " +
42
+ "Fresh sites and HTML-format pages outside public (including the default unlisted namespace) always use subdomain; an explicit path there still publishes, on subdomain, with a delivery notice. " +
41
43
  "Everything else in any namespace (Markdown, code/text, files, JSON, KV, public HTML) defaults to path (Promotion); public HTML may automatically choose subdomain for browser features. " +
42
44
  "When creation returns an existing publication, it keeps its actual mode and URL.");
43
45
  function hostingResponseLines(data) {
@@ -47,11 +49,20 @@ function hostingResponseLines(data) {
47
49
  if (data.routingCohort === "old")
48
50
  lines.push("Hosting: Existing link");
49
51
  if (data.deliveryModeMatched === false)
50
- lines.push("Requested hosting differs from the existing publication; its URL and mode were preserved.");
52
+ lines.push("Requested hosting differs from the effective mode; use the returned URL.");
51
53
  lines.push(...deliveryReasonLines(data));
54
+ lines.push(...noticeLines(data));
52
55
  return lines;
53
56
  }
54
- /** Optional HTML create/update fields: why the delivery mode was chosen or flagged. */
57
+ /** Server `notices` ({code, message}) on publish/update responses: each tolerated-input adjustment, verbatim. */
58
+ function noticeLines(data) {
59
+ if (!Array.isArray(data.notices))
60
+ return [];
61
+ return data.notices
62
+ .filter((n) => typeof n === "object" && n !== null && typeof n.code === "string" && typeof n.message === "string")
63
+ .map((n) => `Notice (${n.code}): ${n.message}`);
64
+ }
65
+ /** Optional delivery fields on HTML and hosting responses: why the mode was chosen, flagged or not applied. */
55
66
  function deliveryReasonLines(data) {
56
67
  const { deliveryModeReason: reason, deliveryNotice: notice } = data;
57
68
  const lines = [];
@@ -115,9 +126,10 @@ server.tool("publish_html", "Publish HTML or Markdown content to BrewPage (repos
115
126
  content: z.string().describe("HTML or Markdown content to publish"),
116
127
  deliveryMode: DELIVERY_MODE_SCHEMA,
117
128
  format: z
118
- .enum(["HTML", "MARKDOWN"])
129
+ .string()
130
+ .min(1)
119
131
  .default("HTML")
120
- .describe("Content format: HTML or MARKDOWN"),
132
+ .describe("Content format, default HTML. HTML or MARKDOWN; the server also maps aliases (md, text/markdown, file extensions, code languages) and detects unknown values from content, reporting the change in notices."),
121
133
  namespace: z
122
134
  .string()
123
135
  .optional()
@@ -126,13 +138,7 @@ server.tool("publish_html", "Publish HTML or Markdown content to BrewPage (repos
126
138
  .string()
127
139
  .optional()
128
140
  .describe("Optional password to protect the page"),
129
- ttlDays: z
130
- .number()
131
- .int()
132
- .min(1)
133
- .max(30)
134
- .optional()
135
- .describe("Requested TTL in days (1-30, default 15). Backend owner caps and eligible automatic extensions can affect expiry; use returned expiresAt."),
141
+ ttlDays: TTL_SCHEMA,
136
142
  filename: z
137
143
  .string()
138
144
  .max(200)
@@ -229,13 +235,13 @@ server.tool("publish_file", "Upload a file to BrewPage via URL. Repository defau
229
235
  ],
230
236
  };
231
237
  });
232
- server.tool("update_hosting", "Change delivery mode for a NEW publication (not a site, not a non-public HTML-format page). Requires owner token and current hostingVersion. OLD links and forced subdomain modes are locked; reload after a 409 conflict. Content updates never change hosting.", {
233
- type: z.enum(["html", "file", "json", "kv"]).describe("Resource type; sites have no hosting-choice endpoint"),
234
- namespace: z.string().describe("Resource namespace; non-public HTML-format pages are locked"),
238
+ server.tool("update_hosting", "Change delivery mode for a NEW publication (not a site, not a non-public HTML-format page). Requires owner token; pass the current hostingVersion when known. Mismatches are reported, not rejected: a stale version still applies, and OLD links or forced subdomain modes stay unchanged; the result then carries a delivery notice. Content updates never change hosting.", {
239
+ type: z.enum(["html", "file", "json", "kv"]).describe("Resource type; sites always stay on their own subdomain"),
240
+ namespace: z.string().describe("Resource namespace; non-public HTML-format pages stay on subdomain"),
235
241
  id: z.string().describe("Resource ID"),
236
242
  ownerToken: z.string().describe("Original resource owner token"),
237
243
  deliveryMode: z.enum(["path", "subdomain"]).describe("path = Promotion; subdomain = Dedicated subdomain"),
238
- expectedVersion: z.number().int().min(1).max(Number.MAX_SAFE_INTEGER).describe("Current hostingVersion from the server; required for concurrency control"),
244
+ expectedVersion: z.number().int().min(1).max(Number.MAX_SAFE_INTEGER).optional().describe("Optional current hostingVersion from the server; a stale value still applies and the result says so"),
239
245
  }, async ({ type, namespace, id, ownerToken, deliveryMode, expectedVersion }) => {
240
246
  const segment = type === "file" ? "files" : type;
241
247
  const path = `/api/${segment}/${encodeURIComponent(namespace)}/${encodeURIComponent(id)}/hosting`;
@@ -382,12 +388,7 @@ server.tool("publish_site", "Publish an HTML site to BrewPage. Single-page: pass
382
388
  .string()
383
389
  .optional()
384
390
  .describe("Optional password to protect the site"),
385
- ttlDays: z
386
- .number()
387
- .min(1)
388
- .max(30)
389
- .optional()
390
- .describe("Requested TTL in days (1-30, default 15). Backend owner caps and eligible automatic extensions can affect expiry; use returned expiresAt."),
391
+ ttlDays: TTL_SCHEMA,
391
392
  ownerToken: z
392
393
  .string()
393
394
  .optional()
@@ -494,12 +495,7 @@ server.tool("republish_site", "Republish (full-replace) an existing multi-file B
494
495
  .string()
495
496
  .optional()
496
497
  .describe("Entry file path, default index.html"),
497
- ttlDays: z
498
- .number()
499
- .min(1)
500
- .max(30)
501
- .optional()
502
- .describe("Compatibility input (1-30); site republishing preserves existing expiry. Use returned expiresAt."),
498
+ ttlDays: TTL_SCHEMA.describe("Ignored: republishing keeps the existing expiry; a supplied value comes back as a ttl-ignored notice."),
503
499
  tags: z
504
500
  .array(z.string())
505
501
  .optional()
@@ -634,13 +630,7 @@ server.tool("publish_json", "Publish a JSON document to BrewPage (repository def
634
630
  .string()
635
631
  .optional()
636
632
  .describe("Optional password to protect the document"),
637
- ttlDays: z
638
- .number()
639
- .int()
640
- .min(1)
641
- .max(30)
642
- .optional()
643
- .describe("Requested TTL in days (1-30, default 15). Backend owner caps and eligible automatic extensions can affect expiry; use returned expiresAt."),
633
+ ttlDays: TTL_SCHEMA,
644
634
  tags: z
645
635
  .array(z.string())
646
636
  .optional()
@@ -780,13 +770,7 @@ server.tool("publish_kv", "Publish a key/value entry to BrewPage. Creates a KV s
780
770
  .string()
781
771
  .optional()
782
772
  .describe("Optional password to protect the KV store"),
783
- ttlDays: z
784
- .number()
785
- .int()
786
- .min(1)
787
- .max(30)
788
- .optional()
789
- .describe("Requested TTL in days (1-30, default 15). Backend owner caps and eligible automatic extensions can affect expiry; use returned expiresAt."),
773
+ ttlDays: TTL_SCHEMA,
790
774
  tags: z
791
775
  .array(z.string())
792
776
  .optional()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brewpage-mcp",
3
- "version": "1.9.5",
3
+ "version": "1.11.0",
4
4
  "mcpName": "io.github.kochetkov-ma/brewpage-mcp",
5
5
  "description": "MCP server for BrewPage — publish and manage HTML, sites, KV, JSON and files from AI assistants",
6
6
  "type": "module",