brewpage-mcp 1.1.1 → 1.2.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 (2) hide show
  1. package/dist/index.js +55 -12
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -229,8 +229,19 @@ server.tool("get_stats", "Get BrewPage platform-wide usage statistics including
229
229
  ],
230
230
  };
231
231
  });
232
- server.tool("publish_site", "Publish a single-page HTML site to BrewPage. Accepts HTML content as the entry file (index.html). For multi-file sites with CSS/JS/images, use the REST API directly. Returns a public URL and owner token.", {
233
- entryContent: z.string().describe("HTML content for the site entry file (index.html)"),
232
+ server.tool("publish_site", "Publish an HTML site to BrewPage. Single-page: pass `entryContent`. Multi-page: pass `files` (array of `{path, content}`). Optional `entry` overrides default `index.html`.", {
233
+ entryContent: z
234
+ .string()
235
+ .optional()
236
+ .describe("HTML content for a single-page site (entry file). Mutually exclusive with `files`."),
237
+ files: z
238
+ .array(z.object({ path: z.string(), content: z.string() }))
239
+ .optional()
240
+ .describe("Multi-file site: array of `{path, content}`. Mutually exclusive with `entryContent`."),
241
+ entry: z
242
+ .string()
243
+ .optional()
244
+ .describe("Entry file path, default index.html"),
234
245
  namespace: z
235
246
  .string()
236
247
  .optional()
@@ -244,26 +255,52 @@ server.tool("publish_site", "Publish a single-page HTML site to BrewPage. Accept
244
255
  .min(1)
245
256
  .max(30)
246
257
  .optional()
247
- .describe("Time to live in days (1-30, default: 5)"),
258
+ .describe("Time to live in days (1-30, default: 15)"),
248
259
  ownerToken: z
249
260
  .string()
250
261
  .optional()
251
262
  .describe("Existing owner token to group this site under the same owner as previous content"),
252
- }, async ({ entryContent, namespace, password, ttlDays, ownerToken }) => {
263
+ }, async ({ entryContent, files, entry, namespace, password, ttlDays, ownerToken }) => {
264
+ const hasEntry = typeof entryContent === "string";
265
+ const hasFiles = Array.isArray(files) && files.length > 0;
266
+ if (hasEntry === hasFiles) {
267
+ return {
268
+ content: [
269
+ {
270
+ type: "text",
271
+ text: "Provide exactly one of `entryContent` (single-page) or `files` (multi-page).",
272
+ },
273
+ ],
274
+ isError: true,
275
+ };
276
+ }
253
277
  const formData = new FormData();
254
- const entryBlob = new Blob([entryContent], { type: "text/html" });
255
- formData.append("files", entryBlob, "index.html");
256
- formData.append("paths", "index.html");
257
- if (namespace)
258
- formData.append("ns", namespace);
259
- if (ttlDays)
260
- formData.append("ttl", String(ttlDays));
278
+ if (hasFiles) {
279
+ for (const f of files) {
280
+ formData.append("files", new Blob([f.content], { type: "text/html" }), f.path);
281
+ formData.append("paths", f.path);
282
+ }
283
+ }
284
+ else {
285
+ const entryBlob = new Blob([entryContent], { type: "text/html" });
286
+ const entryName = entry || "index.html";
287
+ formData.append("files", entryBlob, entryName);
288
+ formData.append("paths", entryName);
289
+ }
261
290
  const headers = {};
262
291
  if (password)
263
292
  headers["X-Password"] = password;
264
293
  if (ownerToken)
265
294
  headers["X-Owner-Token"] = ownerToken;
266
- const url = `${BASE_URL}/api/sites`;
295
+ const qsParams = [];
296
+ if (entry)
297
+ qsParams.push(`entry=${encodeURIComponent(entry)}`);
298
+ if (namespace)
299
+ qsParams.push(`ns=${encodeURIComponent(namespace)}`);
300
+ if (ttlDays)
301
+ qsParams.push(`ttl=${encodeURIComponent(String(ttlDays))}`);
302
+ const qs = qsParams.length ? `?${qsParams.join("&")}` : "";
303
+ const url = `${BASE_URL}/api/sites${qs}`;
267
304
  const res = await fetch(url, { method: "POST", headers, body: formData });
268
305
  const data = await res.json().catch(() => null);
269
306
  if (!res.ok) {
@@ -287,6 +324,12 @@ server.tool("publish_site", "Publish a single-page HTML site to BrewPage. Accept
287
324
  `Entry file: ${site.entryFile || "index.html"}`,
288
325
  `Files: ${site.fileCount || 1}`,
289
326
  ];
327
+ if (site.totalSizeBytes !== undefined)
328
+ lines.push(`Size: ${site.totalSizeBytes} bytes`);
329
+ if (site.ownerLink)
330
+ lines.push(`Owner link: ${site.ownerLink}`);
331
+ if (Array.isArray(site.tags) && site.tags.length)
332
+ lines.push(`Tags: ${site.tags.join(", ")}`);
290
333
  if (site.expiresAt)
291
334
  lines.push(`Expires: ${site.expiresAt}`);
292
335
  lines.push(``, `===================================`, `OWNER TOKEN: ${site.ownerToken}`, `===================================`, ``, `IMPORTANT: Save your owner token! You need it to view info or delete this site. It cannot be recovered if lost.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brewpage-mcp",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for BrewPage — publish and manage HTML, KV, JSON, and file content from AI assistants",
5
5
  "type": "module",
6
6
  "bin": {