@vibesharingapp/mcp-server 0.5.0 → 0.6.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/dist/index.js +271 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -78,6 +78,7 @@ class VibesharingClient {
|
|
|
78
78
|
status: updates.status,
|
|
79
79
|
priority: updates.priority,
|
|
80
80
|
assignedTo: updates.assigned_to,
|
|
81
|
+
resolutionNote: updates.resolution_note,
|
|
81
82
|
}),
|
|
82
83
|
});
|
|
83
84
|
}
|
|
@@ -88,6 +89,7 @@ class VibesharingClient {
|
|
|
88
89
|
status: updates.status,
|
|
89
90
|
priority: updates.priority,
|
|
90
91
|
assignedTo: updates.assigned_to,
|
|
92
|
+
resolutionNote: updates.resolution_note,
|
|
91
93
|
}),
|
|
92
94
|
});
|
|
93
95
|
}
|
|
@@ -162,6 +164,31 @@ class VibesharingClient {
|
|
|
162
164
|
method: "DELETE",
|
|
163
165
|
});
|
|
164
166
|
}
|
|
167
|
+
async generateFeedbackTopics(projectId, topics) {
|
|
168
|
+
return this.request("/api/feedback-topics", {
|
|
169
|
+
method: "POST",
|
|
170
|
+
body: JSON.stringify({
|
|
171
|
+
projectId,
|
|
172
|
+
topics,
|
|
173
|
+
source: "auto",
|
|
174
|
+
}),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
async notifyFeedbackResolved(projectId, feedbackIds, deployUrl) {
|
|
178
|
+
return this.request("/api/feedback/notify-resolved", {
|
|
179
|
+
method: "POST",
|
|
180
|
+
body: JSON.stringify({ projectId, feedbackIds, deployUrl }),
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
async updateFeedbackBrief(projectId, brief, focus) {
|
|
184
|
+
const updates = { feedback_brief: brief };
|
|
185
|
+
if (focus)
|
|
186
|
+
updates.feedback_focus = focus;
|
|
187
|
+
return this.request(`/api/prototypes/${projectId}`, {
|
|
188
|
+
method: "PATCH",
|
|
189
|
+
body: JSON.stringify(updates),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
165
192
|
}
|
|
166
193
|
/**
|
|
167
194
|
* Simple fuzzy text matching. Scores based on:
|
|
@@ -207,8 +234,18 @@ function fuzzyMatch(query, items, getName, threshold = 0.3) {
|
|
|
207
234
|
.sort((a, b) => b.score - a.score);
|
|
208
235
|
}
|
|
209
236
|
// ---- Version tracking & What's New ----
|
|
210
|
-
const CURRENT_VERSION = "0.
|
|
237
|
+
const CURRENT_VERSION = "0.6.0";
|
|
211
238
|
const WHATS_NEW = {
|
|
239
|
+
"0.6.0": [
|
|
240
|
+
"🆕 VibeSharing MCP v0.6.0 — What's New:",
|
|
241
|
+
"",
|
|
242
|
+
"• Auto-generated feedback questions — After deploying, use generate_feedback_topics",
|
|
243
|
+
" to create 3-5 targeted questions that guide stakeholders toward useful feedback.",
|
|
244
|
+
" Questions are categorized by theme: vision alignment, feasibility, design fidelity,",
|
|
245
|
+
" or interaction design. Previous auto-generated questions are replaced on each deploy.",
|
|
246
|
+
"• Feedback briefs — Include a brief parameter to set context stakeholders see in the",
|
|
247
|
+
" Context tab. Also auto-extracted from ## Feedback Brief in CLAUDE.md at deploy time.",
|
|
248
|
+
].join("\n"),
|
|
212
249
|
"0.5.0": [
|
|
213
250
|
"🆕 VibeSharing MCP v0.5.0 — What's New:",
|
|
214
251
|
"",
|
|
@@ -272,7 +309,7 @@ const client = new VibesharingClient(VIBESHARING_URL, VIBESHARING_TOKEN);
|
|
|
272
309
|
// Create MCP server
|
|
273
310
|
const server = new index_js_1.Server({
|
|
274
311
|
name: "vibesharing",
|
|
275
|
-
version: "0.
|
|
312
|
+
version: "0.6.0",
|
|
276
313
|
}, {
|
|
277
314
|
capabilities: {
|
|
278
315
|
tools: {},
|
|
@@ -398,10 +435,55 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
398
435
|
type: "string",
|
|
399
436
|
description: "User ID to assign to. Use empty string to unassign.",
|
|
400
437
|
},
|
|
438
|
+
resolution_note: {
|
|
439
|
+
type: "string",
|
|
440
|
+
description: "Brief explanation of how the feedback was addressed (shown to the stakeholder). Only meaningful when status is resolved/wont_fix/deferred.",
|
|
441
|
+
},
|
|
401
442
|
},
|
|
402
443
|
required: ["feedback_ids"],
|
|
403
444
|
},
|
|
404
445
|
},
|
|
446
|
+
{
|
|
447
|
+
name: "close_feedback_loop",
|
|
448
|
+
description: "CALL THIS AFTER DEPLOYING when there is open feedback. Matches what you just built to open feedback items, resolves them with explanations, and notifies the original stakeholders with a personalized digest. The stakeholder sees exactly what happened to their feedback.\n\nFlow:\n1. Pull open feedback via get_feedback\n2. Look at what you built and match changes to feedback items\n3. Call this tool with the resolutions\n4. Stakeholders get email: 'Your feedback was addressed' with per-item explanations",
|
|
449
|
+
inputSchema: {
|
|
450
|
+
type: "object",
|
|
451
|
+
properties: {
|
|
452
|
+
project_id: {
|
|
453
|
+
type: "string",
|
|
454
|
+
description: "The VibeSharing prototype ID",
|
|
455
|
+
},
|
|
456
|
+
resolutions: {
|
|
457
|
+
type: "array",
|
|
458
|
+
items: {
|
|
459
|
+
type: "object",
|
|
460
|
+
properties: {
|
|
461
|
+
feedback_id: {
|
|
462
|
+
type: "string",
|
|
463
|
+
description: "The feedback item ID being resolved",
|
|
464
|
+
},
|
|
465
|
+
status: {
|
|
466
|
+
type: "string",
|
|
467
|
+
enum: ["resolved", "wont_fix", "deferred", "in_progress"],
|
|
468
|
+
description: "What happened: resolved (fixed), wont_fix (intentional), deferred (later), in_progress (started but not done)",
|
|
469
|
+
},
|
|
470
|
+
note: {
|
|
471
|
+
type: "string",
|
|
472
|
+
description: "Brief explanation of what changed or why it was deferred. This is shown directly to the stakeholder. Be specific: 'Nav restructured to separate admin and user flows' not 'Fixed the navigation'.",
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
required: ["feedback_id", "status", "note"],
|
|
476
|
+
},
|
|
477
|
+
description: "Array of feedback items to resolve with explanations",
|
|
478
|
+
},
|
|
479
|
+
deploy_url: {
|
|
480
|
+
type: "string",
|
|
481
|
+
description: "Optional: URL of the new deploy (included in notification so stakeholders can see the update)",
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
required: ["project_id", "resolutions"],
|
|
485
|
+
},
|
|
486
|
+
},
|
|
405
487
|
{
|
|
406
488
|
name: "sync_context",
|
|
407
489
|
description: "Sync your CLAUDE.md, AGENTS.md, or project context to VibeSharing. This helps maintain context across AI sessions and team members.",
|
|
@@ -654,6 +736,52 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
|
654
736
|
required: ["link_id"],
|
|
655
737
|
},
|
|
656
738
|
},
|
|
739
|
+
{
|
|
740
|
+
name: "generate_feedback_topics",
|
|
741
|
+
description: "Auto-generate feedback questions for a prototype based on what was built. IMPORTANT: Before generating questions, ask the user: 'What type of feedback is most important for this deploy?' and present these options:\n\n 1. Awareness only — just sharing progress, no feedback needed\n 2. Design direction — brand, visual, layout feedback\n 3. Technical feasibility — is this buildable, are these features doable\n 4. Vision alignment — does this match where we're going\n 5. Interaction design — usability, flow, UX patterns\n 6. Full review — all feedback welcome (default)\n\nUse their answer as the 'focus' parameter. If 'awareness', skip topic generation and just set the brief. Otherwise generate 3-5 questions, weighting toward the chosen focus theme.",
|
|
742
|
+
inputSchema: {
|
|
743
|
+
type: "object",
|
|
744
|
+
properties: {
|
|
745
|
+
project_id: {
|
|
746
|
+
type: "string",
|
|
747
|
+
description: "The VibeSharing prototype ID",
|
|
748
|
+
},
|
|
749
|
+
focus: {
|
|
750
|
+
type: "string",
|
|
751
|
+
enum: ["awareness", "design", "feasibility", "vision", "interaction", "full"],
|
|
752
|
+
description: "The type of feedback the designer wants. 'awareness' = no questions, just FYI. Others emphasize that theme. 'full' = all themes equally. Default: 'full'.",
|
|
753
|
+
},
|
|
754
|
+
brief: {
|
|
755
|
+
type: "string",
|
|
756
|
+
description: "A short (2-4 sentence) feedback brief explaining what this prototype is and what's ready for review. Stored on the prototype and shown to stakeholders in the Context tab.",
|
|
757
|
+
},
|
|
758
|
+
topics: {
|
|
759
|
+
type: "array",
|
|
760
|
+
items: {
|
|
761
|
+
type: "object",
|
|
762
|
+
properties: {
|
|
763
|
+
title: {
|
|
764
|
+
type: "string",
|
|
765
|
+
description: "The feedback question (e.g., 'Does this navigation flow match how your team actually works?')",
|
|
766
|
+
},
|
|
767
|
+
description: {
|
|
768
|
+
type: "string",
|
|
769
|
+
description: "Optional: Additional context for the question",
|
|
770
|
+
},
|
|
771
|
+
theme: {
|
|
772
|
+
type: "string",
|
|
773
|
+
enum: ["vision", "feasibility", "design", "interaction"],
|
|
774
|
+
description: "Question theme: 'vision' (alignment with goals), 'feasibility' (technical possibility), 'design' (brand/visual fidelity), 'interaction' (usability/UX patterns)",
|
|
775
|
+
},
|
|
776
|
+
},
|
|
777
|
+
required: ["title"],
|
|
778
|
+
},
|
|
779
|
+
description: "Array of feedback questions to create. Generate 3-5 based on what you built. Weight toward the focus theme (e.g., if focus is 'feasibility', 2-3 questions should be feasibility-themed). Not required when focus is 'awareness'.",
|
|
780
|
+
},
|
|
781
|
+
},
|
|
782
|
+
required: ["project_id"],
|
|
783
|
+
},
|
|
784
|
+
},
|
|
657
785
|
],
|
|
658
786
|
};
|
|
659
787
|
});
|
|
@@ -828,7 +956,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
828
956
|
};
|
|
829
957
|
}
|
|
830
958
|
case "triage_feedback": {
|
|
831
|
-
const { feedback_ids, status: newStatus, priority: newPriority, assigned_to: newAssignee } = args;
|
|
959
|
+
const { feedback_ids, status: newStatus, priority: newPriority, assigned_to: newAssignee, resolution_note } = args;
|
|
832
960
|
if (!feedback_ids || feedback_ids.length === 0) {
|
|
833
961
|
return {
|
|
834
962
|
content: [{ type: "text", text: "Error: feedback_ids array is required" }],
|
|
@@ -841,6 +969,8 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
841
969
|
updates.priority = newPriority;
|
|
842
970
|
if (newAssignee !== undefined)
|
|
843
971
|
updates.assigned_to = newAssignee || null;
|
|
972
|
+
if (resolution_note)
|
|
973
|
+
updates.resolution_note = resolution_note;
|
|
844
974
|
const result = await client.triageFeedback(feedback_ids, updates);
|
|
845
975
|
const changes = [];
|
|
846
976
|
if (newStatus)
|
|
@@ -849,6 +979,8 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
849
979
|
changes.push(`priority → ${newPriority}`);
|
|
850
980
|
if (newAssignee !== undefined)
|
|
851
981
|
changes.push(newAssignee ? `assigned → ${newAssignee}` : "unassigned");
|
|
982
|
+
if (resolution_note)
|
|
983
|
+
changes.push(`note: "${resolution_note}"`);
|
|
852
984
|
return {
|
|
853
985
|
content: [
|
|
854
986
|
{
|
|
@@ -858,6 +990,63 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
858
990
|
],
|
|
859
991
|
};
|
|
860
992
|
}
|
|
993
|
+
case "close_feedback_loop": {
|
|
994
|
+
const { project_id, resolutions, deploy_url } = args;
|
|
995
|
+
if (!resolutions || resolutions.length === 0) {
|
|
996
|
+
return {
|
|
997
|
+
content: [{ type: "text", text: "Error: At least one resolution is required." }],
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
// Step 1: Resolve each feedback item with its note
|
|
1001
|
+
const resolvedIds = [];
|
|
1002
|
+
const errors = [];
|
|
1003
|
+
for (const res of resolutions) {
|
|
1004
|
+
try {
|
|
1005
|
+
await client.triageFeedback([res.feedback_id], {
|
|
1006
|
+
status: res.status,
|
|
1007
|
+
resolution_note: res.note,
|
|
1008
|
+
});
|
|
1009
|
+
resolvedIds.push(res.feedback_id);
|
|
1010
|
+
}
|
|
1011
|
+
catch (err) {
|
|
1012
|
+
errors.push(`Failed to update ${res.feedback_id}: ${err}`);
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
// Step 2: Notify stakeholders
|
|
1016
|
+
let notifyResult = { notified: 0, emailed: 0, stakeholders: 0 };
|
|
1017
|
+
if (resolvedIds.length > 0) {
|
|
1018
|
+
try {
|
|
1019
|
+
notifyResult = await client.notifyFeedbackResolved(project_id, resolvedIds, deploy_url);
|
|
1020
|
+
}
|
|
1021
|
+
catch (err) {
|
|
1022
|
+
errors.push(`Notification failed: ${err}`);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
const statusLabels = {
|
|
1026
|
+
resolved: "Resolved",
|
|
1027
|
+
wont_fix: "Won't fix",
|
|
1028
|
+
deferred: "Deferred",
|
|
1029
|
+
in_progress: "In progress",
|
|
1030
|
+
};
|
|
1031
|
+
const lines = [
|
|
1032
|
+
`✅ Feedback loop closed — ${resolvedIds.length} item${resolvedIds.length === 1 ? "" : "s"} updated:`,
|
|
1033
|
+
"",
|
|
1034
|
+
...resolutions.map((r, i) => {
|
|
1035
|
+
const label = statusLabels[r.status] || r.status;
|
|
1036
|
+
const success = resolvedIds.includes(r.feedback_id) ? "✓" : "✗";
|
|
1037
|
+
return ` ${success} [${label}] ${r.note}`;
|
|
1038
|
+
}),
|
|
1039
|
+
];
|
|
1040
|
+
if (notifyResult.stakeholders > 0) {
|
|
1041
|
+
lines.push("", `📬 ${notifyResult.stakeholders} stakeholder${notifyResult.stakeholders === 1 ? "" : "s"} notified (${notifyResult.emailed} email${notifyResult.emailed === 1 ? "" : "s"} sent)`, "Each stakeholder received a personalized digest showing what happened to their specific feedback.");
|
|
1042
|
+
}
|
|
1043
|
+
if (errors.length > 0) {
|
|
1044
|
+
lines.push("", `⚠️ ${errors.length} error(s):`, ...errors.map(e => ` - ${e}`));
|
|
1045
|
+
}
|
|
1046
|
+
return {
|
|
1047
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
861
1050
|
case "sync_context": {
|
|
862
1051
|
const { project_id, content } = args;
|
|
863
1052
|
await client.syncContext(project_id, content);
|
|
@@ -1284,6 +1473,85 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
|
1284
1473
|
],
|
|
1285
1474
|
};
|
|
1286
1475
|
}
|
|
1476
|
+
case "generate_feedback_topics": {
|
|
1477
|
+
const { project_id, topics, brief, focus } = args;
|
|
1478
|
+
const feedbackFocus = focus || "full";
|
|
1479
|
+
const themeLabels = {
|
|
1480
|
+
vision: "Vision Alignment",
|
|
1481
|
+
feasibility: "Feasibility",
|
|
1482
|
+
design: "Design Fidelity",
|
|
1483
|
+
interaction: "Interaction Design",
|
|
1484
|
+
};
|
|
1485
|
+
const focusLabels = {
|
|
1486
|
+
awareness: "Awareness only",
|
|
1487
|
+
design: "Design direction",
|
|
1488
|
+
feasibility: "Technical feasibility",
|
|
1489
|
+
vision: "Vision alignment",
|
|
1490
|
+
interaction: "Interaction design",
|
|
1491
|
+
full: "Full review",
|
|
1492
|
+
};
|
|
1493
|
+
// Store brief and focus
|
|
1494
|
+
try {
|
|
1495
|
+
await client.updateFeedbackBrief(project_id, brief || "", feedbackFocus);
|
|
1496
|
+
}
|
|
1497
|
+
catch (err) {
|
|
1498
|
+
console.error("Failed to store feedback brief/focus:", err);
|
|
1499
|
+
}
|
|
1500
|
+
// Awareness mode: no questions, just the brief
|
|
1501
|
+
if (feedbackFocus === "awareness") {
|
|
1502
|
+
// Clear any existing auto-generated questions
|
|
1503
|
+
try {
|
|
1504
|
+
await client.generateFeedbackTopics(project_id, []);
|
|
1505
|
+
}
|
|
1506
|
+
catch {
|
|
1507
|
+
// OK if this fails — just means no old auto topics to clear
|
|
1508
|
+
}
|
|
1509
|
+
const lines = [
|
|
1510
|
+
`📢 Prototype set to awareness mode — no feedback questions will be shown.`,
|
|
1511
|
+
];
|
|
1512
|
+
if (brief) {
|
|
1513
|
+
lines.push("", `📋 Brief saved: "${brief.substring(0, 100)}${brief.length > 100 ? "..." : ""}"`);
|
|
1514
|
+
}
|
|
1515
|
+
lines.push("", "Stakeholders will see this as an FYI with the Context tab available.", "They can still leave general comments if they choose to.");
|
|
1516
|
+
return {
|
|
1517
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
1518
|
+
};
|
|
1519
|
+
}
|
|
1520
|
+
// All other modes: generate questions
|
|
1521
|
+
if (!topics || topics.length === 0) {
|
|
1522
|
+
return {
|
|
1523
|
+
content: [{ type: "text", text: "Error: At least one topic is required when focus is not 'awareness'." }],
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
// Sort topics: focused theme first, then others
|
|
1527
|
+
const sortedTopics = feedbackFocus !== "full"
|
|
1528
|
+
? [
|
|
1529
|
+
...topics.filter(t => t.theme === feedbackFocus),
|
|
1530
|
+
...topics.filter(t => t.theme !== feedbackFocus),
|
|
1531
|
+
]
|
|
1532
|
+
: topics;
|
|
1533
|
+
const result = await client.generateFeedbackTopics(project_id, sortedTopics);
|
|
1534
|
+
const created = result.topics || [];
|
|
1535
|
+
const lines = [
|
|
1536
|
+
`✅ Created ${created.length} feedback question${created.length === 1 ? "" : "s"} (focus: ${focusLabels[feedbackFocus] || feedbackFocus}):`,
|
|
1537
|
+
"",
|
|
1538
|
+
...created.map((t, i) => {
|
|
1539
|
+
const tag = t.theme ? ` [${themeLabels[t.theme] || t.theme}]` : "";
|
|
1540
|
+
const star = t.theme === feedbackFocus ? " ★" : "";
|
|
1541
|
+
return ` ${i + 1}. ${t.title}${tag}${star}`;
|
|
1542
|
+
}),
|
|
1543
|
+
];
|
|
1544
|
+
if (brief) {
|
|
1545
|
+
lines.push("", `📋 Feedback brief saved — stakeholders can see it in the Context tab.`);
|
|
1546
|
+
}
|
|
1547
|
+
if (feedbackFocus !== "full") {
|
|
1548
|
+
lines.push("", `${themeLabels[feedbackFocus] || feedbackFocus} questions are pinned to the top for stakeholders.`);
|
|
1549
|
+
}
|
|
1550
|
+
lines.push("", "Previous auto-generated questions were replaced. Manual questions are untouched.");
|
|
1551
|
+
return {
|
|
1552
|
+
content: [{ type: "text", text: lines.join("\n") }],
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1287
1555
|
default:
|
|
1288
1556
|
return {
|
|
1289
1557
|
content: [
|
package/package.json
CHANGED