@rui.branco/jira-mcp 1.7.0 → 1.7.2

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/index.js +26 -18
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -2505,19 +2505,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
2505
2505
 
2506
2506
  const content = [{ type: "text", text: result.text }];
2507
2507
 
2508
- // Add Jira images
2508
+ // Anthropic vision only accepts png/jpeg/gif/webp under 5MB. We sniff
2509
+ // the magic bytes instead of trusting the filename, since a misnamed
2510
+ // file (e.g. SVG saved as .png) gets the whole response rejected with
2511
+ // "Could not process image".
2512
+ const MAX_IMAGE_BYTES = 5 * 1024 * 1024;
2513
+ const detectImageMime = (buf) => {
2514
+ if (!buf || buf.length < 12) return null;
2515
+ if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) return "image/png";
2516
+ if (buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff) return "image/jpeg";
2517
+ if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x38) return "image/gif";
2518
+ if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 &&
2519
+ buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50) return "image/webp";
2520
+ return null;
2521
+ };
2509
2522
  for (const imagePath of result.jiraImages) {
2510
2523
  try {
2511
2524
  const imageData = fs.readFileSync(imagePath);
2512
- const ext = path.extname(imagePath).toLowerCase();
2513
- const mimeType =
2514
- ext === ".png"
2515
- ? "image/png"
2516
- : ext === ".gif"
2517
- ? "image/gif"
2518
- : ext === ".webp"
2519
- ? "image/webp"
2520
- : "image/jpeg";
2525
+ if (imageData.length > MAX_IMAGE_BYTES) continue;
2526
+ const mimeType = detectImageMime(imageData);
2527
+ if (!mimeType) continue;
2521
2528
  content.push({
2522
2529
  type: "image",
2523
2530
  data: imageData.toString("base64"),
@@ -2528,17 +2535,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
2528
2535
  }
2529
2536
  }
2530
2537
 
2531
- // Add Figma images (now supports multiple images per design)
2538
+ // Figma images (multiple per design). Validate magic bytes here too.
2532
2539
  for (const design of result.figmaDesigns) {
2533
2540
  if (design.images && design.images.length > 0) {
2534
2541
  for (const img of design.images) {
2535
- if (img.buffer) {
2536
- content.push({
2537
- type: "image",
2538
- data: img.buffer.toString("base64"),
2539
- mimeType: "image/png",
2540
- });
2541
- }
2542
+ if (!img.buffer || img.buffer.length > MAX_IMAGE_BYTES) continue;
2543
+ const mimeType = detectImageMime(img.buffer);
2544
+ if (!mimeType) continue;
2545
+ content.push({
2546
+ type: "image",
2547
+ data: img.buffer.toString("base64"),
2548
+ mimeType: mimeType,
2549
+ });
2542
2550
  }
2543
2551
  }
2544
2552
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rui.branco/jira-mcp",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "Jira MCP server for Claude Code - fetch tickets, search with JQL, update tickets, manage comments, change status, and get Figma designs",
5
5
  "main": "index.js",
6
6
  "bin": {