@ourroadmaps/mcp 0.18.0 → 0.19.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 +283 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -536,8 +536,12 @@ class ApiClient {
536
536
  searchParams.set("limit", String(params.limit));
537
537
  if (params?.offset)
538
538
  searchParams.set("offset", String(params.offset));
539
- const query = searchParams.toString();
540
- const path = query ? `/v1/roadmaps?${query}` : "/v1/roadmaps";
539
+ if (params?.horizon)
540
+ searchParams.set("horizon", params.horizon);
541
+ if (params?.query)
542
+ searchParams.set("query", params.query);
543
+ const queryString = searchParams.toString();
544
+ const path = queryString ? `/v1/roadmaps?${queryString}` : "/v1/roadmaps";
541
545
  return await this.request(path);
542
546
  }
543
547
  async getRoadmap(id) {
@@ -895,6 +899,36 @@ class ApiClient {
895
899
  method: "DELETE"
896
900
  });
897
901
  }
902
+ async listInitiatives() {
903
+ const response = await this.request("/v1/initiatives");
904
+ return response.data;
905
+ }
906
+ async getInitiative(id) {
907
+ return await this.request(`/v1/initiatives/${id}`);
908
+ }
909
+ async createInitiative(data) {
910
+ return await this.request("/v1/initiatives", {
911
+ method: "POST",
912
+ body: JSON.stringify(data)
913
+ });
914
+ }
915
+ async updateInitiative(id, data) {
916
+ return await this.request(`/v1/initiatives/${id}`, {
917
+ method: "PATCH",
918
+ body: JSON.stringify(data)
919
+ });
920
+ }
921
+ async deleteInitiative(id) {
922
+ await this.request(`/v1/initiatives/${id}`, {
923
+ method: "DELETE"
924
+ });
925
+ }
926
+ async reorderInitiatives(items) {
927
+ return await this.request("/v1/initiatives/reorder", {
928
+ method: "POST",
929
+ body: JSON.stringify({ items })
930
+ });
931
+ }
898
932
  async updateDesignDescription(roadmapId, description) {
899
933
  const response = await this.request(`/v1/designs/roadmaps/${roadmapId}/design`, {
900
934
  method: "PATCH",
@@ -1014,6 +1048,12 @@ function registerAllTools(server) {
1014
1048
  registerGetHistorySummary(server);
1015
1049
  registerCreateStatusUpdate(server);
1016
1050
  registerSaveStories(server);
1051
+ registerSearchInitiatives(server);
1052
+ registerGetInitiative(server);
1053
+ registerCreateInitiative(server);
1054
+ registerUpdateInitiative(server);
1055
+ registerDeleteInitiative(server);
1056
+ registerReorderInitiatives(server);
1017
1057
  registerUploadWireframe(server);
1018
1058
  registerUpdateWireframe(server);
1019
1059
  registerDeleteWireframe(server);
@@ -1045,18 +1085,11 @@ function registerSearchRoadmaps(server) {
1045
1085
  offset
1046
1086
  }) => {
1047
1087
  const client2 = getApiClient();
1048
- const response = await client2.listRoadmaps({ limit, offset });
1088
+ const response = await client2.listRoadmaps({ limit, offset, horizon, query });
1049
1089
  let roadmaps = response.items;
1050
- if (query) {
1051
- const q = query.toLowerCase();
1052
- roadmaps = roadmaps.filter((r) => r.title.toLowerCase().includes(q));
1053
- }
1054
1090
  if (status) {
1055
1091
  roadmaps = roadmaps.filter((r) => r.status === status);
1056
1092
  }
1057
- if (horizon) {
1058
- roadmaps = roadmaps.filter((r) => r.horizon === horizon);
1059
- }
1060
1093
  return {
1061
1094
  content: [
1062
1095
  {
@@ -1348,19 +1381,25 @@ function registerCreateRoadmapItem(server) {
1348
1381
  inputSchema: {
1349
1382
  title: z11.string().describe("Title of the roadmap item"),
1350
1383
  status: roadmapStatusSchema.optional().describe('Status (defaults to "not_started")'),
1351
- horizon: horizonSchema.optional().describe('Planning horizon (defaults to "inbox")')
1384
+ horizon: horizonSchema.optional().describe('Planning horizon (defaults to "inbox")'),
1385
+ initiativeId: z11.string().optional().describe("UUID of initiative to link this item to on creation")
1352
1386
  }
1353
1387
  }, async ({
1354
1388
  title,
1355
1389
  status,
1356
- horizon
1390
+ horizon,
1391
+ initiativeId
1357
1392
  }) => {
1358
1393
  const client2 = getApiClient();
1359
- const roadmap2 = await client2.createRoadmap({
1394
+ const createData = {
1360
1395
  title,
1361
1396
  status: status ?? "not_started",
1362
1397
  horizon: horizon ?? "inbox"
1363
- });
1398
+ };
1399
+ if (initiativeId) {
1400
+ createData.initiativeId = initiativeId;
1401
+ }
1402
+ const roadmap2 = await client2.createRoadmap(createData);
1364
1403
  return {
1365
1404
  content: [
1366
1405
  {
@@ -1382,7 +1421,7 @@ function registerCreateRoadmapItem(server) {
1382
1421
  var effortSizeSchema = z11.enum(["xs", "s", "m", "l", "xl"]);
1383
1422
  function registerUpdateRoadmapItem(server) {
1384
1423
  server.registerTool("update_roadmap_item", {
1385
- description: "Update an existing roadmap item. Can update title, status, horizon, value, effort, order, prompt, or brainstorm notes.",
1424
+ description: "Update an existing roadmap item. Can update title, status, horizon, value, effort, order, prompt, initiative link, or brainstorm notes.",
1386
1425
  inputSchema: {
1387
1426
  id: z11.string().describe("The UUID of the roadmap item to update"),
1388
1427
  title: z11.string().optional().describe("New title"),
@@ -1391,6 +1430,7 @@ function registerUpdateRoadmapItem(server) {
1391
1430
  value: z11.number().int().min(1).max(3).nullable().optional().describe("Value rating (1-3 stars, where 3 is highest value)"),
1392
1431
  effort: effortSizeSchema.nullable().optional().describe("Effort estimate (xs=extra small, s=small, m=medium, l=large, xl=extra large)"),
1393
1432
  order: z11.number().int().min(0).optional().describe("Sort order for prioritization (lower numbers appear first)"),
1433
+ initiativeId: z11.string().nullable().optional().describe("UUID to link item to initiative, or null to unlink from any initiative"),
1394
1434
  designDescription: z11.string().nullable().optional().describe("Description for the Design phase"),
1395
1435
  planDescription: z11.string().nullable().optional().describe("Description for the Planning phase"),
1396
1436
  buildDescription: z11.string().nullable().optional().describe("Description for the Build phase"),
@@ -1405,6 +1445,7 @@ function registerUpdateRoadmapItem(server) {
1405
1445
  value,
1406
1446
  effort,
1407
1447
  order,
1448
+ initiativeId,
1408
1449
  designDescription,
1409
1450
  planDescription,
1410
1451
  buildDescription,
@@ -1425,6 +1466,8 @@ function registerUpdateRoadmapItem(server) {
1425
1466
  updates.effort = effort;
1426
1467
  if (order !== undefined)
1427
1468
  updates.order = order;
1469
+ if (initiativeId !== undefined)
1470
+ updates.initiativeId = initiativeId;
1428
1471
  const roadmap2 = Object.keys(updates).length > 0 ? await client2.updateRoadmap(id, updates) : await client2.getRoadmap(id);
1429
1472
  const phaseUpdates = {};
1430
1473
  if (designDescription !== undefined) {
@@ -3071,6 +3114,231 @@ Expires: ${expiryDate}`
3071
3114
  };
3072
3115
  });
3073
3116
  }
3117
+ var dateGranularitySchema2 = z11.enum(["day", "month", "quarter", "half_year", "year"]);
3118
+ function registerSearchInitiatives(server) {
3119
+ server.registerTool("search_initiatives", {
3120
+ description: "Search for initiatives by title or filter by horizon. Returns a list of matching initiatives with item counts.",
3121
+ inputSchema: {
3122
+ query: z11.string().optional().describe("Search query to match against title or description"),
3123
+ horizon: horizonSchema.optional().describe("Filter by planning horizon"),
3124
+ limit: z11.number().int().min(1).max(100).optional().describe("Max items to return (default 10)"),
3125
+ offset: z11.number().int().min(0).optional().describe("Number of items to skip (default 0)")
3126
+ }
3127
+ }, async ({
3128
+ query,
3129
+ horizon,
3130
+ limit = 10,
3131
+ offset = 0
3132
+ }) => {
3133
+ const client2 = getApiClient();
3134
+ let initiatives = await client2.listInitiatives();
3135
+ if (query) {
3136
+ const lowerQuery = query.toLowerCase();
3137
+ initiatives = initiatives.filter((i) => i.title.toLowerCase().includes(lowerQuery) || i.description?.toLowerCase().includes(lowerQuery));
3138
+ }
3139
+ if (horizon) {
3140
+ initiatives = initiatives.filter((i) => i.horizon === horizon);
3141
+ }
3142
+ const total = initiatives.length;
3143
+ const paginatedInitiatives = initiatives.slice(offset, offset + limit);
3144
+ return {
3145
+ content: [
3146
+ {
3147
+ type: "text",
3148
+ text: JSON.stringify({
3149
+ items: paginatedInitiatives.map((i) => ({
3150
+ id: i.id,
3151
+ title: i.title,
3152
+ description: i.description,
3153
+ horizon: i.horizon,
3154
+ targetDate: i.targetDate,
3155
+ itemCount: i.itemCount,
3156
+ doneCount: i.doneCount,
3157
+ order: i.order
3158
+ })),
3159
+ pagination: {
3160
+ limit,
3161
+ offset,
3162
+ total,
3163
+ hasMore: offset + limit < total
3164
+ }
3165
+ }, null, 2)
3166
+ }
3167
+ ]
3168
+ };
3169
+ });
3170
+ }
3171
+ function registerGetInitiative(server) {
3172
+ server.registerTool("get_initiative", {
3173
+ description: "Get full details of an initiative including all linked roadmap items.",
3174
+ inputSchema: {
3175
+ id: z11.string().describe("The UUID of the initiative")
3176
+ }
3177
+ }, async ({ id }) => {
3178
+ const client2 = getApiClient();
3179
+ const result = await client2.getInitiative(id);
3180
+ return {
3181
+ content: [
3182
+ {
3183
+ type: "text",
3184
+ text: JSON.stringify(result, null, 2)
3185
+ }
3186
+ ]
3187
+ };
3188
+ });
3189
+ }
3190
+ function registerCreateInitiative(server) {
3191
+ server.registerTool("create_initiative", {
3192
+ description: "Create a new initiative. Initiatives group related roadmap items for cross-functional coordination.",
3193
+ inputSchema: {
3194
+ title: z11.string().describe("Title of the initiative"),
3195
+ description: z11.string().optional().describe("Description of the initiative (markdown)"),
3196
+ horizon: horizonSchema.optional().describe('Planning horizon (defaults to "inbox")'),
3197
+ dateGranularity: dateGranularitySchema2.optional().describe("Target date granularity: day, month, quarter, half_year, or year"),
3198
+ dateValue: z11.string().optional().describe('Target date value matching granularity (e.g., "2024-Q1", "2024-03")'),
3199
+ targetDate: z11.string().optional().describe("Target date in YYYY-MM-DD format")
3200
+ }
3201
+ }, async ({
3202
+ title,
3203
+ description,
3204
+ horizon,
3205
+ dateGranularity,
3206
+ dateValue,
3207
+ targetDate
3208
+ }) => {
3209
+ const client2 = getApiClient();
3210
+ const initiative = await client2.createInitiative({
3211
+ title,
3212
+ description: description ?? null,
3213
+ horizon: horizon ?? "inbox",
3214
+ dateGranularity: dateGranularity ?? null,
3215
+ dateValue: dateValue ?? null,
3216
+ targetDate: targetDate ?? null
3217
+ });
3218
+ return {
3219
+ content: [
3220
+ {
3221
+ type: "text",
3222
+ text: JSON.stringify({
3223
+ success: true,
3224
+ initiative: {
3225
+ id: initiative.id,
3226
+ title: initiative.title,
3227
+ description: initiative.description,
3228
+ horizon: initiative.horizon,
3229
+ targetDate: initiative.targetDate,
3230
+ itemCount: initiative.itemCount,
3231
+ doneCount: initiative.doneCount
3232
+ }
3233
+ }, null, 2)
3234
+ }
3235
+ ]
3236
+ };
3237
+ });
3238
+ }
3239
+ function registerUpdateInitiative(server) {
3240
+ server.registerTool("update_initiative", {
3241
+ description: "Update an existing initiative.",
3242
+ inputSchema: {
3243
+ id: z11.string().describe("The UUID of the initiative to update"),
3244
+ title: z11.string().optional().describe("New title"),
3245
+ description: z11.string().nullable().optional().describe("New description (null to clear)"),
3246
+ horizon: horizonSchema.optional().describe("New planning horizon"),
3247
+ dateGranularity: dateGranularitySchema2.nullable().optional().describe("New target date granularity (null to clear)"),
3248
+ dateValue: z11.string().nullable().optional().describe("New target date value (null to clear)"),
3249
+ targetDate: z11.string().nullable().optional().describe("New target date in YYYY-MM-DD format (null to clear)"),
3250
+ order: z11.number().int().min(0).optional().describe("Sort order for prioritization (lower numbers appear first)")
3251
+ }
3252
+ }, async ({
3253
+ id,
3254
+ title,
3255
+ description,
3256
+ horizon,
3257
+ dateGranularity,
3258
+ dateValue,
3259
+ targetDate,
3260
+ order
3261
+ }) => {
3262
+ const client2 = getApiClient();
3263
+ const updates = {};
3264
+ if (title !== undefined)
3265
+ updates.title = title;
3266
+ if (description !== undefined)
3267
+ updates.description = description;
3268
+ if (horizon !== undefined)
3269
+ updates.horizon = horizon;
3270
+ if (dateGranularity !== undefined)
3271
+ updates.dateGranularity = dateGranularity;
3272
+ if (dateValue !== undefined)
3273
+ updates.dateValue = dateValue;
3274
+ if (targetDate !== undefined)
3275
+ updates.targetDate = targetDate;
3276
+ if (order !== undefined)
3277
+ updates.order = order;
3278
+ const initiative = await client2.updateInitiative(id, updates);
3279
+ return {
3280
+ content: [
3281
+ {
3282
+ type: "text",
3283
+ text: JSON.stringify({
3284
+ success: true,
3285
+ initiative: {
3286
+ id: initiative.id,
3287
+ title: initiative.title,
3288
+ description: initiative.description,
3289
+ horizon: initiative.horizon,
3290
+ targetDate: initiative.targetDate,
3291
+ itemCount: initiative.itemCount,
3292
+ doneCount: initiative.doneCount,
3293
+ order: initiative.order
3294
+ }
3295
+ }, null, 2)
3296
+ }
3297
+ ]
3298
+ };
3299
+ });
3300
+ }
3301
+ function registerDeleteInitiative(server) {
3302
+ server.registerTool("delete_initiative", {
3303
+ description: "Delete an initiative. This is a soft delete that also unlinks all roadmap items from the initiative.",
3304
+ inputSchema: {
3305
+ id: z11.string().describe("The UUID of the initiative to delete")
3306
+ }
3307
+ }, async ({ id }) => {
3308
+ const client2 = getApiClient();
3309
+ await client2.deleteInitiative(id);
3310
+ return {
3311
+ content: [
3312
+ {
3313
+ type: "text",
3314
+ text: JSON.stringify({ success: true, deleted: id }, null, 2)
3315
+ }
3316
+ ]
3317
+ };
3318
+ });
3319
+ }
3320
+ function registerReorderInitiatives(server) {
3321
+ server.registerTool("reorder_initiatives", {
3322
+ description: "Bulk reorder initiatives by setting their order values. Lower order values appear first.",
3323
+ inputSchema: {
3324
+ items: z11.array(z11.object({
3325
+ id: z11.string().describe("The UUID of the initiative"),
3326
+ order: z11.number().int().min(0).describe("The new order value (0-based)")
3327
+ })).describe("Array of initiatives with their new order values")
3328
+ }
3329
+ }, async ({ items }) => {
3330
+ const client2 = getApiClient();
3331
+ await client2.reorderInitiatives(items);
3332
+ return {
3333
+ content: [
3334
+ {
3335
+ type: "text",
3336
+ text: JSON.stringify({ success: true, reordered: items.length }, null, 2)
3337
+ }
3338
+ ]
3339
+ };
3340
+ });
3341
+ }
3074
3342
 
3075
3343
  // src/index.ts
3076
3344
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ourroadmaps/mcp",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "MCP server for OurRoadmaps - manage roadmaps, features, and ideas from Claude Code",
5
5
  "type": "module",
6
6
  "bin": {