@vibesharingapp/mcp-server 0.2.0 → 0.3.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 +22 -7
- package/dist/index.js +502 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ See comments, suggestions, and resolved issues without opening a browser.
|
|
|
46
46
|
|
|
47
47
|
### Keep context alive across sessions
|
|
48
48
|
```
|
|
49
|
-
"Sync my CLAUDE.md to VibeSharing"
|
|
49
|
+
"Sync my CLAUDE.md (or AGENTS.md) to VibeSharing"
|
|
50
50
|
```
|
|
51
51
|
Your project context persists on VibeSharing, so any team member (or AI session) can pick up where you left off.
|
|
52
52
|
|
|
@@ -64,9 +64,11 @@ Every prototype you've registered, with links and recent activity.
|
|
|
64
64
|
npm install -g @vibesharingapp/mcp-server
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
### 2. Get Your Token
|
|
67
|
+
### 2. Get Your Token & Connect GitHub
|
|
68
68
|
|
|
69
|
-
Sign up at [vibesharing.app](https://vibesharing.app)
|
|
69
|
+
Sign up at [vibesharing.app](https://vibesharing.app), then go to [Account Settings](https://vibesharing.app/dashboard/account) to:
|
|
70
|
+
- **Connect your GitHub account** — required for Push to Deploy (gives you automatic push access to prototype repos)
|
|
71
|
+
- **Copy your deploy token** — needed for the MCP server config below
|
|
70
72
|
|
|
71
73
|
### 3. Configure Claude Code
|
|
72
74
|
|
|
@@ -104,10 +106,11 @@ See the full picture of your team's prototyping velocity. Guide feedback with cu
|
|
|
104
106
|
|
|
105
107
|
| Tool | Description |
|
|
106
108
|
|------|-------------|
|
|
107
|
-
| `
|
|
109
|
+
| `deploy_prototype` | **NEW** Deploy code directly to VibeSharing (builds & hosts it for you) |
|
|
110
|
+
| `register_prototype` | Register an already-deployed prototype with name, description, and URL |
|
|
108
111
|
| `list_prototypes` | List all prototypes in your organization |
|
|
109
112
|
| `get_feedback` | Get feedback and comments for any prototype |
|
|
110
|
-
| `sync_context` | Push CLAUDE.md or project notes to VibeSharing |
|
|
113
|
+
| `sync_context` | Push CLAUDE.md, AGENTS.md, or project notes to VibeSharing |
|
|
111
114
|
|
|
112
115
|
## Environment Variables
|
|
113
116
|
|
|
@@ -118,6 +121,18 @@ See the full picture of your team's prototyping velocity. Guide feedback with cu
|
|
|
118
121
|
|
|
119
122
|
## Examples
|
|
120
123
|
|
|
124
|
+
### Deploy directly from Claude Code
|
|
125
|
+
```
|
|
126
|
+
You: "Deploy this to VibeSharing as 'Checkout Flow v2'"
|
|
127
|
+
|
|
128
|
+
Claude: Deployed successfully!
|
|
129
|
+
|
|
130
|
+
Live URL: https://proto-checkout-flow-v2-abc123.vercel.app
|
|
131
|
+
VibeSharing: https://vibesharing.app/dashboard/projects/xyz789
|
|
132
|
+
|
|
133
|
+
Your team can now view the prototype and leave feedback.
|
|
134
|
+
```
|
|
135
|
+
|
|
121
136
|
### Register after deploying
|
|
122
137
|
```
|
|
123
138
|
You: "I just deployed to https://checkout-v2.vercel.app - register it on VibeSharing
|
|
@@ -139,7 +154,7 @@ Claude: 3 new comments on Dashboard Redesign:
|
|
|
139
154
|
|
|
140
155
|
### Keep your AI context in sync
|
|
141
156
|
```
|
|
142
|
-
You: "Sync my CLAUDE.md to the Dashboard project on VibeSharing"
|
|
157
|
+
You: "Sync my CLAUDE.md (or AGENTS.md) to the Dashboard project on VibeSharing"
|
|
143
158
|
|
|
144
159
|
Claude: Context synced! Your team can now see your project notes at:
|
|
145
160
|
https://vibesharing.app/dashboard/projects/abc123
|
|
@@ -149,7 +164,7 @@ Claude: Context synced! Your team can now see your project notes at:
|
|
|
149
164
|
|
|
150
165
|
VibeSharing isn't just another tool to check. It's infrastructure for teams building with AI:
|
|
151
166
|
|
|
152
|
-
- **CLAUDE.md
|
|
167
|
+
- **Context file sync** (CLAUDE.md, AGENTS.md) keeps context alive across sessions and team members
|
|
153
168
|
- **Guided feedback topics** help stakeholders give useful input
|
|
154
169
|
- **Email notifications** when prototypes update or get feedback
|
|
155
170
|
- **Works with any deploy target** - Vercel, Netlify, Replit, Lovable, v0, or paste any URL
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@ class VibesharingClient {
|
|
|
19
19
|
headers: {
|
|
20
20
|
"Content-Type": "application/json",
|
|
21
21
|
Authorization: `Bearer ${this.token}`,
|
|
22
|
+
"X-Vibesharing-Client": "mcp",
|
|
22
23
|
...options.headers,
|
|
23
24
|
},
|
|
24
25
|
});
|
|
@@ -34,6 +35,21 @@ class VibesharingClient {
|
|
|
34
35
|
body: JSON.stringify(params),
|
|
35
36
|
});
|
|
36
37
|
}
|
|
38
|
+
async listCollections() {
|
|
39
|
+
return this.request("/api/collections");
|
|
40
|
+
}
|
|
41
|
+
async createCollection(params) {
|
|
42
|
+
return this.request("/api/collections", {
|
|
43
|
+
method: "POST",
|
|
44
|
+
body: JSON.stringify(params),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
async deployFiles(prototypeId, files, commitMessage) {
|
|
48
|
+
return this.request(`/api/prototypes/${prototypeId}/deploy-code`, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
body: JSON.stringify({ files, commitMessage }),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
37
53
|
async listPrototypes() {
|
|
38
54
|
return this.request("/api/prototypes");
|
|
39
55
|
}
|
|
@@ -49,6 +65,31 @@ class VibesharingClient {
|
|
|
49
65
|
body: JSON.stringify({ projectId, content }),
|
|
50
66
|
});
|
|
51
67
|
}
|
|
68
|
+
async verifyToken() {
|
|
69
|
+
const url = `${this.baseUrl}/api/prototypes`;
|
|
70
|
+
const response = await fetch(url, {
|
|
71
|
+
headers: {
|
|
72
|
+
"Content-Type": "application/json",
|
|
73
|
+
Authorization: `Bearer ${this.token}`,
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
78
|
+
return { valid: false, error: error.error || `API error: ${response.status}` };
|
|
79
|
+
}
|
|
80
|
+
const data = await response.json();
|
|
81
|
+
return { valid: true, prototypeCount: (data.prototypes || []).length };
|
|
82
|
+
}
|
|
83
|
+
async uploadSource(prototypeId, sourceCode, filename, storageOption) {
|
|
84
|
+
return this.request(`/api/prototypes/${prototypeId}/source`, {
|
|
85
|
+
method: "POST",
|
|
86
|
+
body: JSON.stringify({
|
|
87
|
+
source_code: sourceCode,
|
|
88
|
+
filename: filename || "page.tsx",
|
|
89
|
+
storage_option: storageOption || "permanent",
|
|
90
|
+
}),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
52
93
|
async deployPrototype(params) {
|
|
53
94
|
return this.request("/api/deploy/code", {
|
|
54
95
|
method: "POST",
|
|
@@ -60,9 +101,38 @@ class VibesharingClient {
|
|
|
60
101
|
}),
|
|
61
102
|
});
|
|
62
103
|
}
|
|
104
|
+
async importRepo(prototypeId, repoUrl) {
|
|
105
|
+
return this.request("/api/git/import-repo", {
|
|
106
|
+
method: "POST",
|
|
107
|
+
body: JSON.stringify({ prototypeId, repoUrl }),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
async addContextLink(params) {
|
|
111
|
+
return this.request("/api/context-links", {
|
|
112
|
+
method: "POST",
|
|
113
|
+
body: JSON.stringify({
|
|
114
|
+
folder_id: params.folderId || null,
|
|
115
|
+
project_id: params.projectId || null,
|
|
116
|
+
title: params.title,
|
|
117
|
+
url: params.url || null,
|
|
118
|
+
note: params.note || null,
|
|
119
|
+
}),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
async listContextLinks(params) {
|
|
123
|
+
const param = params.folderId
|
|
124
|
+
? `folderId=${params.folderId}`
|
|
125
|
+
: `projectId=${params.projectId}`;
|
|
126
|
+
return this.request(`/api/context-links?${param}`);
|
|
127
|
+
}
|
|
128
|
+
async removeContextLink(linkId) {
|
|
129
|
+
return this.request(`/api/context-links/${linkId}`, {
|
|
130
|
+
method: "DELETE",
|
|
131
|
+
});
|
|
132
|
+
}
|
|
63
133
|
}
|
|
64
134
|
// Get configuration from environment
|
|
65
|
-
const VIBESHARING_URL = process.env.VIBESHARING_URL || "https://vibesharing.app";
|
|
135
|
+
const VIBESHARING_URL = process.env.VIBESHARING_URL || "https://www.vibesharing.app";
|
|
66
136
|
const VIBESHARING_TOKEN = process.env.VIBESHARING_TOKEN;
|
|
67
137
|
if (!VIBESHARING_TOKEN) {
|
|
68
138
|
console.error("Error: VIBESHARING_TOKEN environment variable is required");
|
|
@@ -86,7 +156,7 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
86
156
|
tools: [
|
|
87
157
|
{
|
|
88
158
|
name: "register_prototype",
|
|
89
|
-
description: "Register a new prototype on VibeSharing. Use this after deploying a prototype to Vercel, Netlify, or any hosting service. Returns the VibeSharing URL where the team can view and leave feedback.",
|
|
159
|
+
description: "Register a new prototype on VibeSharing. Use this after deploying a prototype to Vercel, Netlify, or any hosting service. Optionally upload source code so colleagues can download it. Returns the VibeSharing URL where the team can view and leave feedback.",
|
|
90
160
|
inputSchema: {
|
|
91
161
|
type: "object",
|
|
92
162
|
properties: {
|
|
@@ -106,6 +176,18 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
106
176
|
type: "string",
|
|
107
177
|
description: "Optional: ID of parent project if this is a version/iteration",
|
|
108
178
|
},
|
|
179
|
+
collection_id: {
|
|
180
|
+
type: "string",
|
|
181
|
+
description: "Optional: ID of collection (folder) to place this prototype in. Use list_collections to find the right ID.",
|
|
182
|
+
},
|
|
183
|
+
source_code: {
|
|
184
|
+
type: "string",
|
|
185
|
+
description: "Optional: Source code to upload to VibeSharing. Colleagues can download this from the prototype page.",
|
|
186
|
+
},
|
|
187
|
+
source_filename: {
|
|
188
|
+
type: "string",
|
|
189
|
+
description: "Optional: Filename for uploaded source (default: 'page.tsx')",
|
|
190
|
+
},
|
|
109
191
|
},
|
|
110
192
|
required: ["name"],
|
|
111
193
|
},
|
|
@@ -118,6 +200,14 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
118
200
|
properties: {},
|
|
119
201
|
},
|
|
120
202
|
},
|
|
203
|
+
{
|
|
204
|
+
name: "list_collections",
|
|
205
|
+
description: "List all collections (folders) in your VibeSharing organization. Use this to find the collection_id when registering prototypes.",
|
|
206
|
+
inputSchema: {
|
|
207
|
+
type: "object",
|
|
208
|
+
properties: {},
|
|
209
|
+
},
|
|
210
|
+
},
|
|
121
211
|
{
|
|
122
212
|
name: "get_feedback",
|
|
123
213
|
description: "Get feedback and comments for a specific prototype. Use this to see what the team thinks about a prototype.",
|
|
@@ -134,7 +224,7 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
134
224
|
},
|
|
135
225
|
{
|
|
136
226
|
name: "sync_context",
|
|
137
|
-
description: "Sync your CLAUDE.md or project context to VibeSharing. This helps maintain context across AI sessions and team members.",
|
|
227
|
+
description: "Sync your CLAUDE.md, AGENTS.md, or project context to VibeSharing. This helps maintain context across AI sessions and team members.",
|
|
138
228
|
inputSchema: {
|
|
139
229
|
type: "object",
|
|
140
230
|
properties: {
|
|
@@ -144,12 +234,46 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
144
234
|
},
|
|
145
235
|
content: {
|
|
146
236
|
type: "string",
|
|
147
|
-
description: "The context content (typically contents of CLAUDE.md)",
|
|
237
|
+
description: "The context content (typically contents of CLAUDE.md or AGENTS.md)",
|
|
148
238
|
},
|
|
149
239
|
},
|
|
150
240
|
required: ["project_id", "content"],
|
|
151
241
|
},
|
|
152
242
|
},
|
|
243
|
+
{
|
|
244
|
+
name: "verify_token",
|
|
245
|
+
description: "Verify that your VibeSharing deploy token is valid. Use this to check connectivity and authentication before other operations.",
|
|
246
|
+
inputSchema: {
|
|
247
|
+
type: "object",
|
|
248
|
+
properties: {},
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: "upload_source",
|
|
253
|
+
description: "Upload source code for an existing prototype on VibeSharing. Colleagues can then download the source from the prototype page. Use this when you want to share code without deploying it.",
|
|
254
|
+
inputSchema: {
|
|
255
|
+
type: "object",
|
|
256
|
+
properties: {
|
|
257
|
+
prototype_id: {
|
|
258
|
+
type: "string",
|
|
259
|
+
description: "The VibeSharing prototype ID to upload source code to",
|
|
260
|
+
},
|
|
261
|
+
source_code: {
|
|
262
|
+
type: "string",
|
|
263
|
+
description: "The source code to upload",
|
|
264
|
+
},
|
|
265
|
+
filename: {
|
|
266
|
+
type: "string",
|
|
267
|
+
description: "Optional: Filename for the source (default: 'page.tsx')",
|
|
268
|
+
},
|
|
269
|
+
storage_option: {
|
|
270
|
+
type: "string",
|
|
271
|
+
description: "Optional: 'permanent' (default), 'auto-delete' (7 days), or 'delete-on-download'",
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
required: ["prototype_id", "source_code"],
|
|
275
|
+
},
|
|
276
|
+
},
|
|
153
277
|
{
|
|
154
278
|
name: "deploy_prototype",
|
|
155
279
|
description: "Deploy code directly to VibeSharing. This deploys your code to Vercel and registers it as a prototype in one step. Use this when you've just built something and want to share it with the team immediately.",
|
|
@@ -172,6 +296,155 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
172
296
|
required: ["code", "name"],
|
|
173
297
|
},
|
|
174
298
|
},
|
|
299
|
+
{
|
|
300
|
+
name: "create_collection",
|
|
301
|
+
description: "Create a new collection in your VibeSharing organization. Collections group related projects and prototypes. Use this before deploying a prototype if you need a new collection to put it in.",
|
|
302
|
+
inputSchema: {
|
|
303
|
+
type: "object",
|
|
304
|
+
properties: {
|
|
305
|
+
name: {
|
|
306
|
+
type: "string",
|
|
307
|
+
description: "Name for the collection (e.g., 'Hero Use Cases', 'Compliance Hub')",
|
|
308
|
+
},
|
|
309
|
+
description: {
|
|
310
|
+
type: "string",
|
|
311
|
+
description: "Optional: Brief description of this collection",
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
required: ["name"],
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
name: "deploy_files",
|
|
319
|
+
description: "Deploy a multi-file Next.js project to VibeSharing. This pushes files to a GitHub repo, deploys to Vercel, and makes the prototype live. Use this for deploying a full project directory (not just a single code string). Requires an existing prototype ID — create one first with register_prototype.",
|
|
320
|
+
inputSchema: {
|
|
321
|
+
type: "object",
|
|
322
|
+
properties: {
|
|
323
|
+
prototype_id: {
|
|
324
|
+
type: "string",
|
|
325
|
+
description: "The VibeSharing prototype ID to deploy to",
|
|
326
|
+
},
|
|
327
|
+
files: {
|
|
328
|
+
type: "array",
|
|
329
|
+
items: {
|
|
330
|
+
type: "object",
|
|
331
|
+
properties: {
|
|
332
|
+
path: {
|
|
333
|
+
type: "string",
|
|
334
|
+
description: "File path relative to project root (e.g., 'app/page.tsx')",
|
|
335
|
+
},
|
|
336
|
+
content: {
|
|
337
|
+
type: "string",
|
|
338
|
+
description: "File content",
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
required: ["path", "content"],
|
|
342
|
+
},
|
|
343
|
+
description: "Array of files to deploy",
|
|
344
|
+
},
|
|
345
|
+
commit_message: {
|
|
346
|
+
type: "string",
|
|
347
|
+
description: "Optional: Git commit message (default: 'Deploy via MCP')",
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
required: ["prototype_id", "files"],
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
name: "import_repo",
|
|
355
|
+
description: "Import an existing GitHub repo into VibeSharing. Pulls the code into a VibeSharing-hosted repo and deploys it to Vercel automatically. Use this when you already have a repo on GitHub and want to share it as a prototype. If no prototype_id is provided, a new prototype is created automatically.",
|
|
356
|
+
inputSchema: {
|
|
357
|
+
type: "object",
|
|
358
|
+
properties: {
|
|
359
|
+
repo_url: {
|
|
360
|
+
type: "string",
|
|
361
|
+
description: "GitHub repo URL (e.g., 'https://github.com/my-org/my-repo')",
|
|
362
|
+
},
|
|
363
|
+
name: {
|
|
364
|
+
type: "string",
|
|
365
|
+
description: "Optional: Name for the prototype. Defaults to the repo name if not provided.",
|
|
366
|
+
},
|
|
367
|
+
prototype_id: {
|
|
368
|
+
type: "string",
|
|
369
|
+
description: "Optional: Existing VibeSharing prototype ID. If not provided, a new prototype is created.",
|
|
370
|
+
},
|
|
371
|
+
collection_id: {
|
|
372
|
+
type: "string",
|
|
373
|
+
description: "Optional: Collection (folder) ID to place the prototype in. Use list_collections to find IDs.",
|
|
374
|
+
},
|
|
375
|
+
parent_project_id: {
|
|
376
|
+
type: "string",
|
|
377
|
+
description: "Optional: Parent project ID if this is a version/iteration of an existing project.",
|
|
378
|
+
},
|
|
379
|
+
description: {
|
|
380
|
+
type: "string",
|
|
381
|
+
description: "Optional: Description of the prototype.",
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
required: ["repo_url"],
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
name: "add_context_link",
|
|
389
|
+
description: "Attach a reference link or note to a collection or project/prototype. Use this to add links to Figma designs, PRDs, Confluence docs, or free-text notes that provide context for reviewers.",
|
|
390
|
+
inputSchema: {
|
|
391
|
+
type: "object",
|
|
392
|
+
properties: {
|
|
393
|
+
folder_id: {
|
|
394
|
+
type: "string",
|
|
395
|
+
description: "Collection (folder) ID to attach the link to. Provide either folder_id or project_id.",
|
|
396
|
+
},
|
|
397
|
+
project_id: {
|
|
398
|
+
type: "string",
|
|
399
|
+
description: "Project or prototype ID to attach the link to. Provide either folder_id or project_id.",
|
|
400
|
+
},
|
|
401
|
+
title: {
|
|
402
|
+
type: "string",
|
|
403
|
+
description: "Title for the reference (e.g., 'Design Spec', 'PRD', 'User Flow Diagram')",
|
|
404
|
+
},
|
|
405
|
+
url: {
|
|
406
|
+
type: "string",
|
|
407
|
+
description: "Optional: URL to the reference material (Figma, Confluence, Google Docs, etc.). Omit for free-text notes.",
|
|
408
|
+
},
|
|
409
|
+
note: {
|
|
410
|
+
type: "string",
|
|
411
|
+
description: "Optional: Description or notes about this reference",
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
required: ["title"],
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
name: "list_context_links",
|
|
419
|
+
description: "List all reference links and notes attached to a collection or project/prototype.",
|
|
420
|
+
inputSchema: {
|
|
421
|
+
type: "object",
|
|
422
|
+
properties: {
|
|
423
|
+
folder_id: {
|
|
424
|
+
type: "string",
|
|
425
|
+
description: "Collection (folder) ID. Provide either folder_id or project_id.",
|
|
426
|
+
},
|
|
427
|
+
project_id: {
|
|
428
|
+
type: "string",
|
|
429
|
+
description: "Project or prototype ID. Provide either folder_id or project_id.",
|
|
430
|
+
},
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
name: "remove_context_link",
|
|
436
|
+
description: "Remove a reference link or note by its ID.",
|
|
437
|
+
inputSchema: {
|
|
438
|
+
type: "object",
|
|
439
|
+
properties: {
|
|
440
|
+
link_id: {
|
|
441
|
+
type: "string",
|
|
442
|
+
description: "The ID of the context link to remove",
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
required: ["link_id"],
|
|
446
|
+
},
|
|
447
|
+
},
|
|
175
448
|
],
|
|
176
449
|
};
|
|
177
450
|
});
|
|
@@ -182,12 +455,25 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
182
455
|
switch (name) {
|
|
183
456
|
case "register_prototype": {
|
|
184
457
|
const params = args;
|
|
185
|
-
const
|
|
458
|
+
const { source_code, source_filename, ...registerParams } = params;
|
|
459
|
+
const result = await client.registerPrototype(registerParams);
|
|
460
|
+
const protoId = result.prototype?.id;
|
|
461
|
+
// Upload source code if provided
|
|
462
|
+
let sourceInfo = "";
|
|
463
|
+
if (source_code && protoId) {
|
|
464
|
+
try {
|
|
465
|
+
const sourceResult = await client.uploadSource(protoId, source_code, source_filename);
|
|
466
|
+
sourceInfo = `\nSource code uploaded (${sourceResult.source?.size || source_code.length} chars). Colleagues can download it from the prototype page.`;
|
|
467
|
+
}
|
|
468
|
+
catch (err) {
|
|
469
|
+
sourceInfo = `\nWarning: Source upload failed: ${err instanceof Error ? err.message : "Unknown error"}`;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
186
472
|
return {
|
|
187
473
|
content: [
|
|
188
474
|
{
|
|
189
475
|
type: "text",
|
|
190
|
-
text: `Prototype registered successfully!\n\nName: ${result.
|
|
476
|
+
text: `Prototype registered successfully!\n\nName: ${result.prototype?.name || params.name}\nVibeSharing URL: ${VIBESHARING_URL}/dashboard/projects/${protoId}\n${params.external_url ? `Live URL: ${params.external_url}` : ""}${sourceInfo}\n\nYour team can now view and leave feedback on this prototype.`,
|
|
191
477
|
},
|
|
192
478
|
],
|
|
193
479
|
};
|
|
@@ -217,6 +503,31 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
217
503
|
],
|
|
218
504
|
};
|
|
219
505
|
}
|
|
506
|
+
case "list_collections": {
|
|
507
|
+
const result = await client.listCollections();
|
|
508
|
+
const collections = result.collections || [];
|
|
509
|
+
if (collections.length === 0) {
|
|
510
|
+
return {
|
|
511
|
+
content: [
|
|
512
|
+
{
|
|
513
|
+
type: "text",
|
|
514
|
+
text: "No collections found. Create one in the VibeSharing dashboard first.",
|
|
515
|
+
},
|
|
516
|
+
],
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
const list = collections
|
|
520
|
+
.map((c) => `- ${c.name}\n ID: ${c.id}${c.description ? `\n ${c.description}` : ""}`)
|
|
521
|
+
.join("\n\n");
|
|
522
|
+
return {
|
|
523
|
+
content: [
|
|
524
|
+
{
|
|
525
|
+
type: "text",
|
|
526
|
+
text: `Found ${collections.length} collection(s):\n\n${list}`,
|
|
527
|
+
},
|
|
528
|
+
],
|
|
529
|
+
};
|
|
530
|
+
}
|
|
220
531
|
case "get_feedback": {
|
|
221
532
|
const { project_id } = args;
|
|
222
533
|
const result = await client.getFeedback(project_id);
|
|
@@ -261,6 +572,42 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
261
572
|
],
|
|
262
573
|
};
|
|
263
574
|
}
|
|
575
|
+
case "verify_token": {
|
|
576
|
+
const result = await client.verifyToken();
|
|
577
|
+
if (result.valid) {
|
|
578
|
+
return {
|
|
579
|
+
content: [
|
|
580
|
+
{
|
|
581
|
+
type: "text",
|
|
582
|
+
text: `Token is valid! Connected to ${VIBESHARING_URL}\n\nYour organization has ${result.prototypeCount} prototype(s).`,
|
|
583
|
+
},
|
|
584
|
+
],
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
return {
|
|
589
|
+
content: [
|
|
590
|
+
{
|
|
591
|
+
type: "text",
|
|
592
|
+
text: `Token is invalid: ${result.error}\n\nGet a new deploy token from VibeSharing → Dashboard → Account Settings.\nThen update your MCP config:\n claude mcp remove vibesharing\n claude mcp add vibesharing -e VIBESHARING_TOKEN=vs_YOUR_NEW_TOKEN -- node /path/to/mcp-server/dist/index.js`,
|
|
593
|
+
},
|
|
594
|
+
],
|
|
595
|
+
isError: true,
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
case "upload_source": {
|
|
600
|
+
const { prototype_id, source_code, filename, storage_option } = args;
|
|
601
|
+
const result = await client.uploadSource(prototype_id, source_code, filename, storage_option);
|
|
602
|
+
return {
|
|
603
|
+
content: [
|
|
604
|
+
{
|
|
605
|
+
type: "text",
|
|
606
|
+
text: `Source code uploaded successfully!\n\nPrototype ID: ${prototype_id}\nFilename: ${result.source?.filename || filename || "page.tsx"}\nSize: ${result.source?.size || source_code.length} characters\nStorage: ${result.source?.storage_option || storage_option || "permanent"}\n\nColleagues can download this from: ${VIBESHARING_URL}/dashboard/projects/${prototype_id}`,
|
|
607
|
+
},
|
|
608
|
+
],
|
|
609
|
+
};
|
|
610
|
+
}
|
|
264
611
|
case "deploy_prototype": {
|
|
265
612
|
const { code, name, prototype_id } = args;
|
|
266
613
|
// If no prototype_id, first register a new prototype
|
|
@@ -289,7 +636,155 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
289
636
|
content: [
|
|
290
637
|
{
|
|
291
638
|
type: "text",
|
|
292
|
-
text: `Deployed successfully!\n\nLive URL: ${result.deployedUrl}\nVibeSharing: ${VIBESHARING_URL}/dashboard/projects/${prototypeId}\n\nYour team can now view the prototype and leave feedback.${result.contextImported ? "\n\
|
|
639
|
+
text: `Deployed successfully!\n\nLive URL: ${result.deployedUrl}\nVibeSharing: ${VIBESHARING_URL}/dashboard/projects/${prototypeId}\n\nYour team can now view the prototype and leave feedback.${result.contextImported ? "\n\nProject context was automatically imported." : ""}`,
|
|
640
|
+
},
|
|
641
|
+
],
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
case "create_collection": {
|
|
645
|
+
const { name: collName, description: collDesc } = args;
|
|
646
|
+
const collResult = await client.createCollection({
|
|
647
|
+
name: collName,
|
|
648
|
+
description: collDesc,
|
|
649
|
+
});
|
|
650
|
+
const coll = collResult.collection;
|
|
651
|
+
return {
|
|
652
|
+
content: [
|
|
653
|
+
{
|
|
654
|
+
type: "text",
|
|
655
|
+
text: `Collection created!\n\nName: ${coll.name}\nID: ${coll.id}\nSlug: ${coll.slug}\n\nYou can now use this collection_id when registering prototypes with register_prototype.`,
|
|
656
|
+
},
|
|
657
|
+
],
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
case "deploy_files": {
|
|
661
|
+
const { prototype_id: deployProtoId, files, commit_message } = args;
|
|
662
|
+
const deployResult = await client.deployFiles(deployProtoId, files, commit_message || "Deploy via MCP");
|
|
663
|
+
return {
|
|
664
|
+
content: [
|
|
665
|
+
{
|
|
666
|
+
type: "text",
|
|
667
|
+
text: `Deployed ${files.length} files!\n\nLive URL: ${deployResult.deployUrl || "Deploying..."}\nRepo: ${deployResult.repoUrl || "N/A"}\nCommit: ${deployResult.commitSha || "N/A"}\n\nVibeSharing: ${VIBESHARING_URL}/dashboard/projects/${deployProtoId}\n\nYour team can now view the prototype and leave feedback.`,
|
|
668
|
+
},
|
|
669
|
+
],
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
case "import_repo": {
|
|
673
|
+
const { repo_url, name: importName, prototype_id: importProtoId, collection_id: importCollectionId, parent_project_id: importParentId, description: importDesc, } = args;
|
|
674
|
+
// Auto-create prototype if no ID provided
|
|
675
|
+
let protoId = importProtoId;
|
|
676
|
+
if (!protoId) {
|
|
677
|
+
// Derive name from repo URL if not provided
|
|
678
|
+
const repoName = repo_url.replace(/\.git$/, "").split("/").pop() || "imported-prototype";
|
|
679
|
+
const protoName = importName || repoName.replace(/[-_]+/g, " ").replace(/\b\w/g, c => c.toUpperCase());
|
|
680
|
+
const registered = await client.registerPrototype({
|
|
681
|
+
name: protoName,
|
|
682
|
+
description: importDesc || `Imported from ${repo_url}`,
|
|
683
|
+
collection_id: importCollectionId,
|
|
684
|
+
parent_project_id: importParentId,
|
|
685
|
+
});
|
|
686
|
+
protoId = registered.prototype?.id;
|
|
687
|
+
}
|
|
688
|
+
if (!protoId) {
|
|
689
|
+
return {
|
|
690
|
+
content: [
|
|
691
|
+
{
|
|
692
|
+
type: "text",
|
|
693
|
+
text: "Error: Could not create prototype. Please try again.",
|
|
694
|
+
},
|
|
695
|
+
],
|
|
696
|
+
isError: true,
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
const importResult = await client.importRepo(protoId, repo_url);
|
|
700
|
+
return {
|
|
701
|
+
content: [
|
|
702
|
+
{
|
|
703
|
+
type: "text",
|
|
704
|
+
text: `Repo imported and deploying!\n\nRepo: ${importResult.repoUrl}\nSource: ${repo_url}\nLive URL: ${importResult.deployUrl}\nVibeSharing: ${VIBESHARING_URL}/dashboard/projects/${protoId}\nFiles imported: ${importResult.fileCount || "unknown"}\n\nPushes to the VibeSharing repo will auto-deploy to Vercel.`,
|
|
705
|
+
},
|
|
706
|
+
],
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
case "add_context_link": {
|
|
710
|
+
const { folder_id, project_id, title, url, note } = args;
|
|
711
|
+
if (!folder_id && !project_id) {
|
|
712
|
+
return {
|
|
713
|
+
content: [
|
|
714
|
+
{
|
|
715
|
+
type: "text",
|
|
716
|
+
text: "Error: Either folder_id or project_id is required.",
|
|
717
|
+
},
|
|
718
|
+
],
|
|
719
|
+
isError: true,
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
const result = await client.addContextLink({
|
|
723
|
+
folderId: folder_id,
|
|
724
|
+
projectId: project_id,
|
|
725
|
+
title,
|
|
726
|
+
url,
|
|
727
|
+
note,
|
|
728
|
+
});
|
|
729
|
+
const parentType = folder_id ? "collection" : "project";
|
|
730
|
+
const parentId = folder_id || project_id;
|
|
731
|
+
return {
|
|
732
|
+
content: [
|
|
733
|
+
{
|
|
734
|
+
type: "text",
|
|
735
|
+
text: `Reference link added successfully!\n\nTitle: ${title}${url ? `\nURL: ${url}` : ""}${note ? `\nNote: ${note}` : ""}\nAttached to ${parentType}: ${parentId}\nLink ID: ${result.link?.id}\n\nView it at: ${VIBESHARING_URL}/dashboard/${folder_id ? "folders" : "projects"}/${parentId}`,
|
|
736
|
+
},
|
|
737
|
+
],
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
case "list_context_links": {
|
|
741
|
+
const { folder_id, project_id } = args;
|
|
742
|
+
if (!folder_id && !project_id) {
|
|
743
|
+
return {
|
|
744
|
+
content: [
|
|
745
|
+
{
|
|
746
|
+
type: "text",
|
|
747
|
+
text: "Error: Either folder_id or project_id is required.",
|
|
748
|
+
},
|
|
749
|
+
],
|
|
750
|
+
isError: true,
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
const result = await client.listContextLinks({
|
|
754
|
+
folderId: folder_id,
|
|
755
|
+
projectId: project_id,
|
|
756
|
+
});
|
|
757
|
+
const links = result.links || [];
|
|
758
|
+
if (links.length === 0) {
|
|
759
|
+
return {
|
|
760
|
+
content: [
|
|
761
|
+
{
|
|
762
|
+
type: "text",
|
|
763
|
+
text: "No reference links found. Use add_context_link to attach Figma designs, PRDs, docs, or notes.",
|
|
764
|
+
},
|
|
765
|
+
],
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
const list = links
|
|
769
|
+
.map((l) => `- ${l.title}\n ID: ${l.id}${l.url ? `\n URL: ${l.url}` : " (note)"}${l.note ? `\n Note: ${l.note}` : ""}\n Added: ${new Date(l.created_at).toLocaleDateString()}`)
|
|
770
|
+
.join("\n\n");
|
|
771
|
+
return {
|
|
772
|
+
content: [
|
|
773
|
+
{
|
|
774
|
+
type: "text",
|
|
775
|
+
text: `Found ${links.length} reference link(s):\n\n${list}`,
|
|
776
|
+
},
|
|
777
|
+
],
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
case "remove_context_link": {
|
|
781
|
+
const { link_id } = args;
|
|
782
|
+
await client.removeContextLink(link_id);
|
|
783
|
+
return {
|
|
784
|
+
content: [
|
|
785
|
+
{
|
|
786
|
+
type: "text",
|
|
787
|
+
text: `Reference link ${link_id} removed successfully.`,
|
|
293
788
|
},
|
|
294
789
|
],
|
|
295
790
|
};
|
package/package.json
CHANGED