vibedsgn-mcp 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.
package/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # vibedsgn-mcp
2
+
3
+ MCP server for posting designs to [Vibedsgn](https://vibedsgn.com) from AI agents like Claude Code, Cursor, Codex, and any other MCP-compatible tool.
4
+
5
+ Built for agents — every tool has a workflow-explaining description, structured error codes, and a `whoami` pre-flight so your agent can fail fast on bad auth.
6
+
7
+ ## Quick Start
8
+
9
+ ### 1. Get your API key
10
+
11
+ 1. Go to [vibedsgn.com/settings](https://vibedsgn.com/settings)
12
+ 2. Scroll to **API Key** section
13
+ 3. Click **Generate API Key**
14
+ 4. Copy the key (it's shown only once — starts with `vdsgn_`)
15
+
16
+ ### 2. Configure your agent
17
+
18
+ **Option A: Interactive setup**
19
+
20
+ ```bash
21
+ npx vibedsgn-mcp init
22
+ ```
23
+
24
+ **Option B: Manual configuration**
25
+
26
+ <details>
27
+ <summary>Claude Code (~/.claude.json)</summary>
28
+
29
+ ```json
30
+ {
31
+ "mcpServers": {
32
+ "vibedsgn": {
33
+ "command": "npx",
34
+ "args": ["-y", "vibedsgn-mcp"],
35
+ "env": {
36
+ "VIBEDSGN_API_KEY": "vdsgn_your_key_here"
37
+ }
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ </details>
44
+
45
+ <details>
46
+ <summary>Cursor (~/.cursor/mcp.json)</summary>
47
+
48
+ ```json
49
+ {
50
+ "mcpServers": {
51
+ "vibedsgn": {
52
+ "command": "npx",
53
+ "args": ["-y", "vibedsgn-mcp"],
54
+ "env": {
55
+ "VIBEDSGN_API_KEY": "vdsgn_your_key_here"
56
+ }
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ </details>
63
+
64
+ ## Tools
65
+
66
+ ### `whoami`
67
+
68
+ Verify the API key and return the authenticated user. **Call this first** to confirm auth before doing real work — cheap, no DB writes.
69
+
70
+ Returns: `{ user: { id, name, handle, image } }`
71
+
72
+ ### `list_design_tools`
73
+
74
+ Browse the design tool registry on Vibedsgn so you can pick a valid `primaryToolId` for `post_vibe`.
75
+
76
+ | Param | Type | Notes |
77
+ |-------|------|-------|
78
+ | `category` | string | Exact category match: `ai-design`, `ai-agents`, `design-skills`, `ai-stack` |
79
+ | `slug` | string | Exact tool slug lookup (case-insensitive) |
80
+ | `q` | string | Fuzzy substring across name/slug/description |
81
+
82
+ All params optional; multiple combine with AND. No params returns the full registry.
83
+
84
+ Returns: `{ count, tools: [{ id, name, slug, category, description }] }`
85
+
86
+ ### `post_vibe`
87
+
88
+ Publish a design to Vibedsgn. Vibes go live immediately — no draft step.
89
+
90
+ **Workflow:**
91
+ 1. Call `whoami` to confirm auth
92
+ 2. Call `list_design_tools` (with `q: "cursor"` or similar) to pick `primaryToolId`
93
+ 3. **(Optional)** Call `post_vibe` with `dryRun: true` to preview the predicted slug + tool name without uploading or publishing — useful for "show the user, then commit" flows
94
+ 4. Call `post_vibe` with the title, primaryToolId, and **either** `desktopImageUrl` (a public URL — preferred) **or** `desktopImage` (base64 PNG, max 4MB)
95
+
96
+ **Required fields:**
97
+ - `title` — Project name
98
+ - `primaryToolId` — Tool ID from `list_design_tools`
99
+ - `desktopImageUrl` *or* `desktopImage` — at least one
100
+
101
+ **Optional fields:**
102
+
103
+ | Field | Type | Notes |
104
+ |-------|------|-------|
105
+ | `description` | string | 1-2 sentences |
106
+ | `desktopImageUrl` | url | Preferred. Server fetches and uploads. |
107
+ | `desktopImage` | base64 | Fallback. Slower because base64 doubles payload. |
108
+ | `mobileImageUrl` / `mobileImage` | url / base64 | Optional mobile screenshot |
109
+ | `tags` | string[] | Free-form curation tags |
110
+ | `systemPrompt` | string | Generation prompt used |
111
+ | `processNotes` | string | Notes about the build process |
112
+ | `aiStack` | object | `{ codingAgents?, imageGen?, videoGen?, other? }` — all inner arrays optional |
113
+ | `designSystem` | object | `{ colors?, typography? }` |
114
+ | `liveUrl` | url | Live project URL |
115
+ | `githubUrl` | url | GitHub repo URL |
116
+ | `dryRun` | boolean | When `true`, validate inputs and return the predicted slug + tool without uploading or publishing. No DB write, no Vercel Blob call. Default `false`. |
117
+
118
+ Returns: `{ id, slug, url, message }` — `url` is the absolute https URL of the published vibe.
119
+
120
+ When `dryRun: true`, returns: `{ dryRun: true, wouldCreate: { slug, url, title, primaryTool: { id, name, slug } }, message }` instead. No `id` because no row is created.
121
+
122
+ ### `delete_vibe`
123
+
124
+ Permanently delete a vibe you own. Cascades to likes, bookmarks, comments, and notifications. **Irreversible.**
125
+
126
+ | Param | Type | Notes |
127
+ |-------|------|-------|
128
+ | `id` | string | The vibe id returned by `post_vibe` |
129
+
130
+ You can only delete vibes owned by the authenticated user. Attempts to delete someone else's vibe return `NOT_FOUND` (we don't distinguish from "doesn't exist", to avoid leaking ownership info).
131
+
132
+ ## Error format
133
+
134
+ All tools return errors in a structured format your agent can branch on:
135
+
136
+ ```json
137
+ {
138
+ "success": false,
139
+ "error": {
140
+ "code": "UNAUTHORIZED" | "VALIDATION_ERROR" | "NOT_FOUND" | "RATE_LIMIT" | "INTERNAL" | "...",
141
+ "message": "Human-readable description",
142
+ "details": { "...optional..." }
143
+ }
144
+ }
145
+ ```
146
+
147
+ ## Environment Variables
148
+
149
+ | Variable | Required | Description |
150
+ |----------|----------|-------------|
151
+ | `VIBEDSGN_API_KEY` | Yes* | Your API key from vibedsgn.com/settings |
152
+ | `VIBEDSGN_API_URL` | No | Custom API base (default: `https://vibedsgn.com`) |
153
+ | `VIBEDSGN_SESSION_TOKEN` | No | Alternative: OAuth session token |
154
+
155
+ *Either `VIBEDSGN_API_KEY` or `VIBEDSGN_SESSION_TOKEN` is required.
156
+
157
+ ## License
158
+
159
+ MIT
package/dist/cli.cjs ADDED
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/cli.ts
27
+ var p = __toESM(require("@clack/prompts"), 1);
28
+ var import_fs = __toESM(require("fs"), 1);
29
+ var import_path = __toESM(require("path"), 1);
30
+ var import_os = __toESM(require("os"), 1);
31
+ var CLAUDE_CONFIG_PATH = import_path.default.join(import_os.default.homedir(), ".claude.json");
32
+ var CURSOR_CONFIG_PATH = import_path.default.join(import_os.default.homedir(), ".cursor", "mcp.json");
33
+ function getMcpServerConfig(apiKey, apiUrl) {
34
+ const env = { VIBEDSGN_API_KEY: apiKey };
35
+ if (apiUrl) env.VIBEDSGN_API_URL = apiUrl;
36
+ return {
37
+ command: "npx",
38
+ args: ["-y", "vibedsgn-mcp"],
39
+ env
40
+ };
41
+ }
42
+ async function main() {
43
+ const args = process.argv.slice(2);
44
+ if (args[0] !== "init") {
45
+ console.log("Usage: vibedsgn-mcp init");
46
+ console.log(" Interactive setup for Claude Code, Cursor, or other MCP-compatible agents.");
47
+ process.exit(0);
48
+ }
49
+ p.intro("Vibedsgn MCP Server Setup");
50
+ const apiKey = await p.text({
51
+ message: "Enter your Vibedsgn API key:",
52
+ placeholder: "vdsgn_...",
53
+ validate: (val) => {
54
+ if (!val || !val.startsWith("vdsgn_")) return "API key must start with vdsgn_";
55
+ if (val.length < 20) return "API key is too short";
56
+ return void 0;
57
+ }
58
+ });
59
+ if (p.isCancel(apiKey)) {
60
+ p.cancel("Setup cancelled.");
61
+ process.exit(0);
62
+ }
63
+ const customUrl = await p.confirm({
64
+ message: "Use custom API URL? (default: https://vibedsgn.com)",
65
+ initialValue: false
66
+ });
67
+ if (p.isCancel(customUrl)) {
68
+ p.cancel("Setup cancelled.");
69
+ process.exit(0);
70
+ }
71
+ let apiUrl;
72
+ if (customUrl) {
73
+ const url = await p.text({
74
+ message: "Enter API URL:",
75
+ placeholder: "https://vibedsgn.com"
76
+ });
77
+ if (p.isCancel(url)) {
78
+ p.cancel("Setup cancelled.");
79
+ process.exit(0);
80
+ }
81
+ apiUrl = url;
82
+ }
83
+ const agent = await p.select({
84
+ message: "Which AI agent are you configuring?",
85
+ options: [
86
+ { value: "claude", label: "Claude Code", hint: "~/.claude.json" },
87
+ { value: "cursor", label: "Cursor", hint: "~/.cursor/mcp.json" },
88
+ { value: "manual", label: "Other / Manual", hint: "Print config to copy" }
89
+ ]
90
+ });
91
+ if (p.isCancel(agent)) {
92
+ p.cancel("Setup cancelled.");
93
+ process.exit(0);
94
+ }
95
+ const serverConfig = getMcpServerConfig(apiKey, apiUrl);
96
+ if (agent === "manual") {
97
+ p.note(
98
+ JSON.stringify({ mcpServers: { vibedsgn: serverConfig } }, null, 2),
99
+ "Add this to your MCP configuration file:"
100
+ );
101
+ p.outro("Done! Add the config above to your agent's MCP settings.");
102
+ return;
103
+ }
104
+ const configPath = agent === "claude" ? CLAUDE_CONFIG_PATH : CURSOR_CONFIG_PATH;
105
+ const configDir = import_path.default.dirname(configPath);
106
+ let config = {};
107
+ if (import_fs.default.existsSync(configPath)) {
108
+ try {
109
+ config = JSON.parse(import_fs.default.readFileSync(configPath, "utf-8"));
110
+ } catch {
111
+ p.log.warn(`Could not parse existing ${configPath} \u2014 will create new.`);
112
+ }
113
+ }
114
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
115
+ config.mcpServers = {};
116
+ }
117
+ config.mcpServers.vibedsgn = serverConfig;
118
+ if (!import_fs.default.existsSync(configDir)) {
119
+ import_fs.default.mkdirSync(configDir, { recursive: true });
120
+ }
121
+ import_fs.default.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
122
+ p.outro(`Config written to ${configPath}. Restart your agent to activate.`);
123
+ }
124
+ main().catch((err) => {
125
+ console.error("Setup failed:", err);
126
+ process.exit(1);
127
+ });
package/dist/cli.d.cts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import * as p from "@clack/prompts";
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import os from "os";
8
+ var CLAUDE_CONFIG_PATH = path.join(os.homedir(), ".claude.json");
9
+ var CURSOR_CONFIG_PATH = path.join(os.homedir(), ".cursor", "mcp.json");
10
+ function getMcpServerConfig(apiKey, apiUrl) {
11
+ const env = { VIBEDSGN_API_KEY: apiKey };
12
+ if (apiUrl) env.VIBEDSGN_API_URL = apiUrl;
13
+ return {
14
+ command: "npx",
15
+ args: ["-y", "vibedsgn-mcp"],
16
+ env
17
+ };
18
+ }
19
+ async function main() {
20
+ const args = process.argv.slice(2);
21
+ if (args[0] !== "init") {
22
+ console.log("Usage: vibedsgn-mcp init");
23
+ console.log(" Interactive setup for Claude Code, Cursor, or other MCP-compatible agents.");
24
+ process.exit(0);
25
+ }
26
+ p.intro("Vibedsgn MCP Server Setup");
27
+ const apiKey = await p.text({
28
+ message: "Enter your Vibedsgn API key:",
29
+ placeholder: "vdsgn_...",
30
+ validate: (val) => {
31
+ if (!val || !val.startsWith("vdsgn_")) return "API key must start with vdsgn_";
32
+ if (val.length < 20) return "API key is too short";
33
+ return void 0;
34
+ }
35
+ });
36
+ if (p.isCancel(apiKey)) {
37
+ p.cancel("Setup cancelled.");
38
+ process.exit(0);
39
+ }
40
+ const customUrl = await p.confirm({
41
+ message: "Use custom API URL? (default: https://vibedsgn.com)",
42
+ initialValue: false
43
+ });
44
+ if (p.isCancel(customUrl)) {
45
+ p.cancel("Setup cancelled.");
46
+ process.exit(0);
47
+ }
48
+ let apiUrl;
49
+ if (customUrl) {
50
+ const url = await p.text({
51
+ message: "Enter API URL:",
52
+ placeholder: "https://vibedsgn.com"
53
+ });
54
+ if (p.isCancel(url)) {
55
+ p.cancel("Setup cancelled.");
56
+ process.exit(0);
57
+ }
58
+ apiUrl = url;
59
+ }
60
+ const agent = await p.select({
61
+ message: "Which AI agent are you configuring?",
62
+ options: [
63
+ { value: "claude", label: "Claude Code", hint: "~/.claude.json" },
64
+ { value: "cursor", label: "Cursor", hint: "~/.cursor/mcp.json" },
65
+ { value: "manual", label: "Other / Manual", hint: "Print config to copy" }
66
+ ]
67
+ });
68
+ if (p.isCancel(agent)) {
69
+ p.cancel("Setup cancelled.");
70
+ process.exit(0);
71
+ }
72
+ const serverConfig = getMcpServerConfig(apiKey, apiUrl);
73
+ if (agent === "manual") {
74
+ p.note(
75
+ JSON.stringify({ mcpServers: { vibedsgn: serverConfig } }, null, 2),
76
+ "Add this to your MCP configuration file:"
77
+ );
78
+ p.outro("Done! Add the config above to your agent's MCP settings.");
79
+ return;
80
+ }
81
+ const configPath = agent === "claude" ? CLAUDE_CONFIG_PATH : CURSOR_CONFIG_PATH;
82
+ const configDir = path.dirname(configPath);
83
+ let config = {};
84
+ if (fs.existsSync(configPath)) {
85
+ try {
86
+ config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
87
+ } catch {
88
+ p.log.warn(`Could not parse existing ${configPath} \u2014 will create new.`);
89
+ }
90
+ }
91
+ if (!config.mcpServers || typeof config.mcpServers !== "object") {
92
+ config.mcpServers = {};
93
+ }
94
+ config.mcpServers.vibedsgn = serverConfig;
95
+ if (!fs.existsSync(configDir)) {
96
+ fs.mkdirSync(configDir, { recursive: true });
97
+ }
98
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
99
+ p.outro(`Config written to ${configPath}. Restart your agent to activate.`);
100
+ }
101
+ main().catch((err) => {
102
+ console.error("Setup failed:", err);
103
+ process.exit(1);
104
+ });