@@ -755,6 +755,210 @@ describe("useMcpToolTool", () => {
755755 consoleSpy . mockRestore ( )
756756 } )
757757
758+ it ( "should ignore images with unsupported MIME types" , async ( ) => {
759+ const block : ToolUse = {
760+ type : "tool_use" ,
761+ name : "use_mcp_tool" ,
762+ params : {
763+ server_name : "test_server" ,
764+ tool_name : "test_tool" ,
765+ arguments : '{"param": "value"}' ,
766+ } ,
767+ partial : false ,
768+ }
769+
770+ mockAskApproval . mockResolvedValue ( true )
771+
772+ const mockToolResult = {
773+ content : [
774+ { type : "text" , text : "Generated content with different image types:" } ,
775+ {
776+ type : "image" ,
777+ data : "PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCI+PGNpcmNsZSBjeD0iNTAiIGN5PSI1MCIgcj0iNDAiLz48L3N2Zz4=" ,
778+ mimeType : "image/svg+xml" , // Unsupported MIME type
779+ } ,
780+ {
781+ type : "image" ,
782+ data : "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChAI9jU" ,
783+ mimeType : "image/png" , // Supported MIME type
784+ } ,
785+ ] ,
786+ isError : false ,
787+ }
788+
789+ mockProviderRef . deref . mockReturnValue ( {
790+ getMcpHub : ( ) => ( {
791+ callTool : vi . fn ( ) . mockResolvedValue ( mockToolResult ) ,
792+ } ) ,
793+ postMessageToWebview : vi . fn ( ) ,
794+ getState : vi . fn ( ) . mockResolvedValue ( {
795+ mcpMaxImagesPerResponse : 20 ,
796+ mcpMaxImageSizeMB : 10 ,
797+ } ) ,
798+ } )
799+
800+ const consoleSpy = vi . spyOn ( console , "warn" ) . mockImplementation ( ( ) => { } )
801+
802+ await useMcpToolTool (
803+ mockTask as Task ,
804+ block ,
805+ mockAskApproval ,
806+ mockHandleError ,
807+ mockPushToolResult ,
808+ mockRemoveClosingTag ,
809+ )
810+
811+ // Should only include the supported PNG image, not the SVG
812+ const sayCall = ( mockTask . say as any ) . mock . calls . find ( ( call : any ) => call [ 0 ] === "mcp_server_response" )
813+ expect ( sayCall [ 2 ] ) . toHaveLength ( 1 )
814+ expect ( sayCall [ 2 ] [ 0 ] ) . toContain ( "data:image/png;base64," )
815+
816+ // Should log warning about unsupported MIME type
817+ expect ( consoleSpy ) . toHaveBeenCalledWith ( "Unsupported image MIME type: image/svg+xml" )
818+
819+ expect ( mockPushToolResult ) . toHaveBeenCalledWith (
820+ "Tool result: Generated content with different image types: (with 1 images)" ,
821+ )
822+
823+ consoleSpy . mockRestore ( )
824+ } )
825+
826+ it ( "should ignore malformed image content missing data property" , async ( ) => {
827+ const block : ToolUse = {
828+ type : "tool_use" ,
829+ name : "use_mcp_tool" ,
830+ params : {
831+ server_name : "test_server" ,
832+ tool_name : "test_tool" ,
833+ arguments : '{"param": "value"}' ,
834+ } ,
835+ partial : false ,
836+ }
837+
838+ mockAskApproval . mockResolvedValue ( true )
839+
840+ const mockToolResult = {
841+ content : [
842+ { type : "text" , text : "Generated content with malformed image:" } ,
843+ {
844+ type : "image" ,
845+ // Missing data property
846+ mimeType : "image/png" ,
847+ } ,
848+ {
849+ type : "image" ,
850+ data : "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChAI9jU" ,
851+ mimeType : "image/png" , // Valid image
852+ } ,
853+ ] ,
854+ isError : false ,
855+ }
856+
857+ mockProviderRef . deref . mockReturnValue ( {
858+ getMcpHub : ( ) => ( {
859+ callTool : vi . fn ( ) . mockResolvedValue ( mockToolResult ) ,
860+ } ) ,
861+ postMessageToWebview : vi . fn ( ) ,
862+ getState : vi . fn ( ) . mockResolvedValue ( {
863+ mcpMaxImagesPerResponse : 20 ,
864+ mcpMaxImageSizeMB : 10 ,
865+ } ) ,
866+ } )
867+
868+ const consoleSpy = vi . spyOn ( console , "warn" ) . mockImplementation ( ( ) => { } )
869+
870+ await useMcpToolTool (
871+ mockTask as Task ,
872+ block ,
873+ mockAskApproval ,
874+ mockHandleError ,
875+ mockPushToolResult ,
876+ mockRemoveClosingTag ,
877+ )
878+
879+ // Should only include the valid image, not the malformed one
880+ const sayCall = ( mockTask . say as any ) . mock . calls . find ( ( call : any ) => call [ 0 ] === "mcp_server_response" )
881+ expect ( sayCall [ 2 ] ) . toHaveLength ( 1 )
882+ expect ( sayCall [ 2 ] [ 0 ] ) . toContain ( "data:image/png;base64," )
883+
884+ // Should log warning about missing data property
885+ expect ( consoleSpy ) . toHaveBeenCalledWith ( "Invalid MCP ImageContent: missing data or mimeType" )
886+
887+ expect ( mockPushToolResult ) . toHaveBeenCalledWith (
888+ "Tool result: Generated content with malformed image: (with 1 images)" ,
889+ )
890+
891+ consoleSpy . mockRestore ( )
892+ } )
893+
894+ it ( "should ignore malformed image content missing mimeType property" , async ( ) => {
895+ const block : ToolUse = {
896+ type : "tool_use" ,
897+ name : "use_mcp_tool" ,
898+ params : {
899+ server_name : "test_server" ,
900+ tool_name : "test_tool" ,
901+ arguments : '{"param": "value"}' ,
902+ } ,
903+ partial : false ,
904+ }
905+
906+ mockAskApproval . mockResolvedValue ( true )
907+
908+ const mockToolResult = {
909+ content : [
910+ { type : "text" , text : "Generated content with malformed image:" } ,
911+ {
912+ type : "image" ,
913+ data : "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChAI9jU" ,
914+ // Missing mimeType property
915+ } ,
916+ {
917+ type : "image" ,
918+ data : "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChAI9jU" ,
919+ mimeType : "image/png" , // Valid image
920+ } ,
921+ ] ,
922+ isError : false ,
923+ }
924+
925+ mockProviderRef . deref . mockReturnValue ( {
926+ getMcpHub : ( ) => ( {
927+ callTool : vi . fn ( ) . mockResolvedValue ( mockToolResult ) ,
928+ } ) ,
929+ postMessageToWebview : vi . fn ( ) ,
930+ getState : vi . fn ( ) . mockResolvedValue ( {
931+ mcpMaxImagesPerResponse : 20 ,
932+ mcpMaxImageSizeMB : 10 ,
933+ } ) ,
934+ } )
935+
936+ const consoleSpy = vi . spyOn ( console , "warn" ) . mockImplementation ( ( ) => { } )
937+
938+ await useMcpToolTool (
939+ mockTask as Task ,
940+ block ,
941+ mockAskApproval ,
942+ mockHandleError ,
943+ mockPushToolResult ,
944+ mockRemoveClosingTag ,
945+ )
946+
947+ // Should only include the valid image, not the malformed one
948+ const sayCall = ( mockTask . say as any ) . mock . calls . find ( ( call : any ) => call [ 0 ] === "mcp_server_response" )
949+ expect ( sayCall [ 2 ] ) . toHaveLength ( 1 )
950+ expect ( sayCall [ 2 ] [ 0 ] ) . toContain ( "data:image/png;base64," )
951+
952+ // Should log warning about missing mimeType property
953+ expect ( consoleSpy ) . toHaveBeenCalledWith ( "Invalid MCP ImageContent: missing data or mimeType" )
954+
955+ expect ( mockPushToolResult ) . toHaveBeenCalledWith (
956+ "Tool result: Generated content with malformed image: (with 1 images)" ,
957+ )
958+
959+ consoleSpy . mockRestore ( )
960+ } )
961+
758962 it ( "should handle user rejection" , async ( ) => {
759963 const block : ToolUse = {
760964 type : "tool_use" ,
0 commit comments