@ourroadmaps/mcp 0.25.0 → 0.27.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 +96 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -526,7 +526,8 @@ var SLIDE_TYPES = [
526
526
  "image",
527
527
  "quote",
528
528
  "code",
529
- "thank_you"
529
+ "thank_you",
530
+ "mermaid"
530
531
  ];
531
532
  var slideTypeSchema = z12.enum(SLIDE_TYPES);
532
533
  var titleContentSchema = z12.object({
@@ -581,6 +582,10 @@ var thankYouContentSchema = z12.object({
581
582
  ctaText: z12.string().optional(),
582
583
  ctaUrl: z12.string().optional()
583
584
  });
585
+ var mermaidContentSchema = z12.object({
586
+ title: z12.string().optional(),
587
+ code: z12.string().default("")
588
+ });
584
589
  var typedSlideContentSchema = z12.discriminatedUnion("type", [
585
590
  z12.object({ type: z12.literal("title"), ...titleContentSchema.shape }),
586
591
  z12.object({ type: z12.literal("section_header"), ...sectionHeaderContentSchema.shape }),
@@ -591,7 +596,8 @@ var typedSlideContentSchema = z12.discriminatedUnion("type", [
591
596
  z12.object({ type: z12.literal("image"), ...imageContentSchema.shape }),
592
597
  z12.object({ type: z12.literal("quote"), ...quoteContentSchema.shape }),
593
598
  z12.object({ type: z12.literal("code"), ...codeContentSchema.shape }),
594
- z12.object({ type: z12.literal("thank_you"), ...thankYouContentSchema.shape })
599
+ z12.object({ type: z12.literal("thank_you"), ...thankYouContentSchema.shape }),
600
+ z12.object({ type: z12.literal("mermaid"), ...mermaidContentSchema.shape })
595
601
  ]);
596
602
  var slideContentSchema = z12.object({
597
603
  body: z12.string().optional()
@@ -1301,6 +1307,13 @@ class ApiClient {
1301
1307
  body: JSON.stringify({ items })
1302
1308
  });
1303
1309
  }
1310
+ async getSlideUploadUrl(presentationId, variantId, data) {
1311
+ const response = await this.request(`/v1/presentations/${presentationId}/variants/${variantId}/slides/upload-url`, {
1312
+ method: "POST",
1313
+ body: JSON.stringify(data)
1314
+ });
1315
+ return response.data;
1316
+ }
1304
1317
  async getVariantPresentationId(variantId) {
1305
1318
  const presentations = await this.listPresentations();
1306
1319
  for (const presentation2 of presentations.items) {
@@ -1421,6 +1434,7 @@ function registerAllTools(server) {
1421
1434
  registerUpdateSlide(server);
1422
1435
  registerDeleteSlide(server);
1423
1436
  registerReorderSlides(server);
1437
+ registerUploadSlideImage(server);
1424
1438
  }
1425
1439
  function registerGetWorkflows(server) {
1426
1440
  server.registerTool("get_workflows", {
@@ -4299,7 +4313,7 @@ function registerGetSlide(server) {
4299
4313
  }
4300
4314
  function registerCreateSlide(server) {
4301
4315
  server.registerTool("create_slide", {
4302
- 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).",
4316
+ 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).",
4303
4317
  inputSchema: {
4304
4318
  variantId: z15.string().describe("The UUID of the variant"),
4305
4319
  slideType: z15.enum([
@@ -4312,9 +4326,10 @@ function registerCreateSlide(server) {
4312
4326
  "image",
4313
4327
  "quote",
4314
4328
  "code",
4315
- "thank_you"
4329
+ "thank_you",
4330
+ "mermaid"
4316
4331
  ]).default("bullets").describe("The type of slide to create"),
4317
- 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}. Etc.'),
4332
+ 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"}. Etc.'),
4318
4333
  speakerNotes: z15.string().nullable().optional().describe("Speaker notes for the slide")
4319
4334
  }
4320
4335
  }, async ({
@@ -4465,6 +4480,82 @@ function registerReorderSlides(server) {
4465
4480
  };
4466
4481
  });
4467
4482
  }
4483
+ function registerUploadSlideImage(server) {
4484
+ server.registerTool("upload_slide_image", {
4485
+ description: 'Upload an image to a slide. Gets a presigned URL and returns a curl command to execute for the upload, then updates the slide content with the image URL. The slide must be of type "image".',
4486
+ inputSchema: {
4487
+ variantId: z15.string().describe("The UUID of the variant"),
4488
+ slideId: z15.string().describe("The UUID of the slide to add the image to"),
4489
+ filePath: z15.string().describe("Absolute path to the image file on disk")
4490
+ }
4491
+ }, async ({
4492
+ variantId,
4493
+ slideId,
4494
+ filePath
4495
+ }) => {
4496
+ const client2 = getApiClient();
4497
+ const presentationId = await client2.getVariantPresentationId(variantId);
4498
+ if (!presentationId) {
4499
+ return {
4500
+ content: [
4501
+ {
4502
+ type: "text",
4503
+ text: JSON.stringify({ error: "Variant not found" }, null, 2)
4504
+ }
4505
+ ]
4506
+ };
4507
+ }
4508
+ const filename = filePath.split("/").pop() || "image.png";
4509
+ const contentType = inferContentType(filename);
4510
+ if (!contentType || !contentType.startsWith("image/")) {
4511
+ return {
4512
+ content: [
4513
+ {
4514
+ type: "text",
4515
+ text: JSON.stringify({
4516
+ error: "Invalid file type. Slide images only accept image files (png, jpeg, gif, webp)."
4517
+ })
4518
+ }
4519
+ ]
4520
+ };
4521
+ }
4522
+ const slide2 = await client2.getSlide(presentationId, variantId, slideId);
4523
+ if (slide2.slideType !== "image") {
4524
+ return {
4525
+ content: [
4526
+ {
4527
+ type: "text",
4528
+ text: JSON.stringify({
4529
+ error: `Slide is type "${slide2.slideType}", not "image". Only image slides support image upload.`
4530
+ })
4531
+ }
4532
+ ]
4533
+ };
4534
+ }
4535
+ const { uploadUrl, imageUrl } = await client2.getSlideUploadUrl(presentationId, variantId, {
4536
+ filename,
4537
+ contentType
4538
+ });
4539
+ const existingContent = slide2.content || {};
4540
+ await client2.updateSlide(presentationId, variantId, slideId, {
4541
+ content: { ...existingContent, imageUrl }
4542
+ });
4543
+ const curlCommand = `curl -X PUT -H "Content-Type: ${contentType}" --data-binary @"${filePath}" "${uploadUrl}"`;
4544
+ return {
4545
+ content: [
4546
+ {
4547
+ type: "text",
4548
+ text: JSON.stringify({
4549
+ slideId,
4550
+ imageUrl,
4551
+ curlCommand,
4552
+ instructions: "Execute the curlCommand to upload the file. The slide has been updated and will display the image once uploaded."
4553
+ }, null, 2)
4554
+ }
4555
+ ]
4556
+ };
4557
+ });
4558
+ }
4468
4559
 
4469
4560
  // src/index.ts
4470
4561
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ourroadmaps/mcp",
3
- "version": "0.25.0",
3
+ "version": "0.27.0",
4
4
  "description": "MCP server for OurRoadmaps - manage roadmaps, features, and ideas from Claude Code",
5
5
  "type": "module",
6
6
  "bin": {