webcake-landing-mcp 1.0.13 → 1.0.14

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.
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Brand icon for the MCP server, shared by both transports.
3
+ *
4
+ * Why this exists: an MCP client (e.g. the claude.ai custom-connector UI) shows
5
+ * a generic globe when it can't find an icon for the server. Two mechanisms can
6
+ * supply one, so we feed BOTH from this single source:
7
+ * 1. A favicon served over HTTP (`/favicon.ico` / `/favicon.svg`) — what
8
+ * favicon-style clients fetch from the server's origin.
9
+ * 2. `serverInfo.icons` in the `initialize` result (MCP spec) — a self-contained
10
+ * data URI so it works without the server knowing its own public URL.
11
+ *
12
+ * The mark is the Webcake green lightning bolt (matches the SPA's McpConnect page).
13
+ */
14
+ // A rounded-square Webcake-green tile with a white lightning bolt. Kept tiny and
15
+ // dependency-free so it can be both served raw and inlined as a data URI.
16
+ export const ICON_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">' +
17
+ '<rect width="32" height="32" rx="7" fill="#14a547"/>' +
18
+ '<path d="M17.5 5 9 17.2h5.6L13 27l9.5-12.2h-5.6L17.5 5Z" fill="#fff"/>' +
19
+ "</svg>";
20
+ export const ICON_MIME = "image/svg+xml";
21
+ // Self-contained data URI for serverInfo.icons (no public URL required).
22
+ export const ICON_DATA_URI = `data:${ICON_MIME};base64,${Buffer.from(ICON_SVG).toString("base64")}`;
23
+ // Public-facing identity reused across the server metadata.
24
+ export const BRAND = {
25
+ title: "Webcake Landing",
26
+ websiteUrl: "https://webcake.io",
27
+ };
package/dist/http.js CHANGED
@@ -16,6 +16,7 @@ import { createServer as createHttpServer } from "node:http";
16
16
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
17
17
  import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
18
18
  import { createServer } from "./server.js";
19
+ import { ICON_SVG, ICON_MIME } from "./branding.js";
19
20
  const MCP_PATH = "/mcp";
20
21
  function sendJson(res, status, body) {
21
22
  res.writeHead(status, { "content-type": "application/json" });
@@ -65,8 +66,25 @@ export async function startHttpServer(port) {
65
66
  const transports = new Map();
66
67
  const httpServer = createHttpServer(async (req, res) => {
67
68
  const path = (req.url ?? "").split("?")[0];
69
+ // Brand icon — clients (e.g. the claude.ai connector) fetch a favicon from the
70
+ // server origin; without one they show a generic globe. Served raw as SVG.
71
+ if (req.method === "GET" && (path === "/favicon.ico" || path === "/favicon.svg" || path === "/icon.svg")) {
72
+ res.writeHead(200, { "content-type": ICON_MIME, "cache-control": "public, max-age=86400" });
73
+ return res.end(ICON_SVG);
74
+ }
68
75
  // Lightweight health check for hosting platforms.
69
76
  if (req.method === "GET" && (path === "/" || path === "/health")) {
77
+ // A browser/connector probing the root with `Accept: text/html` gets a tiny
78
+ // page that links the favicon (helps icon discovery); programmatic probes
79
+ // (the container healthcheck uses `Accept: */*`) still get the JSON health.
80
+ const accept = String(req.headers["accept"] ?? "");
81
+ if (path === "/" && accept.includes("text/html")) {
82
+ res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
83
+ return res.end(`<!doctype html><meta charset="utf-8"><title>Webcake Landing MCP</title>` +
84
+ `<link rel="icon" type="${ICON_MIME}" href="/favicon.svg">` +
85
+ `<body style="font-family:system-ui;padding:40px">` +
86
+ `<h2>Webcake Landing MCP</h2><p>Streamable-HTTP MCP server. Endpoint: <code>${MCP_PATH}</code>.</p></body>`);
87
+ }
70
88
  return sendJson(res, 200, { ok: true, server: "webcake-landing", transport: "streamable-http", endpoint: MCP_PATH });
71
89
  }
72
90
  if (path !== MCP_PATH)
package/dist/server.js CHANGED
@@ -9,8 +9,17 @@
9
9
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
10
  import { landingDomain } from "./domains/landing/index.js";
11
11
  import { registerTools } from "./tools/index.js";
12
+ import { ICON_DATA_URI, ICON_MIME, BRAND } from "./branding.js";
12
13
  export function createServer() {
13
- const server = new McpServer({ name: "webcake-landing", version: "1.0.0" }, { instructions: landingDomain.instructions });
14
+ const server = new McpServer({
15
+ name: "webcake-landing",
16
+ version: "1.0.0",
17
+ // Shown by MCP clients (e.g. the claude.ai connector) instead of a generic
18
+ // globe. icons is per the MCP spec; the data URI keeps it self-contained.
19
+ title: BRAND.title,
20
+ websiteUrl: BRAND.websiteUrl,
21
+ icons: [{ src: ICON_DATA_URI, mimeType: ICON_MIME, sizes: ["any"] }],
22
+ }, { instructions: landingDomain.instructions });
14
23
  registerTools(server, landingDomain);
15
24
  return server;
16
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webcake-landing-mcp",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "MCP server exposing Webcake landing-page element schemas + AI usage hints, and persisting LLM-generated page sources to a Webcake backend.",
5
5
  "type": "module",
6
6
  "bin": {