brewpage-mcp 1.0.0 → 1.1.1
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/index.js +66 -1
- package/package.json +1 -1
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.
|
|
8
|
+
version: "1.1.1",
|
|
9
9
|
});
|
|
10
10
|
async function apiRequest(method, path, body, headers) {
|
|
11
11
|
const url = `${BASE_URL}${path}`;
|
|
@@ -229,6 +229,71 @@ 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)"),
|
|
234
|
+
namespace: z
|
|
235
|
+
.string()
|
|
236
|
+
.optional()
|
|
237
|
+
.describe("Namespace for the site (optional, defaults to 'public')"),
|
|
238
|
+
password: z
|
|
239
|
+
.string()
|
|
240
|
+
.optional()
|
|
241
|
+
.describe("Optional password to protect the site"),
|
|
242
|
+
ttlDays: z
|
|
243
|
+
.number()
|
|
244
|
+
.min(1)
|
|
245
|
+
.max(30)
|
|
246
|
+
.optional()
|
|
247
|
+
.describe("Time to live in days (1-30, default: 5)"),
|
|
248
|
+
ownerToken: z
|
|
249
|
+
.string()
|
|
250
|
+
.optional()
|
|
251
|
+
.describe("Existing owner token to group this site under the same owner as previous content"),
|
|
252
|
+
}, async ({ entryContent, namespace, password, ttlDays, ownerToken }) => {
|
|
253
|
+
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));
|
|
261
|
+
const headers = {};
|
|
262
|
+
if (password)
|
|
263
|
+
headers["X-Password"] = password;
|
|
264
|
+
if (ownerToken)
|
|
265
|
+
headers["X-Owner-Token"] = ownerToken;
|
|
266
|
+
const url = `${BASE_URL}/api/sites`;
|
|
267
|
+
const res = await fetch(url, { method: "POST", headers, body: formData });
|
|
268
|
+
const data = await res.json().catch(() => null);
|
|
269
|
+
if (!res.ok) {
|
|
270
|
+
return {
|
|
271
|
+
content: [
|
|
272
|
+
{
|
|
273
|
+
type: "text",
|
|
274
|
+
text: `Failed to publish site: ${JSON.stringify(data)}`,
|
|
275
|
+
},
|
|
276
|
+
],
|
|
277
|
+
isError: true,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
const site = data;
|
|
281
|
+
const lines = [
|
|
282
|
+
`Site published successfully!`,
|
|
283
|
+
``,
|
|
284
|
+
`URL: ${site.link || "N/A"}`,
|
|
285
|
+
`Namespace: ${site.namespace || "N/A"}`,
|
|
286
|
+
`ID: ${site.id || "N/A"}`,
|
|
287
|
+
`Entry file: ${site.entryFile || "index.html"}`,
|
|
288
|
+
`Files: ${site.fileCount || 1}`,
|
|
289
|
+
];
|
|
290
|
+
if (site.expiresAt)
|
|
291
|
+
lines.push(`Expires: ${site.expiresAt}`);
|
|
292
|
+
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.`);
|
|
293
|
+
return {
|
|
294
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
295
|
+
};
|
|
296
|
+
});
|
|
232
297
|
async function main() {
|
|
233
298
|
const transport = new StdioServerTransport();
|
|
234
299
|
await server.connect(transport);
|