@vibesharingapp/mcp-server 0.1.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.
Files changed (3) hide show
  1. package/README.md +22 -7
  2. package/dist/index.js +568 -7
  3. 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) and grab your deploy token from Account Settings.
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
- | `register_prototype` | Register a deployed prototype with name, description, and URL |
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 sync** keeps context alive across sessions and team members
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,9 +65,74 @@ 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
+ }
93
+ async deployPrototype(params) {
94
+ return this.request("/api/deploy/code", {
95
+ method: "POST",
96
+ body: JSON.stringify({
97
+ code: params.code,
98
+ prototypeName: params.prototypeName,
99
+ prototypeId: params.prototypeId,
100
+ storageOption: "auto-delete", // Store source for 7 days for handoff
101
+ }),
102
+ });
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
+ }
52
133
  }
53
134
  // Get configuration from environment
54
- const VIBESHARING_URL = process.env.VIBESHARING_URL || "https://vibesharing.app";
135
+ const VIBESHARING_URL = process.env.VIBESHARING_URL || "https://www.vibesharing.app";
55
136
  const VIBESHARING_TOKEN = process.env.VIBESHARING_TOKEN;
56
137
  if (!VIBESHARING_TOKEN) {
57
138
  console.error("Error: VIBESHARING_TOKEN environment variable is required");
@@ -62,7 +143,7 @@ const client = new VibesharingClient(VIBESHARING_URL, VIBESHARING_TOKEN);
62
143
  // Create MCP server
63
144
  const server = new index_js_1.Server({
64
145
  name: "vibesharing",
65
- version: "0.1.0",
146
+ version: "0.2.0",
66
147
  }, {
67
148
  capabilities: {
68
149
  tools: {},
@@ -75,7 +156,7 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
75
156
  tools: [
76
157
  {
77
158
  name: "register_prototype",
78
- 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.",
79
160
  inputSchema: {
80
161
  type: "object",
81
162
  properties: {
@@ -95,6 +176,18 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
95
176
  type: "string",
96
177
  description: "Optional: ID of parent project if this is a version/iteration",
97
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
+ },
98
191
  },
99
192
  required: ["name"],
100
193
  },
@@ -107,6 +200,14 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
107
200
  properties: {},
108
201
  },
109
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
+ },
110
211
  {
111
212
  name: "get_feedback",
112
213
  description: "Get feedback and comments for a specific prototype. Use this to see what the team thinks about a prototype.",
@@ -123,7 +224,7 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
123
224
  },
124
225
  {
125
226
  name: "sync_context",
126
- 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.",
127
228
  inputSchema: {
128
229
  type: "object",
129
230
  properties: {
@@ -133,12 +234,217 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
133
234
  },
134
235
  content: {
135
236
  type: "string",
136
- description: "The context content (typically contents of CLAUDE.md)",
237
+ description: "The context content (typically contents of CLAUDE.md or AGENTS.md)",
137
238
  },
138
239
  },
139
240
  required: ["project_id", "content"],
140
241
  },
141
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
+ },
277
+ {
278
+ name: "deploy_prototype",
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.",
280
+ inputSchema: {
281
+ type: "object",
282
+ properties: {
283
+ code: {
284
+ type: "string",
285
+ description: "The React/Next.js page code to deploy (typically a page.tsx file)",
286
+ },
287
+ name: {
288
+ type: "string",
289
+ description: "Name for the prototype (e.g., 'Checkout Flow v2')",
290
+ },
291
+ prototype_id: {
292
+ type: "string",
293
+ description: "Optional: existing prototype ID to update (creates new if not provided)",
294
+ },
295
+ },
296
+ required: ["code", "name"],
297
+ },
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
+ },
142
448
  ],
143
449
  };
144
450
  });
@@ -149,12 +455,25 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
149
455
  switch (name) {
150
456
  case "register_prototype": {
151
457
  const params = args;
152
- const result = await client.registerPrototype(params);
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
+ }
153
472
  return {
154
473
  content: [
155
474
  {
156
475
  type: "text",
157
- text: `Prototype registered successfully!\n\nName: ${result.project?.name || params.name}\nVibeSharing URL: ${VIBESHARING_URL}/dashboard/projects/${result.project?.id}\n${params.external_url ? `Live URL: ${params.external_url}` : ""}\n\nYour team can now view and leave feedback on this prototype.`,
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.`,
158
477
  },
159
478
  ],
160
479
  };
@@ -184,6 +503,31 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
184
503
  ],
185
504
  };
186
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
+ }
187
531
  case "get_feedback": {
188
532
  const { project_id } = args;
189
533
  const result = await client.getFeedback(project_id);
@@ -228,6 +572,223 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
228
572
  ],
229
573
  };
230
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
+ }
611
+ case "deploy_prototype": {
612
+ const { code, name, prototype_id } = args;
613
+ // If no prototype_id, first register a new prototype
614
+ let prototypeId = prototype_id;
615
+ if (!prototypeId) {
616
+ const registered = await client.registerPrototype({ name });
617
+ prototypeId = registered.prototype?.id;
618
+ }
619
+ if (!prototypeId) {
620
+ return {
621
+ content: [
622
+ {
623
+ type: "text",
624
+ text: "Error: Could not create prototype. Please try again.",
625
+ },
626
+ ],
627
+ isError: true,
628
+ };
629
+ }
630
+ const result = await client.deployPrototype({
631
+ code,
632
+ prototypeName: name,
633
+ prototypeId,
634
+ });
635
+ return {
636
+ content: [
637
+ {
638
+ type: "text",
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.`,
788
+ },
789
+ ],
790
+ };
791
+ }
231
792
  default:
232
793
  return {
233
794
  content: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibesharingapp/mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "MCP server for VibeSharing - register prototypes and get feedback directly from Claude Code",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",