@explainui/mcp 0.1.0-beta.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/README.md +101 -0
- package/dist/capture.d.ts +21 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +116 -0
- package/dist/capture.js.map +1 -0
- package/dist/client.d.ts +29 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +78 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +15 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +134 -0
- package/dist/index.js.map +1 -0
- package/dist/tools.d.ts +43 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +245 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +101 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# @explainui/mcp
|
|
2
|
+
|
|
3
|
+
Silent UX QA in your AI agent workflow. This MCP server captures screenshots at multiple viewports and runs GPT-4o analysis against your project's UX constraints — all without leaving your editor.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @explainui/mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Chromium is installed automatically via Playwright during `postinstall`.
|
|
12
|
+
|
|
13
|
+
## Quick Setup
|
|
14
|
+
|
|
15
|
+
### Claude Desktop
|
|
16
|
+
|
|
17
|
+
Add to your `claude_desktop_config.json`:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"explainui": {
|
|
23
|
+
"command": "explainui-mcp",
|
|
24
|
+
"env": {
|
|
25
|
+
"EXPLAINUI_LICENSE_KEY": "ek_live_your_key_here"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Cursor / Windsurf / Cline
|
|
33
|
+
|
|
34
|
+
Consult your editor's MCP configuration docs and add `explainui-mcp` as a stdio server with the environment variable below.
|
|
35
|
+
|
|
36
|
+
## Environment Variables
|
|
37
|
+
|
|
38
|
+
| Variable | Required | Default | Description |
|
|
39
|
+
|---|---|---|---|
|
|
40
|
+
| `EXPLAINUI_LICENSE_KEY` | **Yes** | — | Your license key from [explainui.com/settings](https://explainui.com/settings) |
|
|
41
|
+
| `EXPLAINUI_API_HOST` | No | `https://api.explainui.com` | API base URL (override for self-hosted) |
|
|
42
|
+
|
|
43
|
+
## Tools
|
|
44
|
+
|
|
45
|
+
The server exposes three MCP tools:
|
|
46
|
+
|
|
47
|
+
### `explainui_attach_project`
|
|
48
|
+
|
|
49
|
+
Load your project configuration. **Call this first** before any analysis.
|
|
50
|
+
|
|
51
|
+
| Parameter | Type | Required | Description |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| `project_id` | string | Yes | `proj_xxxxxxxx` from your dashboard |
|
|
54
|
+
|
|
55
|
+
### `explainui_analyze`
|
|
56
|
+
|
|
57
|
+
Run a UX QA check. Captures screenshots at 3 viewports (desktop 1280×800, tablet 768×1024, mobile 375×812) with scroll positions, then sends to GPT-4o for analysis.
|
|
58
|
+
|
|
59
|
+
| Parameter | Type | Required | Description |
|
|
60
|
+
|---|---|---|---|
|
|
61
|
+
| `project_id` | string | Yes | Project ID from attach step |
|
|
62
|
+
| `page_key` | string | Yes | Page to check (e.g. `homepage`, `pricing`) |
|
|
63
|
+
| `iteration` | integer | Yes | Iteration count (1–10), increment after each call |
|
|
64
|
+
| `this_iteration` | string | Yes | What was built/changed (40–500 chars) |
|
|
65
|
+
| `git_snapshot_hash` | string | No | Short SHA from pre-analysis commit |
|
|
66
|
+
|
|
67
|
+
**Returns:** Pass/fail verdict, per-check results, issues with severity and fix suggestions.
|
|
68
|
+
|
|
69
|
+
### `explainui_close_project`
|
|
70
|
+
|
|
71
|
+
End the session. Releases browser resources and clears cached config.
|
|
72
|
+
|
|
73
|
+
| Parameter | Type | Required | Description |
|
|
74
|
+
|---|---|---|---|
|
|
75
|
+
| `project_id` | string | Yes | Same project from attach step |
|
|
76
|
+
| `reason` | enum | Yes | `all_pages_done` · `session_end` · `user_request` · `permanent_error` |
|
|
77
|
+
|
|
78
|
+
## Typical Workflow
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
1. explainui_attach_project → load project config
|
|
82
|
+
2. (write code / make changes)
|
|
83
|
+
3. explainui_analyze → capture + GPT-4o analysis
|
|
84
|
+
4. (fix any issues found)
|
|
85
|
+
5. explainui_analyze → re-check (iteration 2)
|
|
86
|
+
6. explainui_close_project → cleanup
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Development
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
cd packages/explainui_mcp
|
|
93
|
+
npm install
|
|
94
|
+
npm run build # TypeScript → dist/
|
|
95
|
+
npm test # Vitest
|
|
96
|
+
npm run dev # Watch mode
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplainUI MCP — Playwright Screenshot Capture
|
|
3
|
+
* Launches headless Chromium, captures screenshots at all viewports.
|
|
4
|
+
*
|
|
5
|
+
* Browser lifecycle:
|
|
6
|
+
* - Lazy launch on first capture (saves ~400MB idle RAM)
|
|
7
|
+
* - Reused across all analyze calls in a session
|
|
8
|
+
* - Auto-relaunches if browser disconnects
|
|
9
|
+
* - Clean shutdown on SIGINT/SIGTERM
|
|
10
|
+
*/
|
|
11
|
+
import { type CaptureResult } from "./types.js";
|
|
12
|
+
/**
|
|
13
|
+
* Capture screenshots at all configured viewports for a given URL.
|
|
14
|
+
* Returns base64-encoded JPEG screenshots with labels.
|
|
15
|
+
*/
|
|
16
|
+
export declare function captureAllViewports(url: string): Promise<CaptureResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Clean shutdown of the browser instance.
|
|
19
|
+
*/
|
|
20
|
+
export declare function closeBrowser(): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAA8B,KAAK,aAAa,EAAkB,MAAM,YAAY,CAAC;AAmB5F;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAmF7E;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAKlD"}
|
package/dist/capture.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplainUI MCP — Playwright Screenshot Capture
|
|
3
|
+
* Launches headless Chromium, captures screenshots at all viewports.
|
|
4
|
+
*
|
|
5
|
+
* Browser lifecycle:
|
|
6
|
+
* - Lazy launch on first capture (saves ~400MB idle RAM)
|
|
7
|
+
* - Reused across all analyze calls in a session
|
|
8
|
+
* - Auto-relaunches if browser disconnects
|
|
9
|
+
* - Clean shutdown on SIGINT/SIGTERM
|
|
10
|
+
*/
|
|
11
|
+
import { chromium } from "playwright";
|
|
12
|
+
import { VIEWPORTS, ExplainUIError } from "./types.js";
|
|
13
|
+
let browser = null;
|
|
14
|
+
async function getBrowser() {
|
|
15
|
+
if (!browser || !browser.isConnected()) {
|
|
16
|
+
browser = await chromium.launch({
|
|
17
|
+
headless: true,
|
|
18
|
+
args: [
|
|
19
|
+
"--no-sandbox",
|
|
20
|
+
"--disable-setuid-sandbox",
|
|
21
|
+
"--disable-dev-shm-usage",
|
|
22
|
+
"--disable-gpu",
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return browser;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Capture screenshots at all configured viewports for a given URL.
|
|
30
|
+
* Returns base64-encoded JPEG screenshots with labels.
|
|
31
|
+
*/
|
|
32
|
+
export async function captureAllViewports(url) {
|
|
33
|
+
const startTime = Date.now();
|
|
34
|
+
const b = await getBrowser();
|
|
35
|
+
const context = await b.newContext({
|
|
36
|
+
ignoreHTTPSErrors: true,
|
|
37
|
+
userAgent: "ExplainUI/1.0 (UX QA Agent)",
|
|
38
|
+
viewport: { width: 1280, height: 800 },
|
|
39
|
+
});
|
|
40
|
+
const page = await context.newPage();
|
|
41
|
+
try {
|
|
42
|
+
await page.goto(url, { waitUntil: "networkidle", timeout: 15_000 });
|
|
43
|
+
const screenshots = [];
|
|
44
|
+
for (const vp of VIEWPORTS) {
|
|
45
|
+
await page.setViewportSize({ width: vp.width, height: vp.height });
|
|
46
|
+
await page.waitForTimeout(300); // let layout reflow settle
|
|
47
|
+
const pageHeight = await page.evaluate(() => document.body.scrollHeight);
|
|
48
|
+
const scrollStep = vp.height;
|
|
49
|
+
const maxScrolls = Math.min(vp.scrolls, Math.ceil(pageHeight / scrollStep));
|
|
50
|
+
for (let i = 0; i < maxScrolls; i++) {
|
|
51
|
+
const scrollY = i * scrollStep;
|
|
52
|
+
await page.evaluate((y) => window.scrollTo(0, y), scrollY);
|
|
53
|
+
await page.waitForTimeout(150); // let lazy images load
|
|
54
|
+
let bytes = await page.screenshot({
|
|
55
|
+
type: "jpeg",
|
|
56
|
+
quality: 70,
|
|
57
|
+
clip: { x: 0, y: 0, width: vp.width, height: vp.height },
|
|
58
|
+
});
|
|
59
|
+
// Size guard: if screenshot > 5MB, reduce quality
|
|
60
|
+
if (bytes.length > 5 * 1024 * 1024) {
|
|
61
|
+
bytes = await page.screenshot({
|
|
62
|
+
type: "jpeg",
|
|
63
|
+
quality: 50,
|
|
64
|
+
clip: { x: 0, y: 0, width: vp.width, height: vp.height },
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
screenshots.push({
|
|
68
|
+
label: `${vp.label}_scroll_${i}`,
|
|
69
|
+
viewport: vp.label,
|
|
70
|
+
scroll_index: i,
|
|
71
|
+
data: bytes.toString("base64"),
|
|
72
|
+
});
|
|
73
|
+
// Break if we've scrolled past the page content
|
|
74
|
+
const currentY = await page.evaluate(() => window.scrollY);
|
|
75
|
+
const maxY = await page.evaluate(() => document.body.scrollHeight - window.innerHeight);
|
|
76
|
+
if (currentY >= maxY)
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
screenshots,
|
|
82
|
+
capture_duration_ms: Date.now() - startTime,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
const message = err.message || "";
|
|
87
|
+
if (message.includes("ERR_CONNECTION_REFUSED")) {
|
|
88
|
+
throw new ExplainUIError("LOCAL_SERVER_NOT_RUNNING", `Could not connect to ${url}. Is your dev server running?`);
|
|
89
|
+
}
|
|
90
|
+
if (message.includes("Timeout")) {
|
|
91
|
+
throw new ExplainUIError("CAPTURE_TIMEOUT", `Page at ${url} took too long to load (>15s).`);
|
|
92
|
+
}
|
|
93
|
+
throw err;
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
await page.close();
|
|
97
|
+
await context.close();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Clean shutdown of the browser instance.
|
|
102
|
+
*/
|
|
103
|
+
export async function closeBrowser() {
|
|
104
|
+
if (browser) {
|
|
105
|
+
await browser.close();
|
|
106
|
+
browser = null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Graceful shutdown on process exit
|
|
110
|
+
process.on("SIGINT", () => {
|
|
111
|
+
browser?.close().then(() => process.exit(0));
|
|
112
|
+
});
|
|
113
|
+
process.on("SIGTERM", () => {
|
|
114
|
+
browser?.close().then(() => process.exit(0));
|
|
115
|
+
});
|
|
116
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplainUI MCP — API Client
|
|
3
|
+
* Axios-based client for talking to the ExplainUI API.
|
|
4
|
+
*/
|
|
5
|
+
import type { Config } from "./config.js";
|
|
6
|
+
import type { AnalyzeRequest, AnalyzeResponse, ProjectConfig, VersionInfo } from "./types.js";
|
|
7
|
+
export declare class ApiClient {
|
|
8
|
+
private client;
|
|
9
|
+
private licenseKey;
|
|
10
|
+
private mcpVersion;
|
|
11
|
+
constructor(config: Config);
|
|
12
|
+
/**
|
|
13
|
+
* GET /v2/version — check API compatibility.
|
|
14
|
+
*/
|
|
15
|
+
checkVersion(): Promise<VersionInfo>;
|
|
16
|
+
/**
|
|
17
|
+
* GET /v2/projects/{id}/config — fetch project config (license key auth).
|
|
18
|
+
*/
|
|
19
|
+
getProjectConfig(projectId: string): Promise<ProjectConfig>;
|
|
20
|
+
/**
|
|
21
|
+
* POST /v2/agent/analyze — run UX QA analysis.
|
|
22
|
+
*/
|
|
23
|
+
analyze(req: AnalyzeRequest): Promise<AnalyzeResponse>;
|
|
24
|
+
/**
|
|
25
|
+
* Health check — GET /health
|
|
26
|
+
*/
|
|
27
|
+
healthCheck(): Promise<boolean>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,aAAa,EACb,WAAW,EAEZ,MAAM,YAAY,CAAC;AAGpB,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,EAAE,MAAM;IAa1B;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,WAAW,CAAC;IAK1C;;OAEG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAyBjE;;OAEG;IACG,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAY5D;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAQtC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplainUI MCP — API Client
|
|
3
|
+
* Axios-based client for talking to the ExplainUI API.
|
|
4
|
+
*/
|
|
5
|
+
import axios from "axios";
|
|
6
|
+
import { ExplainUIError } from "./types.js";
|
|
7
|
+
export class ApiClient {
|
|
8
|
+
client;
|
|
9
|
+
licenseKey;
|
|
10
|
+
mcpVersion;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.licenseKey = config.licenseKey;
|
|
13
|
+
this.mcpVersion = config.mcpVersion;
|
|
14
|
+
this.client = axios.create({
|
|
15
|
+
baseURL: config.apiHost,
|
|
16
|
+
timeout: 60_000, // 60s — GPT calls can take a while
|
|
17
|
+
headers: {
|
|
18
|
+
"Content-Type": "application/json",
|
|
19
|
+
"User-Agent": `ExplainUI-MCP/${config.mcpVersion}`,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* GET /v2/version — check API compatibility.
|
|
25
|
+
*/
|
|
26
|
+
async checkVersion() {
|
|
27
|
+
const resp = await this.client.get("/v2/version");
|
|
28
|
+
return resp.data;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* GET /v2/projects/{id}/config — fetch project config (license key auth).
|
|
32
|
+
*/
|
|
33
|
+
async getProjectConfig(projectId) {
|
|
34
|
+
const resp = await this.client.get(`/v2/projects/${projectId}/config`, {
|
|
35
|
+
headers: { "X-License-Key": this.licenseKey },
|
|
36
|
+
});
|
|
37
|
+
const data = resp.data;
|
|
38
|
+
if (data.error) {
|
|
39
|
+
throw new ExplainUIError(data.error.code || "API_ERROR", data.error.message || "Failed to fetch project config");
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
project_id: data.project_id,
|
|
43
|
+
name: data.name,
|
|
44
|
+
pages: data.pages || [],
|
|
45
|
+
constraint_bundle: data.constraint_bundle || {
|
|
46
|
+
user_goal: "",
|
|
47
|
+
user_enforced_constraints: [],
|
|
48
|
+
do_not_flag: [],
|
|
49
|
+
},
|
|
50
|
+
trigger_threshold: data.trigger_threshold || "major_features",
|
|
51
|
+
fetched_at: Date.now(),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* POST /v2/agent/analyze — run UX QA analysis.
|
|
56
|
+
*/
|
|
57
|
+
async analyze(req) {
|
|
58
|
+
const resp = await this.client.post("/v2/agent/analyze", {
|
|
59
|
+
...req,
|
|
60
|
+
license_key: this.licenseKey,
|
|
61
|
+
mcp_version: this.mcpVersion,
|
|
62
|
+
});
|
|
63
|
+
return resp.data;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Health check — GET /health
|
|
67
|
+
*/
|
|
68
|
+
async healthCheck() {
|
|
69
|
+
try {
|
|
70
|
+
const resp = await this.client.get("/health", { timeout: 5000 });
|
|
71
|
+
return resp.data?.status === "ok";
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA6B,MAAM,OAAO,CAAC;AASlD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,OAAO,SAAS;IACZ,MAAM,CAAgB;IACtB,UAAU,CAAS;IACnB,UAAU,CAAS;IAE3B,YAAY,MAAc;QACxB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QACpC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YACzB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,OAAO,EAAE,MAAM,EAAE,mCAAmC;YACpD,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,YAAY,EAAE,iBAAiB,MAAM,CAAC,UAAU,EAAE;aACnD;SACF,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAc,aAAa,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,SAAiB;QACtC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,gBAAgB,SAAS,SAAS,EAAE;YACrE,OAAO,EAAE,EAAE,eAAe,EAAE,IAAI,CAAC,UAAU,EAAE;SAC9C,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,cAAc,CACtB,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,WAAW,EAC9B,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,gCAAgC,CACvD,CAAC;QACJ,CAAC;QACD,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,EAAE;YACvB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,IAAI;gBAC3C,SAAS,EAAE,EAAE;gBACb,yBAAyB,EAAE,EAAE;gBAC7B,WAAW,EAAE,EAAE;aAChB;YACD,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,IAAI,gBAAgB;YAC7D,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;SACvB,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO,CAAC,GAAmB;QAC/B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CACjC,mBAAmB,EACnB;YACE,GAAG,GAAG;YACN,WAAW,EAAE,IAAI,CAAC,UAAU;YAC5B,WAAW,EAAE,IAAI,CAAC,UAAU;SAC7B,CACF,CAAC;QACF,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW;QACf,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACjE,OAAO,IAAI,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplainUI MCP — Configuration
|
|
3
|
+
* Reads environment variables for API host, license key, etc.
|
|
4
|
+
*/
|
|
5
|
+
export interface Config {
|
|
6
|
+
apiHost: string;
|
|
7
|
+
licenseKey: string;
|
|
8
|
+
mcpVersion: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function loadConfig(): Config;
|
|
11
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,MAAM;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,UAAU,IAAI,MAAM,CAcnC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplainUI MCP — Configuration
|
|
3
|
+
* Reads environment variables for API host, license key, etc.
|
|
4
|
+
*/
|
|
5
|
+
export function loadConfig() {
|
|
6
|
+
const apiHost = process.env.EXPLAINUI_API_HOST || "https://api.explainui.com";
|
|
7
|
+
const licenseKey = process.env.EXPLAINUI_LICENSE_KEY || "";
|
|
8
|
+
const mcpVersion = "0.1.0";
|
|
9
|
+
if (!licenseKey) {
|
|
10
|
+
console.error("[ExplainUI] EXPLAINUI_LICENSE_KEY is not set. " +
|
|
11
|
+
"Get your key at https://explainui.com/settings");
|
|
12
|
+
}
|
|
13
|
+
return { apiHost, licenseKey, mcpVersion };
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,UAAU,UAAU;IACxB,MAAM,OAAO,GACX,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,2BAA2B,CAAC;IAChE,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,EAAE,CAAC;IAC3D,MAAM,UAAU,GAAG,OAAO,CAAC;IAE3B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,CAAC,KAAK,CACX,gDAAgD;YAC9C,gDAAgD,CACnD,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;AAC7C,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ExplainUI MCP Server
|
|
4
|
+
* ====================
|
|
5
|
+
* Registers 3 tools: explainui_attach_project, explainui_analyze, explainui_close_project
|
|
6
|
+
* Runs over stdio transport for Claude Desktop, Cursor, Cline, Windsurf.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ExplainUI MCP Server
|
|
4
|
+
* ====================
|
|
5
|
+
* Registers 3 tools: explainui_attach_project, explainui_analyze, explainui_close_project
|
|
6
|
+
* Runs over stdio transport for Claude Desktop, Cursor, Cline, Windsurf.
|
|
7
|
+
*/
|
|
8
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { loadConfig } from "./config.js";
|
|
12
|
+
import { ApiClient } from "./client.js";
|
|
13
|
+
import { attachProject, analyze, closeProject } from "./tools.js";
|
|
14
|
+
// ── Session State ──────────────────────────────────────────────────────────
|
|
15
|
+
function detectPlatform() {
|
|
16
|
+
const c = (process.env.MCP_CLIENT ?? "").toLowerCase();
|
|
17
|
+
if (c.includes("cursor"))
|
|
18
|
+
return "cursor";
|
|
19
|
+
if (c.includes("cline"))
|
|
20
|
+
return "cline";
|
|
21
|
+
if (c.includes("windsurf"))
|
|
22
|
+
return "windsurf";
|
|
23
|
+
if (process.env.CLAUDE_DESKTOP_APP)
|
|
24
|
+
return "claude_desktop";
|
|
25
|
+
return "unknown";
|
|
26
|
+
}
|
|
27
|
+
const session = {
|
|
28
|
+
projectConfig: null,
|
|
29
|
+
platform: detectPlatform(),
|
|
30
|
+
};
|
|
31
|
+
// ── Config + Client ────────────────────────────────────────────────────────
|
|
32
|
+
const config = loadConfig();
|
|
33
|
+
const client = new ApiClient(config);
|
|
34
|
+
// ── MCP Server ─────────────────────────────────────────────────────────────
|
|
35
|
+
const server = new McpServer({
|
|
36
|
+
name: "explainui",
|
|
37
|
+
version: config.mcpVersion,
|
|
38
|
+
});
|
|
39
|
+
// ── Tool: explainui_attach_project ─────────────────────────────────────────
|
|
40
|
+
server.tool("explainui_attach_project", `Load your ExplainUI project configuration into this session.
|
|
41
|
+
|
|
42
|
+
WHEN TO CALL:
|
|
43
|
+
Immediately when the user provides their project ID in any of these forms:
|
|
44
|
+
"ExplainUI project: proj_abc123"
|
|
45
|
+
"My ExplainUI project is proj_abc123"
|
|
46
|
+
"proj_abc123" (if ExplainUI context is established)
|
|
47
|
+
Call BEFORE writing any code. BEFORE starting any task. First action always.
|
|
48
|
+
|
|
49
|
+
WHAT THIS LOADS AND CACHES FOR THE ENTIRE SESSION:
|
|
50
|
+
- pages[]: every configured page with page_key → URL mapping
|
|
51
|
+
- constraint_bundle: design constraints + intentional decisions to skip
|
|
52
|
+
- trigger_threshold: when to auto-call analyze
|
|
53
|
+
- project name + tier
|
|
54
|
+
|
|
55
|
+
CONFIG IS CACHED: If called again for the same project_id within 5 minutes,
|
|
56
|
+
returns cached result without hitting the API.`, {
|
|
57
|
+
project_id: z
|
|
58
|
+
.string()
|
|
59
|
+
.describe("The project ID from explainui.com/dashboard, format: proj_xxxxxxxx"),
|
|
60
|
+
}, async ({ project_id }) => {
|
|
61
|
+
return attachProject(session, client, project_id);
|
|
62
|
+
});
|
|
63
|
+
// ── Tool: explainui_analyze ────────────────────────────────────────────────
|
|
64
|
+
server.tool("explainui_analyze", `Run a UX QA check on a locally running web page. Captures screenshots at 3 viewports (desktop, tablet, mobile) and sends them to GPT-4o for professional UX analysis.
|
|
65
|
+
|
|
66
|
+
Call this after each meaningful code change. The tool:
|
|
67
|
+
1. Launches headless Chromium and captures the page at multiple viewports
|
|
68
|
+
2. Sends screenshots + context to the ExplainUI API
|
|
69
|
+
3. Returns issues with severity, fix suggestions, and bounding boxes
|
|
70
|
+
|
|
71
|
+
IMPORTANT: Always call explainui_attach_project first to load the project config.`, {
|
|
72
|
+
project_id: z
|
|
73
|
+
.string()
|
|
74
|
+
.describe("proj_xxx — from the attach_project result this session"),
|
|
75
|
+
page_key: z
|
|
76
|
+
.string()
|
|
77
|
+
.describe("Which page to check. E.g., 'homepage', 'pricing'. Must match a page in project config."),
|
|
78
|
+
iteration: z
|
|
79
|
+
.number()
|
|
80
|
+
.int()
|
|
81
|
+
.min(1)
|
|
82
|
+
.max(10)
|
|
83
|
+
.describe("Current iteration count for this page_key. Start at 1. Increment after each call."),
|
|
84
|
+
this_iteration: z
|
|
85
|
+
.string()
|
|
86
|
+
.min(40)
|
|
87
|
+
.max(500)
|
|
88
|
+
.describe("What was just built or changed. Be specific — GPT uses this to verify. Minimum 40 characters."),
|
|
89
|
+
git_snapshot_hash: z
|
|
90
|
+
.string()
|
|
91
|
+
.nullable()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe("Short SHA from the pre-analysis git commit. null if git unavailable."),
|
|
94
|
+
}, async (args) => {
|
|
95
|
+
return analyze(session, client, args);
|
|
96
|
+
});
|
|
97
|
+
// ── Tool: explainui_close_project ──────────────────────────────────────────
|
|
98
|
+
server.tool("explainui_close_project", `Mark the ExplainUI session as complete. Housekeeping — always call when done.
|
|
99
|
+
|
|
100
|
+
WHEN TO CALL:
|
|
101
|
+
- After analyze returns next_action="done" for the LAST page in the session
|
|
102
|
+
- When user says: "we're done for today", "that's all", "stopping here"
|
|
103
|
+
- Before ending any long coding session where ExplainUI was active
|
|
104
|
+
- If analysis errors out permanently on all pages
|
|
105
|
+
|
|
106
|
+
WHAT THIS DOES:
|
|
107
|
+
- Releases browser resources (headless Chromium)
|
|
108
|
+
- Clears cached project config
|
|
109
|
+
- All iterations and screenshots are preserved in the dashboard.`, {
|
|
110
|
+
project_id: z
|
|
111
|
+
.string()
|
|
112
|
+
.describe("proj_xxx — same project that was attached this session"),
|
|
113
|
+
reason: z
|
|
114
|
+
.enum([
|
|
115
|
+
"all_pages_done",
|
|
116
|
+
"session_end",
|
|
117
|
+
"user_request",
|
|
118
|
+
"permanent_error",
|
|
119
|
+
])
|
|
120
|
+
.describe("Why the session is being closed"),
|
|
121
|
+
}, async (args) => {
|
|
122
|
+
return closeProject(session, client, args);
|
|
123
|
+
});
|
|
124
|
+
// ── Start Server ───────────────────────────────────────────────────────────
|
|
125
|
+
async function main() {
|
|
126
|
+
const transport = new StdioServerTransport();
|
|
127
|
+
await server.connect(transport);
|
|
128
|
+
console.error(`[ExplainUI MCP] Server started (platform: ${session.platform})`);
|
|
129
|
+
}
|
|
130
|
+
main().catch((err) => {
|
|
131
|
+
console.error("[ExplainUI MCP] Fatal error:", err);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
});
|
|
134
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplainUI MCP — Tool Implementations
|
|
3
|
+
* Three tools: attach_project, analyze, close_project
|
|
4
|
+
*/
|
|
5
|
+
import { ApiClient } from "./client.js";
|
|
6
|
+
import type { ExplainUISession } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* explainui_attach_project — Load project config into session.
|
|
9
|
+
*/
|
|
10
|
+
export declare function attachProject(session: ExplainUISession, client: ApiClient, projectId: string): Promise<{
|
|
11
|
+
content: Array<{
|
|
12
|
+
type: "text";
|
|
13
|
+
text: string;
|
|
14
|
+
}>;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* explainui_analyze — Capture screenshots + run UX QA analysis.
|
|
18
|
+
*/
|
|
19
|
+
export declare function analyze(session: ExplainUISession, client: ApiClient, args: {
|
|
20
|
+
project_id: string;
|
|
21
|
+
page_key: string;
|
|
22
|
+
iteration: number;
|
|
23
|
+
this_iteration: string;
|
|
24
|
+
git_snapshot_hash?: string | null;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
content: Array<{
|
|
27
|
+
type: "text";
|
|
28
|
+
text: string;
|
|
29
|
+
}>;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* explainui_close_project — Session cleanup.
|
|
33
|
+
*/
|
|
34
|
+
export declare function closeProject(session: ExplainUISession, _client: ApiClient, args: {
|
|
35
|
+
project_id: string;
|
|
36
|
+
reason: string;
|
|
37
|
+
}): Promise<{
|
|
38
|
+
content: Array<{
|
|
39
|
+
type: "text";
|
|
40
|
+
text: string;
|
|
41
|
+
}>;
|
|
42
|
+
}>;
|
|
43
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,KAAK,EACV,gBAAgB,EAGjB,MAAM,YAAY,CAAC;AAKpB;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,SAAS,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CA4E7D;AAED;;GAEG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE;IACJ,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC,GACA,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CA4F7D;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,SAAS,EAClB,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC3C,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAuB7D"}
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplainUI MCP — Tool Implementations
|
|
3
|
+
* Three tools: attach_project, analyze, close_project
|
|
4
|
+
*/
|
|
5
|
+
import { captureAllViewports, closeBrowser } from "./capture.js";
|
|
6
|
+
import { ExplainUIError } from "./types.js";
|
|
7
|
+
const CONFIG_CACHE_TTL_MS = 5 * 60 * 1000; // 5 min
|
|
8
|
+
/**
|
|
9
|
+
* explainui_attach_project — Load project config into session.
|
|
10
|
+
*/
|
|
11
|
+
export async function attachProject(session, client, projectId) {
|
|
12
|
+
// Return cached if fresh
|
|
13
|
+
if (session.projectConfig &&
|
|
14
|
+
session.projectConfig.project_id === projectId &&
|
|
15
|
+
Date.now() - session.projectConfig.fetched_at < CONFIG_CACHE_TTL_MS) {
|
|
16
|
+
const config = session.projectConfig;
|
|
17
|
+
return {
|
|
18
|
+
content: [
|
|
19
|
+
{
|
|
20
|
+
type: "text",
|
|
21
|
+
text: [
|
|
22
|
+
`✅ Project already loaded: ${config.name} (${config.project_id})`,
|
|
23
|
+
`Pages: ${config.pages.map((p) => p.page_key).join(", ")}`,
|
|
24
|
+
`Trigger: ${config.trigger_threshold}`,
|
|
25
|
+
`(cached — valid for ${Math.round((CONFIG_CACHE_TTL_MS - (Date.now() - config.fetched_at)) / 1000)}s)`,
|
|
26
|
+
].join("\n"),
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const config = await client.getProjectConfig(projectId);
|
|
33
|
+
session.projectConfig = config;
|
|
34
|
+
const pageList = config.pages
|
|
35
|
+
.map((p) => ` • ${p.page_key} → ${p.url}${p.description ? ` (${p.description})` : ""}`)
|
|
36
|
+
.join("\n");
|
|
37
|
+
return {
|
|
38
|
+
content: [
|
|
39
|
+
{
|
|
40
|
+
type: "text",
|
|
41
|
+
text: [
|
|
42
|
+
`✅ Project loaded: ${config.name} (${config.project_id})`,
|
|
43
|
+
``,
|
|
44
|
+
`Pages:`,
|
|
45
|
+
pageList,
|
|
46
|
+
``,
|
|
47
|
+
`Trigger threshold: ${config.trigger_threshold}`,
|
|
48
|
+
config.constraint_bundle.user_goal
|
|
49
|
+
? `User goal: ${config.constraint_bundle.user_goal}`
|
|
50
|
+
: "",
|
|
51
|
+
config.constraint_bundle.do_not_flag.length > 0
|
|
52
|
+
? `Do not flag: ${config.constraint_bundle.do_not_flag.join(", ")}`
|
|
53
|
+
: "",
|
|
54
|
+
``,
|
|
55
|
+
`You may now call explainui_analyze for any page_key listed above.`,
|
|
56
|
+
]
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
.join("\n"),
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
if (err instanceof ExplainUIError) {
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: "text",
|
|
69
|
+
text: `❌ Failed to load project: ${err.message}\nCode: ${err.code}`,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: "text",
|
|
78
|
+
text: `❌ Failed to load project: ${err.message}`,
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* explainui_analyze — Capture screenshots + run UX QA analysis.
|
|
86
|
+
*/
|
|
87
|
+
export async function analyze(session, client, args) {
|
|
88
|
+
// Verify project is attached
|
|
89
|
+
if (!session.projectConfig) {
|
|
90
|
+
return {
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: "text",
|
|
94
|
+
text: "❌ No project loaded. Call explainui_attach_project first.",
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (session.projectConfig.project_id !== args.project_id) {
|
|
100
|
+
return {
|
|
101
|
+
content: [
|
|
102
|
+
{
|
|
103
|
+
type: "text",
|
|
104
|
+
text: `❌ Project mismatch. Session has ${session.projectConfig.project_id} but you requested ${args.project_id}. Call explainui_attach_project with the correct project.`,
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// Find the page URL
|
|
110
|
+
const pageConfig = session.projectConfig.pages.find((p) => p.page_key === args.page_key);
|
|
111
|
+
if (!pageConfig) {
|
|
112
|
+
const available = session.projectConfig.pages
|
|
113
|
+
.map((p) => p.page_key)
|
|
114
|
+
.join(", ");
|
|
115
|
+
return {
|
|
116
|
+
content: [
|
|
117
|
+
{
|
|
118
|
+
type: "text",
|
|
119
|
+
text: `❌ Unknown page_key: "${args.page_key}". Available: ${available}`,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Step 1: Capture screenshots
|
|
125
|
+
let capture;
|
|
126
|
+
try {
|
|
127
|
+
capture = await captureAllViewports(pageConfig.url);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
if (err instanceof ExplainUIError) {
|
|
131
|
+
return {
|
|
132
|
+
content: [
|
|
133
|
+
{
|
|
134
|
+
type: "text",
|
|
135
|
+
text: `❌ Screenshot capture failed: ${err.message}\nCode: ${err.code}`,
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
content: [
|
|
142
|
+
{
|
|
143
|
+
type: "text",
|
|
144
|
+
text: `❌ Screenshot capture failed: ${err.message}`,
|
|
145
|
+
},
|
|
146
|
+
],
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
// Step 2: Send to API
|
|
150
|
+
try {
|
|
151
|
+
const response = await client.analyze({
|
|
152
|
+
project_id: args.project_id,
|
|
153
|
+
page_key: args.page_key,
|
|
154
|
+
iteration: args.iteration,
|
|
155
|
+
this_iteration: args.this_iteration,
|
|
156
|
+
license_key: "", // Filled by client
|
|
157
|
+
screenshots_base64: capture.screenshots.map((s) => s.data),
|
|
158
|
+
screenshot_labels: capture.screenshots.map((s) => s.label),
|
|
159
|
+
git_snapshot_hash: args.git_snapshot_hash,
|
|
160
|
+
});
|
|
161
|
+
// Step 3: Format response for Claude
|
|
162
|
+
return { content: [{ type: "text", text: formatResponse(response) }] };
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
return {
|
|
166
|
+
content: [
|
|
167
|
+
{
|
|
168
|
+
type: "text",
|
|
169
|
+
text: `❌ Analysis API call failed: ${err.message}`,
|
|
170
|
+
},
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* explainui_close_project — Session cleanup.
|
|
177
|
+
*/
|
|
178
|
+
export async function closeProject(session, _client, args) {
|
|
179
|
+
const projectName = session.projectConfig?.name || args.project_id;
|
|
180
|
+
// Clean up browser
|
|
181
|
+
await closeBrowser();
|
|
182
|
+
// Clear session
|
|
183
|
+
session.projectConfig = null;
|
|
184
|
+
return {
|
|
185
|
+
content: [
|
|
186
|
+
{
|
|
187
|
+
type: "text",
|
|
188
|
+
text: [
|
|
189
|
+
`✅ ExplainUI session closed for ${projectName}.`,
|
|
190
|
+
`Reason: ${args.reason}`,
|
|
191
|
+
``,
|
|
192
|
+
`All iterations and screenshots are preserved in the dashboard.`,
|
|
193
|
+
`Browser resources released.`,
|
|
194
|
+
].join("\n"),
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
// ── Response Formatter ─────────────────────────────────────────────────────
|
|
200
|
+
function formatResponse(resp) {
|
|
201
|
+
const lines = [];
|
|
202
|
+
if (resp.error) {
|
|
203
|
+
lines.push(`❌ Analysis Error`);
|
|
204
|
+
lines.push(`Code: ${resp.error.code}`);
|
|
205
|
+
lines.push(`Message: ${resp.error.message}`);
|
|
206
|
+
if (resp.error.hint)
|
|
207
|
+
lines.push(`Hint: ${resp.error.hint}`);
|
|
208
|
+
return lines.join("\n");
|
|
209
|
+
}
|
|
210
|
+
const emoji = resp.pass ? "✅" : "🔧";
|
|
211
|
+
lines.push(`${emoji} UX QA Result — ${resp.page_key} iteration ${resp.iteration}`);
|
|
212
|
+
lines.push(`Pass: ${resp.pass}`);
|
|
213
|
+
lines.push(`Next action: ${resp.next_action}`);
|
|
214
|
+
lines.push("");
|
|
215
|
+
// Checks summary
|
|
216
|
+
if (resp.checks) {
|
|
217
|
+
lines.push("Checks:");
|
|
218
|
+
for (const [check, result] of Object.entries(resp.checks)) {
|
|
219
|
+
const r = result;
|
|
220
|
+
const icon = r.pass ? "✅" : "❌";
|
|
221
|
+
lines.push(` ${icon} ${check}: ${r.pass ? "pass" : `${r.issues_found} issue(s)`}`);
|
|
222
|
+
}
|
|
223
|
+
lines.push("");
|
|
224
|
+
}
|
|
225
|
+
// Issues
|
|
226
|
+
if (resp.issues && resp.issues.length > 0) {
|
|
227
|
+
lines.push(`Issues (${resp.issues.length}):`);
|
|
228
|
+
for (const issue of resp.issues) {
|
|
229
|
+
lines.push(` [${issue.severity.toUpperCase()}] ${issue.id}: ${issue.summary}`);
|
|
230
|
+
lines.push(` Type: ${issue.type}`);
|
|
231
|
+
lines.push(` Location: ${issue.location.viewport} — ${issue.location.element_description}`);
|
|
232
|
+
lines.push(` Confidence: ${(issue.confidence * 100).toFixed(0)}%`);
|
|
233
|
+
lines.push(` Fix: ${issue.fix_suggestion}`);
|
|
234
|
+
lines.push("");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (resp.deprecation_warning) {
|
|
238
|
+
lines.push(`⚠️ ${resp.deprecation_warning}`);
|
|
239
|
+
}
|
|
240
|
+
if (resp.analysis_duration_ms) {
|
|
241
|
+
lines.push(`(Analysis took ${resp.analysis_duration_ms}ms)`);
|
|
242
|
+
}
|
|
243
|
+
return lines.join("\n");
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplainUI MCP — TypeScript Types
|
|
3
|
+
* Mirrors the Python schema.py models for the MCP side.
|
|
4
|
+
*/
|
|
5
|
+
export interface ExplainUISession {
|
|
6
|
+
projectConfig: ProjectConfig | null;
|
|
7
|
+
platform: "claude_desktop" | "cursor" | "cline" | "windsurf" | "unknown";
|
|
8
|
+
}
|
|
9
|
+
export interface ProjectConfig {
|
|
10
|
+
project_id: string;
|
|
11
|
+
name: string;
|
|
12
|
+
pages: PageConfig[];
|
|
13
|
+
constraint_bundle: ConstraintBundle;
|
|
14
|
+
trigger_threshold: "every_change" | "major_features" | "manual_only";
|
|
15
|
+
fetched_at: number;
|
|
16
|
+
}
|
|
17
|
+
export interface PageConfig {
|
|
18
|
+
page_key: string;
|
|
19
|
+
url: string;
|
|
20
|
+
description: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ConstraintBundle {
|
|
23
|
+
user_goal: string;
|
|
24
|
+
user_enforced_constraints: string[];
|
|
25
|
+
do_not_flag: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface ViewportDef {
|
|
28
|
+
label: string;
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
scrolls: number;
|
|
32
|
+
}
|
|
33
|
+
export declare const VIEWPORTS: ViewportDef[];
|
|
34
|
+
export interface Screenshot {
|
|
35
|
+
label: string;
|
|
36
|
+
viewport: string;
|
|
37
|
+
scroll_index: number;
|
|
38
|
+
data: string;
|
|
39
|
+
}
|
|
40
|
+
export interface CaptureResult {
|
|
41
|
+
screenshots: Screenshot[];
|
|
42
|
+
capture_duration_ms: number;
|
|
43
|
+
}
|
|
44
|
+
export interface AnalyzeRequest {
|
|
45
|
+
project_id: string;
|
|
46
|
+
page_key: string;
|
|
47
|
+
iteration: number;
|
|
48
|
+
this_iteration: string;
|
|
49
|
+
license_key: string;
|
|
50
|
+
screenshots_base64: string[];
|
|
51
|
+
screenshot_labels: string[];
|
|
52
|
+
git_snapshot_hash?: string | null;
|
|
53
|
+
constraint_bundle?: ConstraintBundle;
|
|
54
|
+
mcp_version?: string;
|
|
55
|
+
}
|
|
56
|
+
export interface AnalyzeResponse {
|
|
57
|
+
project_id: string;
|
|
58
|
+
page_key: string;
|
|
59
|
+
iteration: number;
|
|
60
|
+
pass: boolean;
|
|
61
|
+
next_action: "fix" | "done" | "review_human" | "error";
|
|
62
|
+
checks?: Record<string, unknown>;
|
|
63
|
+
issues?: Issue[];
|
|
64
|
+
error?: AnalysisError | null;
|
|
65
|
+
deprecation_warning?: string | null;
|
|
66
|
+
analysis_duration_ms?: number;
|
|
67
|
+
}
|
|
68
|
+
export interface Issue {
|
|
69
|
+
id: string;
|
|
70
|
+
type: string;
|
|
71
|
+
severity: string;
|
|
72
|
+
summary: string;
|
|
73
|
+
location: {
|
|
74
|
+
viewport: string;
|
|
75
|
+
bbox: {
|
|
76
|
+
x: number;
|
|
77
|
+
y: number;
|
|
78
|
+
w: number;
|
|
79
|
+
h: number;
|
|
80
|
+
};
|
|
81
|
+
element_description: string;
|
|
82
|
+
};
|
|
83
|
+
confidence: number;
|
|
84
|
+
fix_suggestion: string;
|
|
85
|
+
}
|
|
86
|
+
export interface AnalysisError {
|
|
87
|
+
code: string;
|
|
88
|
+
message: string;
|
|
89
|
+
hint?: string;
|
|
90
|
+
upgrade_url?: string;
|
|
91
|
+
}
|
|
92
|
+
export interface VersionInfo {
|
|
93
|
+
api_version: string;
|
|
94
|
+
min_mcp_version: string;
|
|
95
|
+
deprecation_warning: string | null;
|
|
96
|
+
}
|
|
97
|
+
export declare class ExplainUIError extends Error {
|
|
98
|
+
code: string;
|
|
99
|
+
constructor(code: string, message: string);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplainUI MCP — TypeScript Types
|
|
3
|
+
* Mirrors the Python schema.py models for the MCP side.
|
|
4
|
+
*/
|
|
5
|
+
export const VIEWPORTS = [
|
|
6
|
+
{ label: "desktop_1280", width: 1280, height: 800, scrolls: 3 },
|
|
7
|
+
{ label: "tablet_768", width: 768, height: 1024, scrolls: 2 },
|
|
8
|
+
{ label: "mobile_375", width: 375, height: 812, scrolls: 2 },
|
|
9
|
+
];
|
|
10
|
+
// ── Error ──────────────────────────────────────────────────────────────────
|
|
11
|
+
export class ExplainUIError extends Error {
|
|
12
|
+
code;
|
|
13
|
+
constructor(code, message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.code = code;
|
|
16
|
+
this.name = "ExplainUIError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqCH,MAAM,CAAC,MAAM,SAAS,GAAkB;IACtC,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE;IAC/D,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE;IAC7D,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE;CAC7D,CAAC;AAsEF,8EAA8E;AAC9E,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,IAAI,CAAS;IACb,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@explainui/mcp",
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"description": "ExplainUI MCP server — silent UX QA in your AI agent workflow",
|
|
5
|
+
"bin": {
|
|
6
|
+
"explainui-mcp": "dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist/",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev": "tsx watch src/index.ts",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"test:watch": "vitest",
|
|
20
|
+
"prepublishOnly": "npm run build",
|
|
21
|
+
"postinstall": "playwright install chromium --quiet || true"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"mcp",
|
|
25
|
+
"ux",
|
|
26
|
+
"qa",
|
|
27
|
+
"playwright",
|
|
28
|
+
"claude",
|
|
29
|
+
"cursor",
|
|
30
|
+
"ai",
|
|
31
|
+
"explainui"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
39
|
+
"axios": "^1.13.6",
|
|
40
|
+
"playwright": "^1.58.2",
|
|
41
|
+
"zod": "^3.25.76",
|
|
42
|
+
"zod-to-json-schema": "^3.25.1"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^20.19.37",
|
|
46
|
+
"tsx": "^4.21.0",
|
|
47
|
+
"typescript": "^5.9.3",
|
|
48
|
+
"vitest": "^1.6.1"
|
|
49
|
+
}
|
|
50
|
+
}
|