sitezen-mcp 1.0.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.
- package/README.md +107 -0
- package/dist/conversion-log.js +67 -0
- package/dist/conversion-rules.md +1361 -0
- package/dist/errors.js +37 -0
- package/dist/figma.js +1369 -0
- package/dist/index.js +37 -0
- package/dist/license.js +121 -0
- package/dist/normalize.js +692 -0
- package/dist/state.js +81 -0
- package/dist/tools-session.js +131 -0
- package/dist/tools.js +1378 -0
- package/dist/validate.js +114 -0
- package/dist/wp-client.js +130 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# SiteZen MCP
|
|
2
|
+
|
|
3
|
+
An MCP server that lets **Claude Desktop** (or any MCP client) drive a SiteZen-enabled WordPress site directly — no Vercel platform, no API key burning on your end, full editor v2 (Style Studio) compatibility.
|
|
4
|
+
|
|
5
|
+
## Why this exists
|
|
6
|
+
|
|
7
|
+
The SiteZen platform conversion engine works, but it lives behind Vercel's 60-second function limit. On Hobby tier, complex Figma sections time out. The MCP path solves that completely:
|
|
8
|
+
|
|
9
|
+
- **No Vercel** → no 60s timeout
|
|
10
|
+
- **No platform API key** → the user's Claude subscription pays for tokens, not yours
|
|
11
|
+
- **Same plugin, same editor** → all the v2 Style Studio panels work on output from this MCP exactly as they do on platform-generated output
|
|
12
|
+
- **Faster iteration** → Claude generates HTML in chat, pushes to WP via tools, user sees result instantly
|
|
13
|
+
|
|
14
|
+
The MCP is a **thin set of hands** — Claude is the brain (it generates the HTML); the MCP just gives Claude the verbs to ship that HTML to WordPress.
|
|
15
|
+
|
|
16
|
+
## Tools (12 total)
|
|
17
|
+
|
|
18
|
+
| Tool | What it does |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `check_config` | Verify connection to the WP site. **Always call first.** |
|
|
21
|
+
| `list_pages` | List all WP pages with id, title, slug, URL. |
|
|
22
|
+
| `list_templates` | List existing SiteZen templates. |
|
|
23
|
+
| `create_page` | Create a new WP page wrapping HTML as a SiteZen Section. |
|
|
24
|
+
| `push_section_to_page` | Append or replace a section on an existing page. |
|
|
25
|
+
| `get_page_html` | Read the current HTML of a page (for editing). |
|
|
26
|
+
| `create_header_footer` | Create a site-wide header or footer template. |
|
|
27
|
+
| `create_template` | Create any other template type (archive, single-post, listing). |
|
|
28
|
+
| `set_site_branding` | Set primary color, accent color, fonts, logo URL. |
|
|
29
|
+
| `get_site_globals` | Read current brand defaults. |
|
|
30
|
+
| `detect_section_kind` | Dry-run the SiteZen detector to see what specialized blocks the editor will recognize. |
|
|
31
|
+
| `editor_v2_capabilities` | Read-only manifest of Style Studio panels — informs Claude how to author HTML for best post-push editability. |
|
|
32
|
+
|
|
33
|
+
## Install
|
|
34
|
+
|
|
35
|
+
### Prerequisites
|
|
36
|
+
|
|
37
|
+
- Node.js 18 or newer
|
|
38
|
+
- A WordPress site with the SiteZen plugin installed and activated
|
|
39
|
+
- The site's **Connection Key** from WP Admin → SiteZen → Connection
|
|
40
|
+
|
|
41
|
+
### Local build
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
cd sitezen-mcp
|
|
45
|
+
npm install
|
|
46
|
+
npm run build
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This produces `dist/index.js` — that's the MCP server binary.
|
|
50
|
+
|
|
51
|
+
### Wire to Claude Desktop
|
|
52
|
+
|
|
53
|
+
See [INSTALL.md](./INSTALL.md) for the exact JSON snippet to add to your Claude Desktop config.
|
|
54
|
+
|
|
55
|
+
## Typical workflow
|
|
56
|
+
|
|
57
|
+
1. Open Claude Desktop with this MCP server connected
|
|
58
|
+
2. Say: *"Check my SiteZen connection."* → Claude calls `check_config`
|
|
59
|
+
3. Say: *"Look at this Figma design [paste URL + screenshot] and build a hero section for my homepage. Match my site's brand."* → Claude calls `get_site_globals`, generates HTML, calls `create_page` with the result
|
|
60
|
+
4. Open the returned `edit_url` in your browser → edit in WP with the v2 Style Studio panels
|
|
61
|
+
5. Say: *"Now add a pricing section below the hero."* → Claude calls `push_section_to_page` with new HTML
|
|
62
|
+
|
|
63
|
+
No platform conversion, no Vercel timeout, no Anthropic API spend on your side — your end user's Claude subscription covers the LLM cost.
|
|
64
|
+
|
|
65
|
+
## Architecture
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
Claude Desktop
|
|
69
|
+
│
|
|
70
|
+
│ MCP protocol over stdio
|
|
71
|
+
▼
|
|
72
|
+
sitezen-mcp (this server)
|
|
73
|
+
│
|
|
74
|
+
│ HTTPS + X-SiteZen-Key
|
|
75
|
+
▼
|
|
76
|
+
WordPress site / SiteZen plugin REST API
|
|
77
|
+
│
|
|
78
|
+
│ wp_insert_post / wp_update_post / etc.
|
|
79
|
+
▼
|
|
80
|
+
WordPress database
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The MCP server is stateless — every tool call reads the env-var config, hits the plugin REST endpoint, returns the result. No local DB, no cache, no background work.
|
|
84
|
+
|
|
85
|
+
## Editor v2 compatibility
|
|
86
|
+
|
|
87
|
+
Everything pushed through this MCP becomes a SiteZen Section block in WP. That block is rendered by the v2 editor JS (in `plugin-v2/assets/js/editor.js`) which gives the user 13+ collapsible Style Studio panels: Layers, Tag, Image, Spacing per-side, Border, Border Radius, Background (with gradient palette), Effects (shadow + opacity + filter), Layout, Size, Flex, Transform (with quick presets), Hover State (writes per-element :hover rules), Alignment & Text Style, Classes.
|
|
88
|
+
|
|
89
|
+
The MCP doesn't apply edits itself — it just pushes HTML, and the editor wraps that HTML in the v2 editing UX automatically. To get the most editing power, have Claude:
|
|
90
|
+
|
|
91
|
+
- Wrap text in semantic tags (h1/h2/h3, not div) → Tag panel can swap freely
|
|
92
|
+
- Add `data-sz-id="hero-cta"` on important elements → Layers panel labels them readably
|
|
93
|
+
- Use inline styles → per-element panels (Spacing, Border, etc.) edit them directly
|
|
94
|
+
- Skip linking external stylesheets that may not exist on the target site
|
|
95
|
+
|
|
96
|
+
The `editor_v2_capabilities` tool returns the full panel manifest plus authoring tips Claude can reference.
|
|
97
|
+
|
|
98
|
+
## When to use this vs the platform
|
|
99
|
+
|
|
100
|
+
| Use the MCP | Use the platform |
|
|
101
|
+
|---|---|
|
|
102
|
+
| Solo / agency workflow with you in the loop | Self-serve, no operator in the chat |
|
|
103
|
+
| You're testing / iterating on Figma → WP | Bulk conversion runs you don't want to babysit |
|
|
104
|
+
| You want to avoid Vercel costs while validating | You've validated and have funding for Pro |
|
|
105
|
+
| Complex sections that time out on Hobby | Simple sections under 60s |
|
|
106
|
+
|
|
107
|
+
Both produce HTML that's edited by the same plugin — pick the input path that fits the situation.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Conversion logging — every successful push is recorded so we can later
|
|
2
|
+
// analyse what designs users convert (popular section types, common failure
|
|
3
|
+
// modes, common Figma file shapes, etc.).
|
|
4
|
+
//
|
|
5
|
+
// Storage today: append-only JSON Lines file at ~/.sitezen/conversions.jsonl
|
|
6
|
+
// — one line per conversion, easy to grep / pipe into anything. Persists
|
|
7
|
+
// across Claude Desktop restarts.
|
|
8
|
+
//
|
|
9
|
+
// Once sitezen.app is live, the same record is ALSO POSTed to
|
|
10
|
+
// /api/license/log_conversion so the dashboard can show stats. The local
|
|
11
|
+
// file stays as the source-of-truth + offline buffer (network failures
|
|
12
|
+
// never lose a record).
|
|
13
|
+
//
|
|
14
|
+
// Per the product decision, we capture "maximum" data: timestamp, license
|
|
15
|
+
// key fingerprint, site URL, Figma URL, page name + id, section type if
|
|
16
|
+
// known, success/fail, error code if failed, full generated HTML.
|
|
17
|
+
import * as fs from "node:fs";
|
|
18
|
+
import * as path from "node:path";
|
|
19
|
+
import * as os from "node:os";
|
|
20
|
+
import * as crypto from "node:crypto";
|
|
21
|
+
const STATE_DIR = path.join(os.homedir(), ".sitezen");
|
|
22
|
+
const LOG_FILE = path.join(STATE_DIR, "conversions.jsonl");
|
|
23
|
+
function fingerprint(licenseKey) {
|
|
24
|
+
if (!licenseKey)
|
|
25
|
+
return "anonymous";
|
|
26
|
+
return crypto.createHash("sha256")
|
|
27
|
+
.update(licenseKey.trim())
|
|
28
|
+
.digest("hex")
|
|
29
|
+
.slice(-8);
|
|
30
|
+
}
|
|
31
|
+
export function logConversion(rec) {
|
|
32
|
+
try {
|
|
33
|
+
if (!fs.existsSync(STATE_DIR)) {
|
|
34
|
+
fs.mkdirSync(STATE_DIR, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
const full = {
|
|
37
|
+
ts: new Date().toISOString(),
|
|
38
|
+
license_fingerprint: fingerprint(rec.license_key || process.env.SITEZEN_LICENSE_KEY),
|
|
39
|
+
site_url: rec.site_url,
|
|
40
|
+
page_name: rec.page_name,
|
|
41
|
+
page_id: rec.page_id,
|
|
42
|
+
figma_url: rec.figma_url,
|
|
43
|
+
section_type: rec.section_type,
|
|
44
|
+
section_bbox: rec.section_bbox,
|
|
45
|
+
success: rec.success,
|
|
46
|
+
error_code: rec.error_code,
|
|
47
|
+
html: rec.html,
|
|
48
|
+
detection: rec.detection,
|
|
49
|
+
};
|
|
50
|
+
fs.appendFileSync(LOG_FILE, JSON.stringify(full) + "\n", "utf8");
|
|
51
|
+
// Fire-and-forget POST to dashboard when available — never blocks
|
|
52
|
+
// the conversion result. Failures are silent; the .jsonl file keeps
|
|
53
|
+
// the authoritative record either way.
|
|
54
|
+
if (process.env.SITEZEN_LICENSE_API_URL) {
|
|
55
|
+
const url = process.env.SITEZEN_LICENSE_API_URL.replace(/\/+$/, "") + "/log_conversion";
|
|
56
|
+
fetch(url, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: { "Content-Type": "application/json" },
|
|
59
|
+
body: JSON.stringify(full),
|
|
60
|
+
}).catch(() => { });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Logging must never break a conversion. Swallow all errors.
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export const LOG_FILE_PATH_FOR_DISPLAY = LOG_FILE;
|