Skip to main content
Glama

šŸŖ„ ImageSorcery MCP

test_resize.py•18.6 kB
import os import cv2 import numpy as np import pytest from fastmcp import Client, FastMCP from imagesorcery_mcp.server import mcp as image_sorcery_mcp_server @pytest.fixture def mcp_server(): # Use the existing server instance return image_sorcery_mcp_server @pytest.fixture def test_image_path(tmp_path): """Create a test image for resizing.""" img_path = tmp_path / "test_image.png" # Create a white image img = np.ones((200, 300, 3), dtype=np.uint8) * 255 # Draw some colored areas to verify resizing # Red square (50,50) to (100,100) img[50:100, 50:100] = [0, 0, 255] # OpenCV uses BGR # Blue square (100,100) to (150,150) img[100:150, 100:150] = [255, 0, 0] # OpenCV uses BGR # Draw a green circle in the center with thickness 5px and diameter 100px center = (150, 100) # x, y coordinates (center of the image) radius = 50 # 100px diameter color = (0, 255, 0) # Green in BGR thickness = 5 cv2.circle(img, center, radius, color, thickness) # Add text "TEST" in the center font = cv2.FONT_HERSHEY_SIMPLEX font_scale = 1 text_color = (0, 0, 0) # Black in BGR text_thickness = 2 text = "TEST" # Get text size to center it properly text_size = cv2.getTextSize(text, font, font_scale, text_thickness)[0] text_x = int(center[0] - text_size[0] / 2) text_y = int(center[1] + text_size[1] / 2) cv2.putText( img, text, (text_x, text_y), font, font_scale, text_color, text_thickness ) cv2.imwrite(str(img_path), img) return str(img_path) class TestResizeToolDefinition: """Tests for the resize tool definition and metadata.""" @pytest.mark.asyncio async def test_resize_in_tools_list(self, mcp_server: FastMCP): """Tests that resize tool is in the list of available tools.""" async with Client(mcp_server) as client: tools = await client.list_tools() # Verify that tools list is not empty assert tools, "Tools list should not be empty" # Check if resize is in the list of tools tool_names = [tool.name for tool in tools] assert "resize" in tool_names, ( "resize tool should be in the list of available tools" ) @pytest.mark.asyncio async def test_resize_description(self, mcp_server: FastMCP): """Tests that resize tool has the correct description.""" async with Client(mcp_server) as client: tools = await client.list_tools() resize_tool = next((tool for tool in tools if tool.name == "resize"), None) # Check description assert resize_tool.description, "resize tool should have a description" assert "resize" in resize_tool.description.lower(), ( "Description should mention that it resizes an image" ) @pytest.mark.asyncio async def test_resize_parameters(self, mcp_server: FastMCP): """Tests that resize tool has the correct parameter structure.""" async with Client(mcp_server) as client: tools = await client.list_tools() resize_tool = next((tool for tool in tools if tool.name == "resize"), None) # Check input schema assert hasattr(resize_tool, "inputSchema"), ( "resize tool should have an inputSchema" ) assert "properties" in resize_tool.inputSchema, ( "inputSchema should have properties field" ) # Check required parameters assert "input_path" in resize_tool.inputSchema["properties"], ( "resize tool should have an 'input_path' property in its inputSchema" ) # Check optional parameters optional_params = [ "width", "height", "scale_factor", "interpolation", "output_path", ] for param in optional_params: assert param in resize_tool.inputSchema["properties"], ( f"resize tool should have a '{param}' property in its inputSchema" ) # Check parameter types - accounting for optional parameters # that use anyOf structure assert ( resize_tool.inputSchema["properties"]["input_path"].get("type") == "string" ), "input_path should be of type string" # For optional integer parameters, check if they have the correct type # in anyOf structure for param in ["width", "height"]: param_schema = resize_tool.inputSchema["properties"][param] if "anyOf" in param_schema: # Check if one of the anyOf options is integer has_integer_type = any( option.get("type") == "integer" for option in param_schema["anyOf"] ) assert has_integer_type, f"{param} should allow integer type" else: assert param_schema.get("type") == "integer", ( f"{param} should be of type integer" ) # For scale_factor (float parameter) scale_factor_schema = resize_tool.inputSchema["properties"][ "scale_factor" ] if "anyOf" in scale_factor_schema: # Check if one of the anyOf options is number has_number_type = any( option.get("type") == "number" for option in scale_factor_schema["anyOf"] ) assert has_number_type, "scale_factor should allow number type" else: assert scale_factor_schema.get("type") == "number", ( "scale_factor should be of type number" ) # For string parameters for param in ["interpolation", "output_path"]: param_schema = resize_tool.inputSchema["properties"][param] if "anyOf" in param_schema: # Check if one of the anyOf options is string has_string_type = any( option.get("type") == "string" for option in param_schema["anyOf"] ) assert has_string_type, f"{param} should allow string type" else: assert param_schema.get("type") == "string", ( f"{param} should be of type string" ) class TestResizeToolExecution: """Tests for the resize tool execution and results.""" @pytest.mark.asyncio async def test_resize_with_dimensions_smaller( self, mcp_server: FastMCP, test_image_path, tmp_path ): """Tests the resize tool execution with specific dimensions (smaller).""" output_path = str(tmp_path / "output_dimensions_smaller.png") async with Client(mcp_server) as client: result = await client.call_tool( "resize", { "input_path": test_image_path, "width": 150, "height": 100, "output_path": output_path, }, ) # Check that the tool returned a result assert result.data == output_path # Verify the file exists assert os.path.exists(output_path) # Verify the resized image dimensions img = cv2.imread(output_path) assert img.shape[:2] == (100, 150) # height, width @pytest.mark.asyncio async def test_resize_with_dimensions_larger( self, mcp_server: FastMCP, test_image_path, tmp_path ): """Tests the resize tool execution with specific dimensions (larger).""" output_path = str(tmp_path / "output_dimensions_larger.png") async with Client(mcp_server) as client: result = await client.call_tool( "resize", { "input_path": test_image_path, "width": 600, "height": 400, "output_path": output_path, }, ) # Check that the tool returned a result assert result.data == output_path # Verify the file exists assert os.path.exists(output_path) # Verify the resized image dimensions img = cv2.imread(output_path) assert img.shape[:2] == (400, 600) # height, width @pytest.mark.asyncio async def test_resize_with_width_only_smaller( self, mcp_server: FastMCP, test_image_path, tmp_path ): """Tests the resize tool execution with only width specified (smaller, preserving aspect ratio).""" output_path = str(tmp_path / "output_width_only_smaller.png") async with Client(mcp_server) as client: result = await client.call_tool( "resize", { "input_path": test_image_path, "width": 150, "output_path": output_path, }, ) # Check that the tool returned a result assert result.data == output_path # Verify the file exists assert os.path.exists(output_path) # Verify the resized image dimensions img = cv2.imread(output_path) assert img.shape[1] == 150 # width # Height should be proportional (original: 200x300, new width: 150) # So new height should be 200 * (150/300) = 100 assert img.shape[0] == 100 # height @pytest.mark.asyncio async def test_resize_with_width_only_larger( self, mcp_server: FastMCP, test_image_path, tmp_path ): """Tests the resize tool execution with only width specified (larger, preserving aspect ratio).""" output_path = str(tmp_path / "output_width_only_larger.png") async with Client(mcp_server) as client: result = await client.call_tool( "resize", { "input_path": test_image_path, "width": 600, "output_path": output_path, }, ) # Check that the tool returned a result assert result.data == output_path # Verify the file exists assert os.path.exists(output_path) # Verify the resized image dimensions img = cv2.imread(output_path) assert img.shape[1] == 600 # width # Height should be proportional (original: 200x300, new width: 600) # So new height should be 200 * (600/300) = 400 assert img.shape[0] == 400 # height @pytest.mark.asyncio async def test_resize_with_height_only_smaller( self, mcp_server: FastMCP, test_image_path, tmp_path ): """Tests the resize tool execution with only height specified (smaller, preserving aspect ratio).""" output_path = str(tmp_path / "output_height_only_smaller.png") async with Client(mcp_server) as client: result = await client.call_tool( "resize", { "input_path": test_image_path, "height": 100, "output_path": output_path, }, ) # Check that the tool returned a result assert result.data == output_path # Verify the file exists assert os.path.exists(output_path) # Verify the resized image dimensions img = cv2.imread(output_path) assert img.shape[0] == 100 # height # Width should be proportional (original: 200x300, new height: 100) # So new width should be 300 * (100/200) = 150 assert img.shape[1] == 150 # width @pytest.mark.asyncio async def test_resize_with_height_only_larger( self, mcp_server: FastMCP, test_image_path, tmp_path ): """Tests the resize tool execution with only height specified (larger, preserving aspect ratio).""" output_path = str(tmp_path / "output_height_only_larger.png") async with Client(mcp_server) as client: result = await client.call_tool( "resize", { "input_path": test_image_path, "height": 400, "output_path": output_path, }, ) # Check that the tool returned a result assert result.data == output_path # Verify the file exists assert os.path.exists(output_path) # Verify the resized image dimensions img = cv2.imread(output_path) assert img.shape[0] == 400 # height # Width should be proportional (original: 200x300, new height: 400) # So new width should be 300 * (400/200) = 600 assert img.shape[1] == 600 # width @pytest.mark.asyncio async def test_resize_with_scale_factor_smaller( self, mcp_server: FastMCP, test_image_path, tmp_path ): """Tests the resize tool execution with scale factor (smaller).""" output_path = str(tmp_path / "output_scale_smaller.png") async with Client(mcp_server) as client: result = await client.call_tool( "resize", { "input_path": test_image_path, "scale_factor": 0.5, "output_path": output_path, }, ) # Check that the tool returned a result assert result.data == output_path # Verify the file exists assert os.path.exists(output_path) # Verify the resized image dimensions img = cv2.imread(output_path) # Original: 200x300, scale: 0.5, so new dimensions should be 100x150 assert img.shape[:2] == (100, 150) # height, width @pytest.mark.asyncio async def test_resize_with_scale_factor_larger( self, mcp_server: FastMCP, test_image_path, tmp_path ): """Tests the resize tool execution with scale factor (larger).""" output_path = str(tmp_path / "output_scale_larger.png") async with Client(mcp_server) as client: result = await client.call_tool( "resize", { "input_path": test_image_path, "scale_factor": 2.0, "output_path": output_path, }, ) # Check that the tool returned a result assert result.data == output_path # Verify the file exists assert os.path.exists(output_path) # Verify the resized image dimensions img = cv2.imread(output_path) # Original: 200x300, scale: 2.0, so new dimensions should be 400x600 assert img.shape[:2] == (400, 600) # height, width @pytest.mark.asyncio async def test_resize_default_output_path( self, mcp_server: FastMCP, test_image_path ): """Tests the resize tool with default output path.""" async with Client(mcp_server) as client: result = await client.call_tool( "resize", {"input_path": test_image_path, "width": 150, "height": 100} ) # Check that the tool returned a result expected_output = test_image_path.replace(".png", "_resized.png") assert result.data == expected_output # Verify the file exists assert os.path.exists(expected_output) # Verify the resized image dimensions img = cv2.imread(expected_output) assert img.shape[:2] == (100, 150) # height, width @pytest.mark.asyncio async def test_resize_with_interpolation( self, mcp_server: FastMCP, test_image_path, tmp_path ): """Tests the resize tool with different interpolation methods.""" interpolation_methods = ["nearest", "linear", "area", "cubic", "lanczos"] for method in interpolation_methods: # Test downscaling output_path_smaller = str(tmp_path / f"output_{method}_smaller.png") async with Client(mcp_server) as client: result = await client.call_tool( "resize", { "input_path": test_image_path, "width": 150, "height": 100, "interpolation": method, "output_path": output_path_smaller, }, ) # Check that the tool returned a result assert result.data == output_path_smaller # Verify the file exists assert os.path.exists(output_path_smaller) # Verify the resized image dimensions img = cv2.imread(output_path_smaller) assert img.shape[:2] == (100, 150) # height, width # Test upscaling output_path_larger = str(tmp_path / f"output_{method}_larger.png") async with Client(mcp_server) as client: result = await client.call_tool( "resize", { "input_path": test_image_path, "width": 600, "height": 400, "interpolation": method, "output_path": output_path_larger, }, ) # Check that the tool returned a result assert result.data == output_path_larger # Verify the file exists assert os.path.exists(output_path_larger) # Verify the resized image dimensions img = cv2.imread(output_path_larger) assert img.shape[:2] == (400, 600) # height, width

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/sunriseapps/imagesorcery-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server