@ourroadmaps/mcp 0.14.0 → 0.16.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 +384 -127
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,4 +1,22 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
3
+ var __create = Object.create;
4
+ var __getProtoOf = Object.getPrototypeOf;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __toESM = (mod, isNodeMode, target) => {
9
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
10
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
+ for (let key of __getOwnPropNames(mod))
12
+ if (!__hasOwnProp.call(to, key))
13
+ __defProp(to, key, {
14
+ get: () => mod[key],
15
+ enumerable: true
16
+ });
17
+ return to;
18
+ };
19
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
2
20
 
3
21
  // src/index.ts
4
22
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -370,6 +388,14 @@ var wireframeSchema = z8.object({
370
388
  imageUrl: z8.string().nullable(),
371
389
  order: z8.number().int()
372
390
  });
391
+ var prototypeSchema = z8.object({
392
+ id: z8.string().uuid(),
393
+ publicUrl: z8.string().url(),
394
+ expiresAt: z8.string().datetime(),
395
+ fileCount: z8.number().int().positive(),
396
+ entryPoint: z8.string(),
397
+ createdAt: z8.string().datetime()
398
+ });
373
399
  var featureLinkSchema = z8.object({
374
400
  id: z8.string().uuid(),
375
401
  featureId: z8.string().uuid(),
@@ -400,6 +426,7 @@ var phaseReleaseSchema = z8.object({
400
426
  var roadmapDetailSchema = roadmapSchema.extend({
401
427
  prd: prdSchema.nullable(),
402
428
  wireframes: z8.array(wireframeSchema),
429
+ prototypes: z8.array(prototypeSchema),
403
430
  brainstormMedia: z8.array(brainstormMediaSchema),
404
431
  brainstormNotes: z8.string().nullable(),
405
432
  featureLinks: z8.array(featureLinkSchema),
@@ -438,8 +465,28 @@ var updateScenarioSchema = z9.object({
438
465
  order: z9.number().int().optional()
439
466
  });
440
467
  var scenarioListSchema = z9.array(scenarioSchema);
441
- // src/tools/index.ts
468
+ // ../../packages/shared/src/schemas/status-update.ts
442
469
  import { z as z10 } from "zod";
470
+ var statusUpdateItemSchema = z10.object({
471
+ id: z10.string().uuid(),
472
+ roadmapItemId: z10.string().uuid(),
473
+ titleAtSnapshot: z10.string(),
474
+ statusAtSnapshot: z10.string(),
475
+ designWalkthroughUrl: z10.string().nullable(),
476
+ releaseWalkthroughUrl: z10.string().nullable()
477
+ });
478
+ var statusUpdateSchema = z10.object({
479
+ id: z10.string().uuid(),
480
+ title: z10.string().nullable(),
481
+ startDate: z10.string(),
482
+ endDate: z10.string(),
483
+ content: z10.string(),
484
+ createdAt: z10.string(),
485
+ items: z10.array(statusUpdateItemSchema).optional()
486
+ });
487
+ var statusUpdateListSchema = z10.array(statusUpdateSchema);
488
+ // src/tools/index.ts
489
+ import { z as z11 } from "zod";
443
490
 
444
491
  // src/auth.ts
445
492
  function getCredentials() {
@@ -876,6 +923,32 @@ class ApiClient {
876
923
  });
877
924
  return response.data;
878
925
  }
926
+ async getPrototypeUploadUrls(roadmapId, files) {
927
+ const response = await this.request(`/v1/roadmaps/${roadmapId}/prototypes/upload-urls`, {
928
+ method: "POST",
929
+ body: JSON.stringify({ files })
930
+ });
931
+ return response.data;
932
+ }
933
+ async createPrototype(roadmapId, data) {
934
+ const response = await this.request(`/v1/roadmaps/${roadmapId}/prototypes`, {
935
+ method: "POST",
936
+ body: JSON.stringify(data)
937
+ });
938
+ return response.data;
939
+ }
940
+ async uploadFile(uploadUrl, content, contentType) {
941
+ const response = await fetch(uploadUrl, {
942
+ method: "PUT",
943
+ body: content,
944
+ headers: {
945
+ "Content-Type": contentType
946
+ }
947
+ });
948
+ if (!response.ok) {
949
+ throw new Error(`Upload failed: ${response.status} ${response.statusText}`);
950
+ }
951
+ }
879
952
  }
880
953
  var client = null;
881
954
  function getApiClient() {
@@ -952,16 +1025,17 @@ function registerAllTools(server) {
952
1025
  registerDeleteProductDesignMedia(server);
953
1026
  registerUploadDesignWalkthrough(server);
954
1027
  registerUploadReleaseWalkthrough(server);
1028
+ registerPublishPrototype(server);
955
1029
  }
956
1030
  function registerSearchRoadmaps(server) {
957
1031
  server.registerTool("search_roadmaps", {
958
1032
  description: "Search for roadmap items by title, status, or horizon. Returns a list of matching roadmap items with basic info.",
959
1033
  inputSchema: {
960
- query: z10.string().optional().describe("Search query to match against title or description"),
1034
+ query: z11.string().optional().describe("Search query to match against title or description"),
961
1035
  status: roadmapStatusSchema.optional().describe("Filter by status"),
962
1036
  horizon: horizonSchema.optional().describe("Filter by planning horizon"),
963
- limit: z10.number().int().min(1).max(100).optional().describe("Max items to return (default 10)"),
964
- offset: z10.number().int().min(0).optional().describe("Number of items to skip (default 0)")
1037
+ limit: z11.number().int().min(1).max(100).optional().describe("Max items to return (default 10)"),
1038
+ offset: z11.number().int().min(0).optional().describe("Number of items to skip (default 0)")
965
1039
  }
966
1040
  }, async ({
967
1041
  query,
@@ -1008,7 +1082,7 @@ function registerGetRoadmap(server) {
1008
1082
  server.registerTool("get_roadmap", {
1009
1083
  description: "Get full details of a roadmap item including PRD, wireframes, brainstorm media, linked features, epics, and stories.",
1010
1084
  inputSchema: {
1011
- id: z10.string().describe("The UUID of the roadmap item")
1085
+ id: z11.string().describe("The UUID of the roadmap item")
1012
1086
  }
1013
1087
  }, async ({ id }) => {
1014
1088
  const client2 = getApiClient();
@@ -1062,7 +1136,7 @@ function registerSearchFeatures(server) {
1062
1136
  server.registerTool("search_features", {
1063
1137
  description: "Search for features and feature areas by name. Returns a list of matching features with basic info.",
1064
1138
  inputSchema: {
1065
- query: z10.string().optional().describe("Search query to match against name"),
1139
+ query: z11.string().optional().describe("Search query to match against name"),
1066
1140
  type: featureTypeSchema.optional().describe("Filter by type (feature or area)")
1067
1141
  }
1068
1142
  }, async ({ query, type }) => {
@@ -1094,7 +1168,7 @@ function registerGetFeature(server) {
1094
1168
  server.registerTool("get_feature", {
1095
1169
  description: "Get full details of a feature including outcomes, child features, and linked roadmap items.",
1096
1170
  inputSchema: {
1097
- id: z10.string().describe("The UUID of the feature")
1171
+ id: z11.string().describe("The UUID of the feature")
1098
1172
  }
1099
1173
  }, async ({ id }) => {
1100
1174
  const client2 = getApiClient();
@@ -1133,7 +1207,7 @@ function registerSearchIdeas(server) {
1133
1207
  server.registerTool("search_ideas", {
1134
1208
  description: "Search for ideas by title or status. Returns a list of matching ideas with basic info.",
1135
1209
  inputSchema: {
1136
- query: z10.string().optional().describe("Search query to match against title or description"),
1210
+ query: z11.string().optional().describe("Search query to match against title or description"),
1137
1211
  status: ideaStatusSchema.optional().describe("Filter by status")
1138
1212
  }
1139
1213
  }, async ({ query, status }) => {
@@ -1233,9 +1307,9 @@ function registerCaptureIdea(server) {
1233
1307
  server.registerTool("capture_idea", {
1234
1308
  description: "Quickly capture a new idea. Ideas are suggestions that can later be reviewed and potentially converted to roadmap items.",
1235
1309
  inputSchema: {
1236
- title: z10.string().describe("Title of the idea"),
1237
- description: z10.string().optional().describe("Detailed description of the idea"),
1238
- source: z10.string().optional().describe('Source of the idea (defaults to "claude-code")')
1310
+ title: z11.string().describe("Title of the idea"),
1311
+ description: z11.string().optional().describe("Detailed description of the idea"),
1312
+ source: z11.string().optional().describe('Source of the idea (defaults to "claude-code")')
1239
1313
  }
1240
1314
  }, async ({
1241
1315
  title,
@@ -1272,7 +1346,7 @@ function registerCreateRoadmapItem(server) {
1272
1346
  server.registerTool("create_roadmap_item", {
1273
1347
  description: "Create a new roadmap item. Use this to add planned work to the roadmap.",
1274
1348
  inputSchema: {
1275
- title: z10.string().describe("Title of the roadmap item"),
1349
+ title: z11.string().describe("Title of the roadmap item"),
1276
1350
  status: roadmapStatusSchema.optional().describe('Status (defaults to "not_started")'),
1277
1351
  horizon: horizonSchema.optional().describe('Planning horizon (defaults to "inbox")')
1278
1352
  }
@@ -1305,23 +1379,23 @@ function registerCreateRoadmapItem(server) {
1305
1379
  };
1306
1380
  });
1307
1381
  }
1308
- var effortSizeSchema = z10.enum(["xs", "s", "m", "l", "xl"]);
1382
+ var effortSizeSchema = z11.enum(["xs", "s", "m", "l", "xl"]);
1309
1383
  function registerUpdateRoadmapItem(server) {
1310
1384
  server.registerTool("update_roadmap_item", {
1311
1385
  description: "Update an existing roadmap item. Can update title, status, horizon, value, effort, order, prompt, or brainstorm notes.",
1312
1386
  inputSchema: {
1313
- id: z10.string().describe("The UUID of the roadmap item to update"),
1314
- title: z10.string().optional().describe("New title"),
1387
+ id: z11.string().describe("The UUID of the roadmap item to update"),
1388
+ title: z11.string().optional().describe("New title"),
1315
1389
  status: roadmapStatusSchema.optional().describe("New status"),
1316
1390
  horizon: horizonSchema.optional().describe("New planning horizon"),
1317
- value: z10.number().int().min(1).max(3).nullable().optional().describe("Value rating (1-3 stars, where 3 is highest value)"),
1391
+ value: z11.number().int().min(1).max(3).nullable().optional().describe("Value rating (1-3 stars, where 3 is highest value)"),
1318
1392
  effort: effortSizeSchema.nullable().optional().describe("Effort estimate (xs=extra small, s=small, m=medium, l=large, xl=extra large)"),
1319
- order: z10.number().int().min(0).optional().describe("Sort order for prioritization (lower numbers appear first)"),
1320
- designDescription: z10.string().nullable().optional().describe("Description for the Design phase"),
1321
- planDescription: z10.string().nullable().optional().describe("Description for the Planning phase"),
1322
- buildDescription: z10.string().nullable().optional().describe("Description for the Build phase"),
1323
- releaseDescription: z10.string().nullable().optional().describe("Description for the Release phase"),
1324
- prompt: z10.string().nullable().optional().describe("Build prompt for the roadmap item")
1393
+ order: z11.number().int().min(0).optional().describe("Sort order for prioritization (lower numbers appear first)"),
1394
+ designDescription: z11.string().nullable().optional().describe("Description for the Design phase"),
1395
+ planDescription: z11.string().nullable().optional().describe("Description for the Planning phase"),
1396
+ buildDescription: z11.string().nullable().optional().describe("Description for the Build phase"),
1397
+ releaseDescription: z11.string().nullable().optional().describe("Description for the Release phase"),
1398
+ prompt: z11.string().nullable().optional().describe("Build prompt for the roadmap item")
1325
1399
  }
1326
1400
  }, async ({
1327
1401
  id,
@@ -1403,12 +1477,12 @@ function registerAddFeature(server) {
1403
1477
  server.registerTool("add_feature", {
1404
1478
  description: "Create a new feature with optional outcomes. Features represent capabilities or functionality areas.",
1405
1479
  inputSchema: {
1406
- name: z10.string().describe("Name of the feature"),
1407
- description: z10.string().optional().describe("Description of the feature"),
1480
+ name: z11.string().describe("Name of the feature"),
1481
+ description: z11.string().optional().describe("Description of the feature"),
1408
1482
  type: featureTypeSchema.optional().describe('Type - "feature" for specific functionality, "area" for grouping (defaults to "feature")'),
1409
- parentId: z10.string().optional().describe("UUID of parent feature/area to nest under"),
1410
- outcomes: z10.array(z10.string()).optional().describe("List of expected outcomes for this feature"),
1411
- linkToRoadmapId: z10.string().optional().describe("UUID of roadmap item to link this feature to")
1483
+ parentId: z11.string().optional().describe("UUID of parent feature/area to nest under"),
1484
+ outcomes: z11.array(z11.string()).optional().describe("List of expected outcomes for this feature"),
1485
+ linkToRoadmapId: z11.string().optional().describe("UUID of roadmap item to link this feature to")
1412
1486
  }
1413
1487
  }, async ({
1414
1488
  name,
@@ -1455,10 +1529,10 @@ function registerSavePrd(server) {
1455
1529
  server.registerTool("save_prd", {
1456
1530
  description: "Save or update the PRD (Product Requirements Document) content for a roadmap item. Content should be markdown.",
1457
1531
  inputSchema: {
1458
- roadmapId: z10.string().describe("The UUID of the roadmap item"),
1459
- what: z10.string().nullable().describe("What is being built - the feature description"),
1460
- why: z10.string().nullable().describe("Why this is being built - the business justification"),
1461
- outcomes: z10.array(z10.string()).optional().describe("List of expected outcomes/success criteria")
1532
+ roadmapId: z11.string().describe("The UUID of the roadmap item"),
1533
+ what: z11.string().nullable().describe("What is being built - the feature description"),
1534
+ why: z11.string().nullable().describe("Why this is being built - the business justification"),
1535
+ outcomes: z11.array(z11.string()).optional().describe("List of expected outcomes/success criteria")
1462
1536
  }
1463
1537
  }, async ({
1464
1538
  roadmapId,
@@ -1496,8 +1570,8 @@ function registerUpdateBrainstormNotes(server) {
1496
1570
  server.registerTool("update_brainstorm_notes", {
1497
1571
  description: "Update the brainstorm notes for a roadmap item. Use this to capture ideas, questions, and research notes.",
1498
1572
  inputSchema: {
1499
- roadmapId: z10.string().describe("The UUID of the roadmap item"),
1500
- notes: z10.string().describe("The brainstorm notes content")
1573
+ roadmapId: z11.string().describe("The UUID of the roadmap item"),
1574
+ notes: z11.string().describe("The brainstorm notes content")
1501
1575
  }
1502
1576
  }, async ({ roadmapId, notes }) => {
1503
1577
  const client2 = getApiClient();
@@ -1526,7 +1600,7 @@ function registerDeleteRoadmapItem(server) {
1526
1600
  server.registerTool("delete_roadmap_item", {
1527
1601
  description: "Delete a roadmap item. This is a soft delete - the item can potentially be recovered.",
1528
1602
  inputSchema: {
1529
- id: z10.string().describe("The UUID of the roadmap item to delete")
1603
+ id: z11.string().describe("The UUID of the roadmap item to delete")
1530
1604
  }
1531
1605
  }, async ({ id }) => {
1532
1606
  const client2 = getApiClient();
@@ -1548,9 +1622,9 @@ function registerReorderRoadmaps(server) {
1548
1622
  server.registerTool("reorder_roadmaps", {
1549
1623
  description: "Bulk reorder roadmap items by setting their order values. Use this to prioritize and organize the roadmap. Lower order values appear first.",
1550
1624
  inputSchema: {
1551
- items: z10.array(z10.object({
1552
- id: z10.string().describe("The UUID of the roadmap item"),
1553
- order: z10.number().int().min(0).describe("The new order value (0-based, lower = higher priority)")
1625
+ items: z11.array(z11.object({
1626
+ id: z11.string().describe("The UUID of the roadmap item"),
1627
+ order: z11.number().int().min(0).describe("The new order value (0-based, lower = higher priority)")
1554
1628
  })).describe("Array of roadmap items with their new order values")
1555
1629
  }
1556
1630
  }, async ({ items }) => {
@@ -1574,10 +1648,10 @@ function registerUpdateFeature(server) {
1574
1648
  server.registerTool("update_feature", {
1575
1649
  description: "Update an existing feature. Can update name, type, or parent.",
1576
1650
  inputSchema: {
1577
- id: z10.string().describe("The UUID of the feature to update"),
1578
- name: z10.string().optional().describe("New name for the feature"),
1651
+ id: z11.string().describe("The UUID of the feature to update"),
1652
+ name: z11.string().optional().describe("New name for the feature"),
1579
1653
  type: featureTypeSchema.optional().describe('New type - "feature" or "area"'),
1580
- parentId: z10.string().nullable().optional().describe("New parent feature/area UUID, or null to move to root")
1654
+ parentId: z11.string().nullable().optional().describe("New parent feature/area UUID, or null to move to root")
1581
1655
  }
1582
1656
  }, async ({
1583
1657
  id,
@@ -1616,7 +1690,7 @@ function registerDeleteFeature(server) {
1616
1690
  server.registerTool("delete_feature", {
1617
1691
  description: "Delete a feature. This is a soft delete that also deletes all child features.",
1618
1692
  inputSchema: {
1619
- id: z10.string().describe("The UUID of the feature to delete")
1693
+ id: z11.string().describe("The UUID of the feature to delete")
1620
1694
  }
1621
1695
  }, async ({ id }) => {
1622
1696
  const client2 = getApiClient();
@@ -1638,7 +1712,7 @@ function registerGetIdea(server) {
1638
1712
  server.registerTool("get_idea", {
1639
1713
  description: "Get full details of a single idea by ID.",
1640
1714
  inputSchema: {
1641
- id: z10.string().describe("The UUID of the idea")
1715
+ id: z11.string().describe("The UUID of the idea")
1642
1716
  }
1643
1717
  }, async ({ id }) => {
1644
1718
  const client2 = getApiClient();
@@ -1667,12 +1741,12 @@ function registerUpdateIdea(server) {
1667
1741
  server.registerTool("update_idea", {
1668
1742
  description: "Update an existing idea. Can update title, description, status, value, or effort.",
1669
1743
  inputSchema: {
1670
- id: z10.string().describe("The UUID of the idea to update"),
1671
- title: z10.string().optional().describe("New title"),
1672
- description: z10.string().nullable().optional().describe("New description"),
1744
+ id: z11.string().describe("The UUID of the idea to update"),
1745
+ title: z11.string().optional().describe("New title"),
1746
+ description: z11.string().nullable().optional().describe("New description"),
1673
1747
  status: ideaStatusSchema.optional().describe("New status"),
1674
- value: z10.enum(["xs", "s", "m", "l", "xl"]).nullable().optional().describe("Estimated value"),
1675
- effort: z10.enum(["xs", "s", "m", "l", "xl"]).nullable().optional().describe("Estimated effort")
1748
+ value: z11.enum(["xs", "s", "m", "l", "xl"]).nullable().optional().describe("Estimated value"),
1749
+ effort: z11.enum(["xs", "s", "m", "l", "xl"]).nullable().optional().describe("Estimated effort")
1676
1750
  }
1677
1751
  }, async ({
1678
1752
  id,
@@ -1719,7 +1793,7 @@ function registerDeleteIdea(server) {
1719
1793
  server.registerTool("delete_idea", {
1720
1794
  description: "Delete an idea. This is a soft delete.",
1721
1795
  inputSchema: {
1722
- id: z10.string().describe("The UUID of the idea to delete")
1796
+ id: z11.string().describe("The UUID of the idea to delete")
1723
1797
  }
1724
1798
  }, async ({ id }) => {
1725
1799
  const client2 = getApiClient();
@@ -1758,8 +1832,8 @@ function registerUpdateStrategy(server) {
1758
1832
  server.registerTool("update_strategy", {
1759
1833
  description: "Update the organization strategy. Can update vision, mission, or both. Use this to set or refine the high-level direction.",
1760
1834
  inputSchema: {
1761
- vision: z10.string().nullable().optional().describe("The vision statement - where the product is headed"),
1762
- mission: z10.string().nullable().optional().describe("The mission statement - why the product exists")
1835
+ vision: z11.string().nullable().optional().describe("The vision statement - where the product is headed"),
1836
+ mission: z11.string().nullable().optional().describe("The mission statement - why the product exists")
1763
1837
  }
1764
1838
  }, async ({ vision, mission }) => {
1765
1839
  const client2 = getApiClient();
@@ -1807,8 +1881,8 @@ function registerCreateScenario(server) {
1807
1881
  server.registerTool("create_scenario", {
1808
1882
  description: "Create a new user scenario. Scenarios describe user workflows and how they accomplish goals.",
1809
1883
  inputSchema: {
1810
- title: z10.string().describe('Title of the scenario (e.g., "User creates their first roadmap")'),
1811
- description: z10.string().nullable().optional().describe("Detailed description of the scenario workflow")
1884
+ title: z11.string().describe('Title of the scenario (e.g., "User creates their first roadmap")'),
1885
+ description: z11.string().nullable().optional().describe("Detailed description of the scenario workflow")
1812
1886
  }
1813
1887
  }, async ({ title, description }) => {
1814
1888
  const client2 = getApiClient();
@@ -1837,9 +1911,9 @@ function registerUpdateScenario(server) {
1837
1911
  server.registerTool("update_scenario", {
1838
1912
  description: "Update an existing scenario.",
1839
1913
  inputSchema: {
1840
- id: z10.string().describe("The UUID of the scenario to update"),
1841
- title: z10.string().optional().describe("New title"),
1842
- description: z10.string().nullable().optional().describe("New description")
1914
+ id: z11.string().describe("The UUID of the scenario to update"),
1915
+ title: z11.string().optional().describe("New title"),
1916
+ description: z11.string().nullable().optional().describe("New description")
1843
1917
  }
1844
1918
  }, async ({
1845
1919
  id,
@@ -1874,7 +1948,7 @@ function registerDeleteScenario(server) {
1874
1948
  server.registerTool("delete_scenario", {
1875
1949
  description: "Delete a scenario. This is a soft delete.",
1876
1950
  inputSchema: {
1877
- id: z10.string().describe("The UUID of the scenario to delete")
1951
+ id: z11.string().describe("The UUID of the scenario to delete")
1878
1952
  }
1879
1953
  }, async ({ id }) => {
1880
1954
  const client2 = getApiClient();
@@ -1889,7 +1963,7 @@ function registerDeleteScenario(server) {
1889
1963
  };
1890
1964
  });
1891
1965
  }
1892
- var productTypeSchema2 = z10.enum([
1966
+ var productTypeSchema2 = z11.enum([
1893
1967
  "brand",
1894
1968
  "product",
1895
1969
  "app",
@@ -1902,8 +1976,8 @@ function registerCreateProduct(server) {
1902
1976
  description: "Create a new product, app, brand, or service. Products represent what the organization builds and offers.",
1903
1977
  inputSchema: {
1904
1978
  type: productTypeSchema2.describe("Type of product"),
1905
- name: z10.string().describe("Name of the product"),
1906
- parentId: z10.string().nullable().optional().describe("UUID of parent product to nest under")
1979
+ name: z11.string().describe("Name of the product"),
1980
+ parentId: z11.string().nullable().optional().describe("UUID of parent product to nest under")
1907
1981
  }
1908
1982
  }, async ({
1909
1983
  type,
@@ -1938,9 +2012,9 @@ function registerUpdateProduct(server) {
1938
2012
  server.registerTool("update_product", {
1939
2013
  description: "Update an existing product.",
1940
2014
  inputSchema: {
1941
- id: z10.string().describe("The UUID of the product to update"),
1942
- name: z10.string().optional().describe("New name"),
1943
- parentId: z10.string().nullable().optional().describe("New parent product UUID, or null to move to root")
2015
+ id: z11.string().describe("The UUID of the product to update"),
2016
+ name: z11.string().optional().describe("New name"),
2017
+ parentId: z11.string().nullable().optional().describe("New parent product UUID, or null to move to root")
1944
2018
  }
1945
2019
  }, async ({ id, name, parentId }) => {
1946
2020
  const client2 = getApiClient();
@@ -1972,7 +2046,7 @@ function registerDeleteProduct(server) {
1972
2046
  server.registerTool("delete_product", {
1973
2047
  description: "Delete a product. This is a soft delete that also deletes all child products.",
1974
2048
  inputSchema: {
1975
- id: z10.string().describe("The UUID of the product to delete")
2049
+ id: z11.string().describe("The UUID of the product to delete")
1976
2050
  }
1977
2051
  }, async ({ id }) => {
1978
2052
  const client2 = getApiClient();
@@ -1995,7 +2069,7 @@ function registerGetProduct(server) {
1995
2069
  server.registerTool("get_product", {
1996
2070
  description: "Get full details of a product by ID, including its documentation (design system and ADRs).",
1997
2071
  inputSchema: {
1998
- id: z10.string().describe("The UUID of the product")
2072
+ id: z11.string().describe("The UUID of the product")
1999
2073
  }
2000
2074
  }, async ({ id }) => {
2001
2075
  const client2 = getApiClient();
@@ -2032,7 +2106,7 @@ function registerSearchProducts(server) {
2032
2106
  server.registerTool("search_products", {
2033
2107
  description: "Search for products by name. Returns a list of matching products with basic info.",
2034
2108
  inputSchema: {
2035
- query: z10.string().optional().describe("Search query to match against product name"),
2109
+ query: z11.string().optional().describe("Search query to match against product name"),
2036
2110
  type: productTypeSchema2.optional().describe("Filter by product type")
2037
2111
  }
2038
2112
  }, async ({ query, type }) => {
@@ -2067,7 +2141,7 @@ function registerGetProductDocumentation(server) {
2067
2141
  server.registerTool("get_product_documentation", {
2068
2142
  description: "Get the documentation (design system and ADRs) for a product. Use this to read existing documentation before updating.",
2069
2143
  inputSchema: {
2070
- productId: z10.string().describe("The UUID of the product")
2144
+ productId: z11.string().describe("The UUID of the product")
2071
2145
  }
2072
2146
  }, async ({ productId }) => {
2073
2147
  const client2 = getApiClient();
@@ -2095,9 +2169,9 @@ function registerUpdateProductDocumentation(server) {
2095
2169
  server.registerTool("update_product_documentation", {
2096
2170
  description: "Update the documentation for a product. Use this to keep design system and ADRs up to date. Creates documentation if it does not exist.",
2097
2171
  inputSchema: {
2098
- productId: z10.string().describe("The UUID of the product"),
2099
- designSystem: z10.string().nullable().optional().describe("Design system documentation - colors, typography, spacing, components. Pass null to clear."),
2100
- adrs: z10.string().nullable().optional().describe("Architecture Decision Records - document key technical decisions. Pass null to clear.")
2172
+ productId: z11.string().describe("The UUID of the product"),
2173
+ designSystem: z11.string().nullable().optional().describe("Design system documentation - colors, typography, spacing, components. Pass null to clear."),
2174
+ adrs: z11.string().nullable().optional().describe("Architecture Decision Records - document key technical decisions. Pass null to clear.")
2101
2175
  }
2102
2176
  }, async ({
2103
2177
  productId,
@@ -2130,16 +2204,16 @@ function registerUpdateProductDocumentation(server) {
2130
2204
  };
2131
2205
  });
2132
2206
  }
2133
- var audienceTypeSchema2 = z10.enum(["stakeholder", "user_persona"]);
2207
+ var audienceTypeSchema2 = z11.enum(["stakeholder", "user_persona"]);
2134
2208
  function registerCreateAudience(server) {
2135
2209
  server.registerTool("create_audience", {
2136
2210
  description: "Create a new audience member - either a stakeholder or user persona. Audiences represent who the product serves.",
2137
2211
  inputSchema: {
2138
2212
  type: audienceTypeSchema2.describe("Type of audience - stakeholder or user_persona"),
2139
- role: z10.string().describe('Role or title of the audience (e.g., "Product Manager", "End User")'),
2140
- likes: z10.string().nullable().optional().describe("What this audience likes or values"),
2141
- dislikes: z10.string().nullable().optional().describe("What this audience dislikes or avoids"),
2142
- priorities: z10.string().nullable().optional().describe("Key priorities for this audience")
2213
+ role: z11.string().describe('Role or title of the audience (e.g., "Product Manager", "End User")'),
2214
+ likes: z11.string().nullable().optional().describe("What this audience likes or values"),
2215
+ dislikes: z11.string().nullable().optional().describe("What this audience dislikes or avoids"),
2216
+ priorities: z11.string().nullable().optional().describe("Key priorities for this audience")
2143
2217
  }
2144
2218
  }, async ({
2145
2219
  type,
@@ -2180,12 +2254,12 @@ function registerUpdateAudience(server) {
2180
2254
  server.registerTool("update_audience", {
2181
2255
  description: "Update an existing audience member.",
2182
2256
  inputSchema: {
2183
- id: z10.string().describe("The UUID of the audience to update"),
2257
+ id: z11.string().describe("The UUID of the audience to update"),
2184
2258
  type: audienceTypeSchema2.optional().describe("New type"),
2185
- role: z10.string().optional().describe("New role"),
2186
- likes: z10.string().nullable().optional().describe("New likes"),
2187
- dislikes: z10.string().nullable().optional().describe("New dislikes"),
2188
- priorities: z10.string().nullable().optional().describe("New priorities")
2259
+ role: z11.string().optional().describe("New role"),
2260
+ likes: z11.string().nullable().optional().describe("New likes"),
2261
+ dislikes: z11.string().nullable().optional().describe("New dislikes"),
2262
+ priorities: z11.string().nullable().optional().describe("New priorities")
2189
2263
  }
2190
2264
  }, async ({
2191
2265
  id,
@@ -2232,7 +2306,7 @@ function registerDeleteAudience(server) {
2232
2306
  server.registerTool("delete_audience", {
2233
2307
  description: "Delete an audience member. This is a soft delete.",
2234
2308
  inputSchema: {
2235
- id: z10.string().describe("The UUID of the audience to delete")
2309
+ id: z11.string().describe("The UUID of the audience to delete")
2236
2310
  }
2237
2311
  }, async ({ id }) => {
2238
2312
  const client2 = getApiClient();
@@ -2274,9 +2348,9 @@ function registerGetHistory(server) {
2274
2348
  server.registerTool("get_history", {
2275
2349
  description: "Get raw history events for a date range. Returns full event details including payloads. " + "Use entityType or entityId filters to narrow results. For status reports, prefer " + "get_history_summary to avoid context overflow.",
2276
2350
  inputSchema: {
2277
- startDate: z10.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Start date in YYYY-MM-DD format"),
2278
- endDate: z10.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("End date in YYYY-MM-DD format"),
2279
- entityType: z10.enum([
2351
+ startDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Start date in YYYY-MM-DD format"),
2352
+ endDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("End date in YYYY-MM-DD format"),
2353
+ entityType: z11.enum([
2280
2354
  "roadmap",
2281
2355
  "feature",
2282
2356
  "idea",
@@ -2308,8 +2382,8 @@ function registerGetHistorySummary(server) {
2308
2382
  server.registerTool("get_history_summary", {
2309
2383
  description: "Get a summary of history events for a date range. Returns counts by entity type, " + "list of changed entities with titles, and total event count. Use this for status " + "report generation instead of get_history to avoid context overflow.",
2310
2384
  inputSchema: {
2311
- startDate: z10.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Start date in YYYY-MM-DD format"),
2312
- endDate: z10.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("End date in YYYY-MM-DD format")
2385
+ startDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Start date in YYYY-MM-DD format"),
2386
+ endDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("End date in YYYY-MM-DD format")
2313
2387
  }
2314
2388
  }, async ({ startDate, endDate }) => {
2315
2389
  const client2 = getApiClient();
@@ -2328,23 +2402,29 @@ function registerCreateStatusUpdate(server) {
2328
2402
  server.registerTool("create_status_update", {
2329
2403
  description: "Create a new status report. Use this after generating the report content from history events.",
2330
2404
  inputSchema: {
2331
- startDate: z10.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Report period start date in YYYY-MM-DD format"),
2332
- endDate: z10.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Report period end date in YYYY-MM-DD format"),
2333
- content: z10.string().describe("The markdown content of the status report"),
2334
- title: z10.string().optional().describe("Optional title for the report")
2405
+ startDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Report period start date in YYYY-MM-DD format"),
2406
+ endDate: z11.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Report period end date in YYYY-MM-DD format"),
2407
+ content: z11.string().describe("The markdown content of the status report"),
2408
+ title: z11.string().optional().describe("Optional title for the report"),
2409
+ items: z11.array(z11.object({
2410
+ roadmapItemId: z11.string().describe("UUID of the roadmap item"),
2411
+ status: z11.string().describe("Status of the item at report creation time")
2412
+ })).optional().describe("Roadmap items to include in the report snapshot")
2335
2413
  }
2336
2414
  }, async ({
2337
2415
  startDate,
2338
2416
  endDate,
2339
2417
  content,
2340
- title
2418
+ title,
2419
+ items
2341
2420
  }) => {
2342
2421
  const client2 = getApiClient();
2343
2422
  const update = await client2.createStatusUpdate({
2344
2423
  startDate,
2345
2424
  endDate,
2346
2425
  content,
2347
- title
2426
+ title,
2427
+ items
2348
2428
  });
2349
2429
  return {
2350
2430
  content: [
@@ -2369,18 +2449,18 @@ function registerSaveStories(server) {
2369
2449
  server.registerTool("save_stories", {
2370
2450
  description: "Save epics and stories for a roadmap item. Replaces all existing epics/stories. Use this to set the complete list of epics and stories for a roadmap.",
2371
2451
  inputSchema: {
2372
- roadmapId: z10.string().uuid().describe("The UUID of the roadmap item"),
2373
- epics: z10.array(z10.object({
2374
- title: z10.string().min(1).describe("Title of the epic"),
2375
- description: z10.string().nullable().optional().describe("Description of the epic"),
2376
- stories: z10.array(z10.object({
2377
- title: z10.string().min(1).describe("Title of the story"),
2378
- description: z10.string().nullable().optional().describe("Description of the story")
2452
+ roadmapId: z11.string().uuid().describe("The UUID of the roadmap item"),
2453
+ epics: z11.array(z11.object({
2454
+ title: z11.string().min(1).describe("Title of the epic"),
2455
+ description: z11.string().nullable().optional().describe("Description of the epic"),
2456
+ stories: z11.array(z11.object({
2457
+ title: z11.string().min(1).describe("Title of the story"),
2458
+ description: z11.string().nullable().optional().describe("Description of the story")
2379
2459
  })).optional().describe("Stories within this epic")
2380
2460
  })).optional().describe("List of epics with their nested stories"),
2381
- stories: z10.array(z10.object({
2382
- title: z10.string().min(1).describe("Title of the story"),
2383
- description: z10.string().nullable().optional().describe("Description of the story")
2461
+ stories: z11.array(z11.object({
2462
+ title: z11.string().min(1).describe("Title of the story"),
2463
+ description: z11.string().nullable().optional().describe("Description of the story")
2384
2464
  })).optional().describe("List of standalone stories (not part of any epic)")
2385
2465
  }
2386
2466
  }, async ({
@@ -2412,10 +2492,10 @@ function registerUploadWireframe(server) {
2412
2492
  server.registerTool("upload_wireframe", {
2413
2493
  description: "Upload an image to a roadmap item's wireframes. Returns a curl command to execute for the upload, then creates the wireframe record. After running the curl command, the wireframe will be visible in the web app.",
2414
2494
  inputSchema: {
2415
- roadmapId: z10.string().describe("The UUID of the roadmap item"),
2416
- filePath: z10.string().describe("Absolute path to the image file on disk"),
2417
- description: z10.string().optional().describe("Optional description of the wireframe"),
2418
- outcomeIds: z10.array(z10.string()).optional().describe("Optional array of PRD outcome IDs this wireframe addresses")
2495
+ roadmapId: z11.string().describe("The UUID of the roadmap item"),
2496
+ filePath: z11.string().describe("Absolute path to the image file on disk"),
2497
+ description: z11.string().optional().describe("Optional description of the wireframe"),
2498
+ outcomeIds: z11.array(z11.string()).optional().describe("Optional array of PRD outcome IDs this wireframe addresses")
2419
2499
  }
2420
2500
  }, async ({
2421
2501
  roadmapId,
@@ -2469,9 +2549,9 @@ function registerUpdateWireframe(server) {
2469
2549
  server.registerTool("update_wireframe", {
2470
2550
  description: "Update a wireframe's description or outcome tags.",
2471
2551
  inputSchema: {
2472
- id: z10.string().describe("The UUID of the wireframe"),
2473
- description: z10.string().nullable().optional().describe("New description for the wireframe"),
2474
- outcomeIds: z10.array(z10.string()).optional().describe("Array of PRD outcome IDs this wireframe addresses (replaces existing)")
2552
+ id: z11.string().describe("The UUID of the wireframe"),
2553
+ description: z11.string().nullable().optional().describe("New description for the wireframe"),
2554
+ outcomeIds: z11.array(z11.string()).optional().describe("Array of PRD outcome IDs this wireframe addresses (replaces existing)")
2475
2555
  }
2476
2556
  }, async ({
2477
2557
  id,
@@ -2507,7 +2587,7 @@ function registerDeleteWireframe(server) {
2507
2587
  server.registerTool("delete_wireframe", {
2508
2588
  description: "Delete a wireframe (soft delete).",
2509
2589
  inputSchema: {
2510
- id: z10.string().describe("The UUID of the wireframe to delete")
2590
+ id: z11.string().describe("The UUID of the wireframe to delete")
2511
2591
  }
2512
2592
  }, async ({ id }) => {
2513
2593
  const client2 = getApiClient();
@@ -2526,9 +2606,9 @@ function registerUploadBrainstormMedia(server) {
2526
2606
  server.registerTool("upload_brainstorm_media", {
2527
2607
  description: "Upload an image or video to a roadmap item's brainstorming section. Returns a curl command to execute for the upload.",
2528
2608
  inputSchema: {
2529
- roadmapId: z10.string().describe("The UUID of the roadmap item"),
2530
- filePath: z10.string().describe("Absolute path to the image or video file on disk"),
2531
- description: z10.string().optional().describe("Optional description of the media")
2609
+ roadmapId: z11.string().describe("The UUID of the roadmap item"),
2610
+ filePath: z11.string().describe("Absolute path to the image or video file on disk"),
2611
+ description: z11.string().optional().describe("Optional description of the media")
2532
2612
  }
2533
2613
  }, async ({
2534
2614
  roadmapId,
@@ -2580,8 +2660,8 @@ function registerUpdateBrainstormMedia(server) {
2580
2660
  server.registerTool("update_brainstorm_media", {
2581
2661
  description: "Update a brainstorm media item's description.",
2582
2662
  inputSchema: {
2583
- id: z10.string().describe("The UUID of the brainstorm media"),
2584
- description: z10.string().nullable().describe("New description for the media")
2663
+ id: z11.string().describe("The UUID of the brainstorm media"),
2664
+ description: z11.string().nullable().describe("New description for the media")
2585
2665
  }
2586
2666
  }, async ({ id, description }) => {
2587
2667
  const client2 = getApiClient();
@@ -2605,7 +2685,7 @@ function registerDeleteBrainstormMedia(server) {
2605
2685
  server.registerTool("delete_brainstorm_media", {
2606
2686
  description: "Delete a brainstorm media item (soft delete).",
2607
2687
  inputSchema: {
2608
- id: z10.string().describe("The UUID of the brainstorm media to delete")
2688
+ id: z11.string().describe("The UUID of the brainstorm media to delete")
2609
2689
  }
2610
2690
  }, async ({ id }) => {
2611
2691
  const client2 = getApiClient();
@@ -2624,9 +2704,9 @@ function registerUploadProductDesignMedia(server) {
2624
2704
  server.registerTool("upload_product_design_media", {
2625
2705
  description: "Upload an image or video to a product's design media section. Returns a curl command to execute for the upload.",
2626
2706
  inputSchema: {
2627
- productId: z10.string().describe("The UUID of the product"),
2628
- filePath: z10.string().describe("Absolute path to the image or video file on disk"),
2629
- description: z10.string().optional().describe("Optional description of the media")
2707
+ productId: z11.string().describe("The UUID of the product"),
2708
+ filePath: z11.string().describe("Absolute path to the image or video file on disk"),
2709
+ description: z11.string().optional().describe("Optional description of the media")
2630
2710
  }
2631
2711
  }, async ({
2632
2712
  productId,
@@ -2679,9 +2759,9 @@ function registerUpdateProductDesignMedia(server) {
2679
2759
  server.registerTool("update_product_design_media", {
2680
2760
  description: "Update a product design media item's description.",
2681
2761
  inputSchema: {
2682
- productId: z10.string().describe("The UUID of the product"),
2683
- mediaId: z10.string().describe("The UUID of the design media"),
2684
- description: z10.string().nullable().describe("New description for the media")
2762
+ productId: z11.string().describe("The UUID of the product"),
2763
+ mediaId: z11.string().describe("The UUID of the design media"),
2764
+ description: z11.string().nullable().describe("New description for the media")
2685
2765
  }
2686
2766
  }, async ({
2687
2767
  productId,
@@ -2709,8 +2789,8 @@ function registerDeleteProductDesignMedia(server) {
2709
2789
  server.registerTool("delete_product_design_media", {
2710
2790
  description: "Delete a product design media item (soft delete).",
2711
2791
  inputSchema: {
2712
- productId: z10.string().describe("The UUID of the product"),
2713
- mediaId: z10.string().describe("The UUID of the design media to delete")
2792
+ productId: z11.string().describe("The UUID of the product"),
2793
+ mediaId: z11.string().describe("The UUID of the design media to delete")
2714
2794
  }
2715
2795
  }, async ({ productId, mediaId }) => {
2716
2796
  const client2 = getApiClient();
@@ -2732,8 +2812,8 @@ function registerUploadDesignWalkthrough(server) {
2732
2812
  server.registerTool("upload_design_walkthrough", {
2733
2813
  description: "Upload a walkthrough video to a roadmap item's design phase. Returns a curl command to execute for the upload.",
2734
2814
  inputSchema: {
2735
- roadmapId: z10.string().describe("The UUID of the roadmap item"),
2736
- filePath: z10.string().describe("Absolute path to the video file on disk")
2815
+ roadmapId: z11.string().describe("The UUID of the roadmap item"),
2816
+ filePath: z11.string().describe("Absolute path to the video file on disk")
2737
2817
  }
2738
2818
  }, async ({ roadmapId, filePath }) => {
2739
2819
  const client2 = getApiClient();
@@ -2775,8 +2855,8 @@ function registerUploadReleaseWalkthrough(server) {
2775
2855
  server.registerTool("upload_release_walkthrough", {
2776
2856
  description: "Upload a walkthrough video to a roadmap item's release phase. Returns a curl command to execute for the upload.",
2777
2857
  inputSchema: {
2778
- roadmapId: z10.string().describe("The UUID of the roadmap item"),
2779
- filePath: z10.string().describe("Absolute path to the video file on disk")
2858
+ roadmapId: z11.string().describe("The UUID of the roadmap item"),
2859
+ filePath: z11.string().describe("Absolute path to the video file on disk")
2780
2860
  }
2781
2861
  }, async ({ roadmapId, filePath }) => {
2782
2862
  const client2 = getApiClient();
@@ -2814,6 +2894,183 @@ function registerUploadReleaseWalkthrough(server) {
2814
2894
  };
2815
2895
  });
2816
2896
  }
2897
+ function getPrototypeContentType(filename) {
2898
+ const ext = filename.split(".").pop()?.toLowerCase() || "";
2899
+ const types = {
2900
+ html: "text/html",
2901
+ css: "text/css",
2902
+ js: "application/javascript",
2903
+ json: "application/json",
2904
+ png: "image/png",
2905
+ jpg: "image/jpeg",
2906
+ jpeg: "image/jpeg",
2907
+ gif: "image/gif",
2908
+ svg: "image/svg+xml",
2909
+ webp: "image/webp"
2910
+ };
2911
+ return types[ext] || "application/octet-stream";
2912
+ }
2913
+ function registerPublishPrototype(server) {
2914
+ server.registerTool("publish_prototype", {
2915
+ description: "Publish a local prototype folder to a shareable URL. Uploads all files from the folder and returns a time-limited shareable link.",
2916
+ inputSchema: {
2917
+ roadmapId: z11.string().uuid().describe("The UUID of the roadmap item to attach the prototype to"),
2918
+ folderPath: z11.string().describe("Absolute path to the local mockup folder"),
2919
+ entryPoint: z11.string().default("index.html").describe("Main HTML file to open (defaults to index.html)")
2920
+ }
2921
+ }, async ({
2922
+ roadmapId,
2923
+ folderPath,
2924
+ entryPoint
2925
+ }) => {
2926
+ const fs = await import("node:fs/promises");
2927
+ const path = await import("node:path");
2928
+ const client2 = getApiClient();
2929
+ const ignoredNames = new Set([
2930
+ ".DS_Store",
2931
+ ".git",
2932
+ "node_modules",
2933
+ ".env",
2934
+ ".gitignore",
2935
+ ".npmrc",
2936
+ "Thumbs.db",
2937
+ ".idea",
2938
+ ".vscode"
2939
+ ]);
2940
+ async function scanFolder(dir, base = "") {
2941
+ const entries = await fs.readdir(dir, { withFileTypes: true });
2942
+ const files2 = [];
2943
+ for (const entry of entries) {
2944
+ if (entry.name.startsWith(".") || ignoredNames.has(entry.name)) {
2945
+ continue;
2946
+ }
2947
+ const relativePath = base ? `${base}/${entry.name}` : entry.name;
2948
+ const fullPath = path.join(dir, entry.name);
2949
+ if (entry.isDirectory()) {
2950
+ files2.push(...await scanFolder(fullPath, relativePath));
2951
+ } else {
2952
+ files2.push(relativePath);
2953
+ }
2954
+ }
2955
+ return files2;
2956
+ }
2957
+ try {
2958
+ await fs.access(folderPath);
2959
+ } catch {
2960
+ return {
2961
+ content: [
2962
+ {
2963
+ type: "text",
2964
+ text: `Error: Folder not found: ${folderPath}`
2965
+ }
2966
+ ]
2967
+ };
2968
+ }
2969
+ const files = await scanFolder(folderPath);
2970
+ if (files.length === 0) {
2971
+ return {
2972
+ content: [
2973
+ {
2974
+ type: "text",
2975
+ text: `Error: No files found in ${folderPath}`
2976
+ }
2977
+ ]
2978
+ };
2979
+ }
2980
+ if (!files.includes(entryPoint)) {
2981
+ return {
2982
+ content: [
2983
+ {
2984
+ type: "text",
2985
+ text: `Error: Entry point "${entryPoint}" not found. Available files: ${files.slice(0, 10).join(", ")}${files.length > 10 ? "..." : ""}`
2986
+ }
2987
+ ]
2988
+ };
2989
+ }
2990
+ const filesWithTypes = files.map((filename) => ({
2991
+ filename,
2992
+ contentType: getPrototypeContentType(filename)
2993
+ }));
2994
+ let uploadData;
2995
+ try {
2996
+ uploadData = await client2.getPrototypeUploadUrls(roadmapId, filesWithTypes);
2997
+ } catch (error) {
2998
+ return {
2999
+ content: [
3000
+ {
3001
+ type: "text",
3002
+ text: `Error getting upload URLs: ${error instanceof Error ? error.message : String(error)}`
3003
+ }
3004
+ ]
3005
+ };
3006
+ }
3007
+ const uploadUrlMap = new Map(uploadData.files.map((f) => [f.filename, f.uploadUrl]));
3008
+ let uploaded = 0;
3009
+ for (const file of files) {
3010
+ const filePath = path.join(folderPath, file);
3011
+ const fileContent = await fs.readFile(filePath);
3012
+ const uploadUrl = uploadUrlMap.get(file);
3013
+ if (!uploadUrl) {
3014
+ return {
3015
+ content: [
3016
+ {
3017
+ type: "text",
3018
+ text: `Error: No upload URL found for ${file}`
3019
+ }
3020
+ ]
3021
+ };
3022
+ }
3023
+ try {
3024
+ await client2.uploadFile(uploadUrl, fileContent, getPrototypeContentType(file));
3025
+ uploaded++;
3026
+ } catch (error) {
3027
+ return {
3028
+ content: [
3029
+ {
3030
+ type: "text",
3031
+ text: `Error uploading ${file}: ${error instanceof Error ? error.message : String(error)}`
3032
+ }
3033
+ ]
3034
+ };
3035
+ }
3036
+ }
3037
+ let prototype;
3038
+ try {
3039
+ prototype = await client2.createPrototype(roadmapId, {
3040
+ token: uploadData.token,
3041
+ fileCount: files.length,
3042
+ entryPoint
3043
+ });
3044
+ } catch (error) {
3045
+ return {
3046
+ content: [
3047
+ {
3048
+ type: "text",
3049
+ text: `Error creating prototype record: ${error instanceof Error ? error.message : String(error)}`
3050
+ }
3051
+ ]
3052
+ };
3053
+ }
3054
+ const expiryDate = new Date(prototype.expiresAt).toLocaleDateString("en-US", {
3055
+ month: "long",
3056
+ day: "numeric",
3057
+ year: "numeric"
3058
+ });
3059
+ return {
3060
+ content: [
3061
+ {
3062
+ type: "text",
3063
+ text: `Published ${uploaded} files!
3064
+
3065
+ Share this link:
3066
+ ${prototype.publicUrl}
3067
+
3068
+ Expires: ${expiryDate}`
3069
+ }
3070
+ ]
3071
+ };
3072
+ });
3073
+ }
2817
3074
 
2818
3075
  // src/index.ts
2819
3076
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ourroadmaps/mcp",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "description": "MCP server for OurRoadmaps - manage roadmaps, features, and ideas from Claude Code",
5
5
  "type": "module",
6
6
  "bin": {