@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.
Files changed (3) hide show
  1. package/README.md +22 -7
  2. package/dist/index.js +502 -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,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 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
+ }
186
472
  return {
187
473
  content: [
188
474
  {
189
475
  type: "text",
190
- 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.`,
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\nCLAUDE.md was automatically imported as context." : ""}`,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibesharingapp/mcp-server",
3
- "version": "0.2.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",