From 61bc027072e5179df64687a4957c82b66c0b6324 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Thu, 15 Oct 2026 11:56:32 +0200 Subject: [PATCH] Fix MCP layer screenshots exceeding maxSize Fixes #445 Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Opus 5.5 --- contributors/people.toml | 4 ++ crates/mcp/src/tools.rs | 15 +++++- crates/mcp/tests/screenshot_pixel_limit.rs | 53 ++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 crates/mcp/tests/screenshot_pixel_limit.rs diff --git a/contributors/people.toml b/contributors/people.toml index e61cfd31..db1f2b54 100644 --- a/contributors/people.toml +++ b/contributors/people.toml @@ -16,3 +16,7 @@ # # To remove your names, delete your entry (or set fields empty) in a PR. The next # contributors.py run, and the next build, drop them. + +[people.Silvertree2010] +display_name = "Netter" +sync_github_name = false diff --git a/crates/mcp/src/tools.rs b/crates/mcp/src/tools.rs index b8d3f3ad..389d75de 100644 --- a/crates/mcp/src/tools.rs +++ b/crates/mcp/src/tools.rs @@ -721,8 +721,19 @@ fn screenshot(b: &mut dyn Backend, a: &Map) -> Result (u32, u32) { + let result = client.call("screenshot", args); + assert_eq!(result["isError"], false, "{result}"); + let size = png_dims(result["content"][0]["data"].as_str().unwrap()); + let meta: Value = serde_json::from_str(result["content"][1]["text"].as_str().unwrap()).unwrap(); + assert_eq!(meta["width"], size.0, "{meta}"); + assert_eq!(meta["height"], size.1, "{meta}"); + size +} + +#[test] +fn layer_screenshots_fit_the_requested_size() { + let mut shadow_client = Client::new(); + let shadow = shadow_client.create(json!({ + "type": "rectangle", "x": 0, "y": 0, + "width": 100, "height": 100, + "props": {"effects": [{ + "type": "dropShadow", "color": "#00000080", + "offset": [0, 40], "radius": 60 + }]} + })); + let shadow_size = dimensions(&mut shadow_client, json!({"ids": [shadow], "maxSize": 100})); + + let mut frame_client = Client::new(); + let frame = frame_client.create(json!({ + "type": "frame", "x": 0, "y": 0, + "width": 100, "height": 100, "props": {"clip": false} + })); + frame_client.create(json!({ + "type": "rectangle", "parent": frame, + "x": 900, "y": 900, "width": 100, "height": 100 + })); + let frame_size = dimensions(&mut frame_client, json!({"ids": [frame], "maxSize": 100})); + + assert!(shadow_size.0 <= 100 && shadow_size.1 <= 100, "shadow screenshot exceeds maxSize: {shadow_size:?}"); + assert!(shadow_size.0 >= 90 && shadow_size.1 >= 90, "shadow screenshot shrank too far: {shadow_size:?}"); + assert!(frame_size.0 <= 100 && frame_size.1 <= 100, "frame screenshot exceeds maxSize: {frame_size:?}"); + assert!(frame_size.0 >= 90 && frame_size.1 >= 90, "frame screenshot shrank too far: {frame_size:?}"); +} + +#[test] +fn plain_layer_screenshot_sizes_are_unchanged() { + let mut client = Client::new(); + let rect = client.create(json!({"type": "rectangle", "x": 0, "y": 0, "width": 100, "height": 100})); + assert_eq!(dimensions(&mut client, json!({"ids": [rect], "maxSize": 100})), (100, 100)); + assert_eq!(dimensions(&mut client, json!({"ids": [rect], "scale": 2})), (200, 200)); +}