@ourroadmaps/mcp 0.30.1 → 0.31.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 (2) hide show
  1. package/dist/index.js +367 -55
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -776,13 +776,8 @@ var SLIDE_TYPES = [
776
776
  "title",
777
777
  "section_header",
778
778
  "bullets",
779
- "two_column",
780
- "comparison",
781
- "timeline",
782
779
  "image",
783
- "quote",
784
780
  "code",
785
- "thank_you",
786
781
  "mermaid",
787
782
  "paragraph"
788
783
  ];
@@ -799,46 +794,17 @@ var bulletsContentSchema = z13.object({
799
794
  title: z13.string().optional(),
800
795
  items: z13.array(z13.string()).default([])
801
796
  });
802
- var twoColumnContentSchema = z13.object({
803
- title: z13.string().optional(),
804
- left: z13.string().default(""),
805
- right: z13.string().default("")
806
- });
807
- var comparisonContentSchema = z13.object({
808
- leftLabel: z13.string().default(""),
809
- leftContent: z13.string().default(""),
810
- rightLabel: z13.string().default(""),
811
- rightContent: z13.string().default("")
812
- });
813
- var timelineStepSchema = z13.object({
814
- title: z13.string(),
815
- description: z13.string().optional()
816
- });
817
- var timelineContentSchema = z13.object({
818
- title: z13.string().optional(),
819
- steps: z13.array(timelineStepSchema).default([])
820
- });
821
797
  var imageContentSchema = z13.object({
822
798
  title: z13.string().optional(),
823
799
  imageUrl: z13.string().optional(),
824
800
  caption: z13.string().optional()
825
801
  });
826
- var quoteContentSchema = z13.object({
827
- quote: z13.string().default(""),
828
- attribution: z13.string().optional()
829
- });
830
802
  var codeContentSchema = z13.object({
831
803
  title: z13.string().optional(),
832
804
  code: z13.string().default(""),
833
805
  language: z13.string().optional(),
834
806
  highlightLines: z13.array(z13.number()).optional()
835
807
  });
836
- var thankYouContentSchema = z13.object({
837
- title: z13.string().default("Thank You"),
838
- subtitle: z13.string().optional(),
839
- ctaText: z13.string().optional(),
840
- ctaUrl: z13.string().optional()
841
- });
842
808
  var mermaidContentSchema = z13.object({
843
809
  title: z13.string().optional(),
844
810
  code: z13.string().default("")
@@ -851,13 +817,8 @@ var typedSlideContentSchema = z13.discriminatedUnion("type", [
851
817
  z13.object({ type: z13.literal("title"), ...titleContentSchema.shape }),
852
818
  z13.object({ type: z13.literal("section_header"), ...sectionHeaderContentSchema.shape }),
853
819
  z13.object({ type: z13.literal("bullets"), ...bulletsContentSchema.shape }),
854
- z13.object({ type: z13.literal("two_column"), ...twoColumnContentSchema.shape }),
855
- z13.object({ type: z13.literal("comparison"), ...comparisonContentSchema.shape }),
856
- z13.object({ type: z13.literal("timeline"), ...timelineContentSchema.shape }),
857
820
  z13.object({ type: z13.literal("image"), ...imageContentSchema.shape }),
858
- z13.object({ type: z13.literal("quote"), ...quoteContentSchema.shape }),
859
821
  z13.object({ type: z13.literal("code"), ...codeContentSchema.shape }),
860
- z13.object({ type: z13.literal("thank_you"), ...thankYouContentSchema.shape }),
861
822
  z13.object({ type: z13.literal("mermaid"), ...mermaidContentSchema.shape }),
862
823
  z13.object({ type: z13.literal("paragraph"), ...paragraphContentSchema.shape })
863
824
  ]);
@@ -983,6 +944,18 @@ var updateBrainstormNotesInput = {
983
944
  roadmapId: idField("roadmap item"),
984
945
  notes: z15.string().describe("The brainstorm notes content")
985
946
  };
947
+ var presentOptionsInput = {
948
+ question: z15.string().describe("The decision or question being presented to the user"),
949
+ options: z15.array(z15.object({
950
+ key: z15.string().describe("Short key like A, B, C"),
951
+ title: z15.string().describe("Option title"),
952
+ description: z15.string().describe("1-2 sentence description of the option")
953
+ })).min(2).max(5).describe("The options to present (2-5)"),
954
+ recommendation: z15.object({
955
+ key: z15.string().describe("Key of the recommended option"),
956
+ reason: z15.string().describe("Brief reason for the recommendation")
957
+ }).optional().describe("Which option is recommended and why")
958
+ };
986
959
  var searchFeaturesInput = {
987
960
  query: z15.string().optional().describe("Search query to match against name"),
988
961
  type: featureTypeSchema.optional().describe("Filter by type (feature or area)")
@@ -1089,16 +1062,7 @@ var deleteAudienceInput = {
1089
1062
  var getHistoryInput = {
1090
1063
  startDate: yyyyMmDdField("Start date in YYYY-MM-DD format"),
1091
1064
  endDate: yyyyMmDdField("End date in YYYY-MM-DD format"),
1092
- entityType: z15.enum([
1093
- "roadmap",
1094
- "feature",
1095
- "idea",
1096
- "prd",
1097
- "wireframe",
1098
- "product",
1099
- "audience",
1100
- "scenario"
1101
- ]).optional().describe("Filter to specific entity type")
1065
+ entityType: z15.enum(["roadmap", "feature", "idea", "prd", "wireframe", "product", "audience", "scenario"]).optional().describe("Filter to specific entity type")
1102
1066
  };
1103
1067
  var getHistorySummaryInput = {
1104
1068
  startDate: yyyyMmDdField("Start date in YYYY-MM-DD format"),
@@ -1143,7 +1107,18 @@ var createInitiativeInput = {
1143
1107
  horizon: horizonSchema.optional().describe('Planning horizon (defaults to "inbox")'),
1144
1108
  dateGranularity: dateGranularitySchema.optional().describe("Target date granularity: day, month, quarter, half-year, or year"),
1145
1109
  dateValue: z15.string().optional().describe('Target date value matching granularity (e.g., "2024-Q1", "2024-03")'),
1146
- targetDate: z15.string().optional().describe("Target date in YYYY-MM-DD format")
1110
+ targetDate: z15.string().optional().describe("Target date in YYYY-MM-DD format"),
1111
+ status: z15.enum(["on_track", "at_risk", "blocked", "paused"]).optional().describe("Project health status"),
1112
+ value: z15.number().int().min(1).max(3).optional().describe("Value rating (1-3 stars)"),
1113
+ effort: z15.enum(["xs", "s", "m", "l", "xl"]).optional().describe("Effort estimate (t-shirt size)"),
1114
+ target: z15.object({
1115
+ granularity: dateGranularitySchema,
1116
+ value: z15.string()
1117
+ }).optional().describe("Flexible target date"),
1118
+ deadline: z15.object({
1119
+ granularity: dateGranularitySchema,
1120
+ value: z15.string()
1121
+ }).optional().describe("Flexible deadline date")
1147
1122
  };
1148
1123
  var updateInitiativeInput = {
1149
1124
  id: idField("initiative to update"),
@@ -1153,7 +1128,18 @@ var updateInitiativeInput = {
1153
1128
  dateGranularity: dateGranularitySchema.nullable().optional().describe("New target date granularity (null to clear)"),
1154
1129
  dateValue: z15.string().nullable().optional().describe("New target date value (null to clear)"),
1155
1130
  targetDate: z15.string().nullable().optional().describe("New target date in YYYY-MM-DD format (null to clear)"),
1156
- order: z15.number().int().min(0).optional().describe("Sort order for prioritization (lower numbers appear first)")
1131
+ order: z15.number().int().min(0).optional().describe("Sort order for prioritization (lower numbers appear first)"),
1132
+ status: z15.enum(["on_track", "at_risk", "blocked", "paused"]).nullable().optional().describe("Project health status (null to clear)"),
1133
+ value: z15.number().int().min(1).max(3).nullable().optional().describe("Value rating (null to clear)"),
1134
+ effort: z15.enum(["xs", "s", "m", "l", "xl"]).nullable().optional().describe("Effort estimate (null to clear)"),
1135
+ target: z15.object({
1136
+ granularity: dateGranularitySchema,
1137
+ value: z15.string()
1138
+ }).nullable().optional().describe("Flexible target date (null to clear)"),
1139
+ deadline: z15.object({
1140
+ granularity: dateGranularitySchema,
1141
+ value: z15.string()
1142
+ }).nullable().optional().describe("Flexible deadline date (null to clear)")
1157
1143
  };
1158
1144
  var deleteInitiativeInput = {
1159
1145
  id: idField("initiative to delete")
@@ -1241,6 +1227,44 @@ var resolveFeedbackCommentInput = {
1241
1227
  sessionId: uuidField("feedback session"),
1242
1228
  commentId: uuidField("comment to resolve/unresolve")
1243
1229
  };
1230
+ var createPresentationFeedbackSessionInput = {
1231
+ presentationId: uuidField("presentation"),
1232
+ variantId: uuidField("variant to create feedback session for"),
1233
+ message: z15.string().optional().describe("Message shown to reviewers"),
1234
+ expiresInDays: z15.number().int().min(1).max(90).optional().describe("Number of days until the session expires (default 14)")
1235
+ };
1236
+ var listPresentationFeedbackSessionsInput = {
1237
+ presentationId: uuidField("presentation"),
1238
+ variantId: uuidField("variant")
1239
+ };
1240
+ var getPresentationFeedbackSummaryInput = {
1241
+ presentationId: uuidField("presentation"),
1242
+ variantId: uuidField("variant"),
1243
+ sessionId: uuidField("feedback session"),
1244
+ filter: z15.enum(["all", "unresolved", "resolved"]).optional().describe("Filter by resolved status (default: unresolved)")
1245
+ };
1246
+ var getPresentationFeedbackDetailInput = {
1247
+ presentationId: uuidField("presentation"),
1248
+ variantId: uuidField("variant"),
1249
+ sessionId: uuidField("feedback session"),
1250
+ feedbackId: z15.string().uuid().optional().describe("Optional: get detail for a single feedback item"),
1251
+ filter: z15.enum(["all", "unresolved", "resolved"]).optional().describe("Filter by resolved status (default: all). Ignored if feedbackId provided.")
1252
+ };
1253
+ var resolvePresentationFeedbackInput = {
1254
+ presentationId: uuidField("presentation"),
1255
+ variantId: uuidField("variant"),
1256
+ sessionId: uuidField("feedback session"),
1257
+ feedbackId: uuidField("feedback item to resolve/unresolve"),
1258
+ type: z15.enum(["slide", "overall"]).describe("Type of feedback item"),
1259
+ resolved: z15.boolean().describe("Set to true to resolve, false to unresolve")
1260
+ };
1261
+ var addPresentationReviewerInput = {
1262
+ presentationId: uuidField("presentation"),
1263
+ variantId: uuidField("variant"),
1264
+ sessionId: uuidField("feedback session"),
1265
+ name: z15.string().min(1).max(200).describe("Reviewer name"),
1266
+ email: z15.string().email().optional().describe("Reviewer email")
1267
+ };
1244
1268
  var searchExportsInput = {
1245
1269
  roadmapId: z15.string().uuid().optional().describe("Filter by roadmap item ID"),
1246
1270
  externalSystem: externalSystemSchema.optional().describe("Filter by external system"),
@@ -1330,8 +1354,8 @@ var getSlideInput = {
1330
1354
  };
1331
1355
  var createSlideInput = {
1332
1356
  variantId: idField("variant"),
1333
- slideType: slideTypeSchema.default("bullets").describe("The type of slide to create"),
1334
- content: z15.record(z15.unknown()).optional().describe('Type-specific content object. For bullets: {title, items: ["..."]}. For title: {title, subtitle}. For two_column: {title, left, right}. For quote: {quote, attribution}. For mermaid: {title, code: "graph TD; A-->B"}. For paragraph: {title, body}. Etc.'),
1357
+ slideType: z15.enum(SLIDE_TYPES).default("bullets").describe("The type of slide to create: title, section_header, bullets, image, code, mermaid, paragraph"),
1358
+ content: z15.record(z15.unknown()).optional().describe('Type-specific content object. For bullets: {title, items: ["..."]}. For title: {title, subtitle}. For image: {title, imageUrl, caption}. For code: {title, code, language}. For mermaid: {title, code: "graph TD; A-->B"}. For paragraph: {title, body}. For section_header: {title, subtitle}.'),
1335
1359
  speakerNotes: z15.string().nullable().optional().describe("Speaker notes for the slide")
1336
1360
  };
1337
1361
  var updateSlideInput = {
@@ -2055,6 +2079,39 @@ class ApiClient {
2055
2079
  });
2056
2080
  return response.data;
2057
2081
  }
2082
+ async createPresentationFeedbackSession(presentationId, variantId, data) {
2083
+ const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions`, {
2084
+ method: "POST",
2085
+ body: JSON.stringify(data)
2086
+ });
2087
+ return response.data;
2088
+ }
2089
+ async listPresentationFeedbackSessions(presentationId, variantId) {
2090
+ const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions`);
2091
+ return response.data;
2092
+ }
2093
+ async getPresentationFeedback(presentationId, variantId, sessionId) {
2094
+ const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/feedback`);
2095
+ return response.data;
2096
+ }
2097
+ async getPresentationFeedbackStats(presentationId, variantId, sessionId) {
2098
+ const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/stats`);
2099
+ return response.data;
2100
+ }
2101
+ async resolvePresentationFeedback(presentationId, variantId, sessionId, feedbackId, data) {
2102
+ const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/feedback/${feedbackId}/resolve`, {
2103
+ method: "PATCH",
2104
+ body: JSON.stringify(data)
2105
+ });
2106
+ return response.data;
2107
+ }
2108
+ async addPresentationReviewer(presentationId, variantId, sessionId, data) {
2109
+ const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/feedback-sessions/${sessionId}/invites`, {
2110
+ method: "POST",
2111
+ body: JSON.stringify(data)
2112
+ });
2113
+ return response.data;
2114
+ }
2058
2115
  async getVariantPresentationId(variantId) {
2059
2116
  const presentations = await this.listPresentations();
2060
2117
  for (const presentation2 of presentations.items) {
@@ -2182,6 +2239,12 @@ function registerAllTools(server) {
2182
2239
  registerDeleteSlide(server);
2183
2240
  registerReorderSlides(server);
2184
2241
  registerUploadSlideImage(server);
2242
+ registerCreatePresentationFeedbackSession(server);
2243
+ registerListPresentationFeedbackSessions(server);
2244
+ registerGetPresentationFeedbackSummary(server);
2245
+ registerGetPresentationFeedbackDetail(server);
2246
+ registerResolvePresentationFeedback(server);
2247
+ registerAddPresentationReviewer(server);
2185
2248
  }
2186
2249
  function registerGetWorkflows(server) {
2187
2250
  server.registerTool("get_workflows", {
@@ -4794,7 +4857,7 @@ function registerGetSlide(server) {
4794
4857
  }
4795
4858
  function registerCreateSlide(server) {
4796
4859
  server.registerTool("create_slide", {
4797
- description: "Create a new slide in a variant. Slide types: title (title + subtitle), section_header (title + subtitle), bullets (title + items array), two_column (title + left/right text), comparison (leftLabel + leftContent + rightLabel + rightContent), timeline (title + steps array of {title, description}), image (title + imageUrl + caption), quote (quote + attribution), code (title + code + language), thank_you (title + subtitle), mermaid (title + code with mermaid diagram syntax), paragraph (title + body with markdown text).",
4860
+ description: "Create a new slide in a variant. Slide types: title (title + subtitle), section_header (title + subtitle), bullets (title + items array), image (title + imageUrl + caption), code (title + code + language), mermaid (title + code with mermaid diagram syntax), paragraph (title + body with markdown text).",
4798
4861
  inputSchema: createSlideInput
4799
4862
  }, async ({
4800
4863
  variantId,
@@ -5021,7 +5084,9 @@ function registerCreateFeedbackSession(server) {
5021
5084
  const invite = session.invites[0];
5022
5085
  if (!invite) {
5023
5086
  return {
5024
- content: [{ type: "text", text: "Error: No invite was created for the session." }]
5087
+ content: [
5088
+ { type: "text", text: "Error: No invite was created for the session." }
5089
+ ]
5025
5090
  };
5026
5091
  }
5027
5092
  const reviewUrl = `https://app.ourroadmaps.com/prototype-review/${invite.token}`;
@@ -5206,6 +5271,253 @@ function registerResolveFeedbackComment(server) {
5206
5271
  };
5207
5272
  });
5208
5273
  }
5274
+ function registerCreatePresentationFeedbackSession(server) {
5275
+ server.registerTool("create_presentation_feedback_session", {
5276
+ description: "Create a feedback session for a presentation variant and get a shareable review link. Reviewers can leave per-slide comments and emoji reactions.",
5277
+ inputSchema: createPresentationFeedbackSessionInput
5278
+ }, async ({
5279
+ presentationId,
5280
+ variantId,
5281
+ message,
5282
+ expiresInDays
5283
+ }) => {
5284
+ const client2 = getApiClient();
5285
+ const session = await client2.createPresentationFeedbackSession(presentationId, variantId, {
5286
+ message,
5287
+ reviewerVisibility: true,
5288
+ expiresInDays,
5289
+ reviewers: [{ name: "Anonymous" }]
5290
+ });
5291
+ const invite = session.invites[0];
5292
+ if (!invite) {
5293
+ return {
5294
+ content: [
5295
+ { type: "text", text: "Error: No invite was created for the session." }
5296
+ ]
5297
+ };
5298
+ }
5299
+ const reviewUrl = `https://app.ourroadmaps.com/review/${invite.token}`;
5300
+ const expiryDate = new Date(session.expiresAt).toLocaleDateString("en-US", {
5301
+ weekday: "long",
5302
+ year: "numeric",
5303
+ month: "long",
5304
+ day: "numeric"
5305
+ });
5306
+ return {
5307
+ content: [
5308
+ {
5309
+ type: "text",
5310
+ text: JSON.stringify({
5311
+ success: true,
5312
+ sessionId: session.id,
5313
+ sessionName: session.name,
5314
+ reviewUrl,
5315
+ expiresAt: session.expiresAt,
5316
+ expiryDate
5317
+ }, null, 2)
5318
+ }
5319
+ ]
5320
+ };
5321
+ });
5322
+ }
5323
+ function registerListPresentationFeedbackSessions(server) {
5324
+ server.registerTool("list_presentation_feedback_sessions", {
5325
+ description: "List all feedback sessions for a presentation variant with invite counts and status.",
5326
+ inputSchema: listPresentationFeedbackSessionsInput
5327
+ }, async ({ presentationId, variantId }) => {
5328
+ const client2 = getApiClient();
5329
+ const sessions = await client2.listPresentationFeedbackSessions(presentationId, variantId);
5330
+ return {
5331
+ content: [
5332
+ {
5333
+ type: "text",
5334
+ text: JSON.stringify({
5335
+ sessions: sessions.map((s) => ({
5336
+ id: s.id,
5337
+ name: s.name,
5338
+ status: s.status,
5339
+ inviteCount: s.invites.length,
5340
+ expiresAt: s.expiresAt,
5341
+ createdAt: s.createdAt
5342
+ }))
5343
+ }, null, 2)
5344
+ }
5345
+ ]
5346
+ };
5347
+ });
5348
+ }
5349
+ function registerGetPresentationFeedbackSummary(server) {
5350
+ server.registerTool("get_presentation_feedback_summary", {
5351
+ description: "Get a human-readable summary of presentation feedback, grouped by slide. Shows reviewer names, comments, emoji reactions, and resolved status. Use this for a quick overview.",
5352
+ inputSchema: getPresentationFeedbackSummaryInput
5353
+ }, async ({
5354
+ presentationId,
5355
+ variantId,
5356
+ sessionId,
5357
+ filter
5358
+ }) => {
5359
+ const client2 = getApiClient();
5360
+ const [stats, feedback] = await Promise.all([
5361
+ client2.getPresentationFeedbackStats(presentationId, variantId, sessionId),
5362
+ client2.getPresentationFeedback(presentationId, variantId, sessionId)
5363
+ ]);
5364
+ const resolvedFilter = filter ?? "unresolved";
5365
+ const filtered = resolvedFilter === "all" ? feedback : feedback.filter((f) => resolvedFilter === "resolved" ? f.resolved : !f.resolved);
5366
+ if (filtered.length === 0) {
5367
+ return {
5368
+ content: [{ type: "text", text: "No feedback found matching the filter." }]
5369
+ };
5370
+ }
5371
+ const slideFeedback = filtered.filter((f) => f.type === "slide");
5372
+ const overallFeedback = filtered.filter((f) => f.type === "overall");
5373
+ const bySlide = new Map;
5374
+ for (const f of slideFeedback) {
5375
+ const key = f.slideId ?? "(unknown)";
5376
+ if (!bySlide.has(key))
5377
+ bySlide.set(key, []);
5378
+ bySlide.get(key).push(f);
5379
+ }
5380
+ let summary = `## Session (${stats.respondedCount}/${stats.totalInvites} responded, ${stats.unresolvedCount} unresolved)
5381
+
5382
+ `;
5383
+ const sortedSlides = [...bySlide.entries()].sort((a, b) => {
5384
+ const orderA = a[1][0]?.slideOrder ?? 0;
5385
+ const orderB = b[1][0]?.slideOrder ?? 0;
5386
+ return orderA - orderB;
5387
+ });
5388
+ for (const [, comments] of sortedSlides) {
5389
+ const first = comments[0];
5390
+ summary += `### Slide ${(first.slideOrder ?? 0) + 1}: "${first.slideTitle ?? "Untitled"}"
5391
+ `;
5392
+ for (const c of comments) {
5393
+ const status = c.resolved ? "RESOLVED" : "OPEN";
5394
+ summary += `- [${status}] by "${c.reviewerName}" — "${c.commentText ?? ""}"
5395
+ `;
5396
+ if (c.emojiReactions && c.emojiReactions.length > 0) {
5397
+ summary += ` Reactions: ${c.emojiReactions.join(", ")}
5398
+ `;
5399
+ }
5400
+ }
5401
+ summary += `
5402
+ `;
5403
+ }
5404
+ if (overallFeedback.length > 0) {
5405
+ summary += `### Overall Feedback
5406
+ `;
5407
+ for (const c of overallFeedback) {
5408
+ const status = c.resolved ? "RESOLVED" : "OPEN";
5409
+ summary += `- [${status}] by "${c.reviewerName}" — "${c.commentText ?? ""}"
5410
+ `;
5411
+ }
5412
+ }
5413
+ return {
5414
+ content: [{ type: "text", text: summary.trim() }]
5415
+ };
5416
+ });
5417
+ }
5418
+ function registerGetPresentationFeedbackDetail(server) {
5419
+ server.registerTool("get_presentation_feedback_detail", {
5420
+ description: "Get full raw feedback data for a presentation session, including slide IDs, emoji reactions, and resolved status. Use this when you need exact data to make targeted slide updates.",
5421
+ inputSchema: getPresentationFeedbackDetailInput
5422
+ }, async ({
5423
+ presentationId,
5424
+ variantId,
5425
+ sessionId,
5426
+ feedbackId,
5427
+ filter
5428
+ }) => {
5429
+ const client2 = getApiClient();
5430
+ const feedback = await client2.getPresentationFeedback(presentationId, variantId, sessionId);
5431
+ let filtered = feedback;
5432
+ if (feedbackId) {
5433
+ filtered = feedback.filter((f) => f.id === feedbackId);
5434
+ if (filtered.length === 0) {
5435
+ return {
5436
+ content: [
5437
+ {
5438
+ type: "text",
5439
+ text: `Feedback item ${feedbackId} not found in this session.`
5440
+ }
5441
+ ]
5442
+ };
5443
+ }
5444
+ } else {
5445
+ const resolvedFilter = filter ?? "all";
5446
+ if (resolvedFilter !== "all") {
5447
+ filtered = feedback.filter((f) => resolvedFilter === "resolved" ? f.resolved : !f.resolved);
5448
+ }
5449
+ }
5450
+ return {
5451
+ content: [
5452
+ {
5453
+ type: "text",
5454
+ text: JSON.stringify({ feedback: filtered }, null, 2)
5455
+ }
5456
+ ]
5457
+ };
5458
+ });
5459
+ }
5460
+ function registerResolvePresentationFeedback(server) {
5461
+ server.registerTool("resolve_presentation_feedback", {
5462
+ description: "Set the resolved status on a presentation feedback item. Requires the feedback type (slide or overall) and the desired resolved state.",
5463
+ inputSchema: resolvePresentationFeedbackInput
5464
+ }, async ({
5465
+ presentationId,
5466
+ variantId,
5467
+ sessionId,
5468
+ feedbackId,
5469
+ type,
5470
+ resolved
5471
+ }) => {
5472
+ const client2 = getApiClient();
5473
+ const result = await client2.resolvePresentationFeedback(presentationId, variantId, sessionId, feedbackId, { type, resolved });
5474
+ return {
5475
+ content: [
5476
+ {
5477
+ type: "text",
5478
+ text: JSON.stringify({
5479
+ success: true,
5480
+ feedbackId: result.id,
5481
+ resolved: result.resolved
5482
+ }, null, 2)
5483
+ }
5484
+ ]
5485
+ };
5486
+ });
5487
+ }
5488
+ function registerAddPresentationReviewer(server) {
5489
+ server.registerTool("add_presentation_reviewer", {
5490
+ description: "Add a reviewer to an active presentation feedback session. Returns a unique review URL for the new reviewer.",
5491
+ inputSchema: addPresentationReviewerInput
5492
+ }, async ({
5493
+ presentationId,
5494
+ variantId,
5495
+ sessionId,
5496
+ name,
5497
+ email
5498
+ }) => {
5499
+ const client2 = getApiClient();
5500
+ const invite = await client2.addPresentationReviewer(presentationId, variantId, sessionId, {
5501
+ name,
5502
+ email
5503
+ });
5504
+ const reviewUrl = `https://app.ourroadmaps.com/review/${invite.token}`;
5505
+ return {
5506
+ content: [
5507
+ {
5508
+ type: "text",
5509
+ text: JSON.stringify({
5510
+ success: true,
5511
+ inviteId: invite.id,
5512
+ reviewUrl,
5513
+ reviewerName: invite.reviewerName,
5514
+ reviewerEmail: invite.reviewerEmail
5515
+ }, null, 2)
5516
+ }
5517
+ ]
5518
+ };
5519
+ });
5520
+ }
5209
5521
 
5210
5522
  // src/index.ts
5211
5523
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ourroadmaps/mcp",
3
- "version": "0.30.1",
3
+ "version": "0.31.0",
4
4
  "description": "MCP server for OurRoadmaps - manage roadmaps, features, and ideas from Claude Code",
5
5
  "type": "module",
6
6
  "bin": {