diff --git a/crates/mcp/src/tests.rs b/crates/mcp/src/tests.rs index 3051a5ad4..0f3cdd56c 100644 --- a/crates/mcp/src/tests.rs +++ b/crates/mcp/src/tests.rs @@ -167,6 +167,16 @@ fn tool_definitions_are_well_formed() { } } +#[test] +fn tools_that_write_files_are_not_read_only() { + // `render_page` and `screenshot` write a file when given `path`, so they must not advertise `readOnlyHint: true`. + for name in ["render_page", "screenshot", "export_png"] { + let definition = tool_definitions().into_iter().find(|v| v["name"] == name).unwrap(); + assert!(definition["inputSchema"]["properties"].get("path").is_some(), "{name} takes a path"); + assert_eq!(definition["annotations"]["readOnlyHint"], false, "{name} writes files"); + } +} + // ---------- layout through the tools ---------- #[test] diff --git a/crates/mcp/src/tools.rs b/crates/mcp/src/tools.rs index 8070ab8d3..d1a1ae53a 100644 --- a/crates/mcp/src/tools.rs +++ b/crates/mcp/src/tools.rs @@ -233,7 +233,7 @@ pub fn tool_definitions() -> Vec { }), &[], ), - true, + false, ), tool( "export_png", @@ -250,7 +250,7 @@ pub fn tool_definitions() -> Vec { "Screenshot", &app_only("Capture the whole app window (menus, panels, canvas) and return it as a PNG image. Optionally also keep it at `path`."), obj(json!({"path": string("Also write the PNG here")}), &[]), - true, + false, ), // ----- input ----- tool(