Skip to main content
Glama

AiDD MCP Server

by skydeckai
import base64 import io import os from mcp.types import TextContent from PIL import Image from .state import state # Maximum file size (100MB) MAX_FILE_SIZE = 100 * 1024 * 1024 # Image size constraints MIN_WIDTH = 20 MAX_WIDTH = 800 def read_image_file_tool(): return { "name": "read_image_file", "description": "Read an image file from the file system and return its contents as a base64-encoded string. " "WHEN TO USE: When you need to view or process image files, include images in responses, analyze " "image content, or convert images to a format that can be transmitted as text. Useful for examining " "screenshots, diagrams, photos, or any visual content stored in the file system. " "WHEN NOT TO USE: When you only need information about the image file without its contents " "(use get_file_info instead), when working with extremely large images (over 100MB), or when you " "need to read text files (use read_file instead). " "RETURNS: A base64-encoded data URI string prefixed with the appropriate MIME type " "(e.g., 'data:image/png;base64,...'). Images that are very small or very large will be automatically " "resized to between 20-800 pixels wide while maintaining aspect ratio. This tool supports common image " "formats like PNG, JPEG, GIF, and WebP. Only works within the allowed directory.", "inputSchema": { "type": "object", "properties": { "path": { "type": "string", "description": "Path to the image file to read. This must be a valid image file in a supported format " "(PNG, JPEG, GIF, WebP). Examples: 'screenshots/screen.png', 'images/logo.jpg', " "'diagrams/flowchart.gif'. Both absolute and relative paths are supported, but must be " "within the allowed workspace." }, "max_size": { "type": "integer", "description": "Maximum file size in bytes to allow. Files larger than this size will be rejected to " "prevent memory issues. Default is 100MB (104,857,600 bytes). For most use cases, the " "default value is sufficient, but you can lower this when working with limited memory.", "optional": True } }, "required": ["path"] }, } async def handle_read_image_file(arguments: dict): """Handle reading an image file and converting it to base64.""" path = arguments.get("path") max_size = arguments.get("max_size", MAX_FILE_SIZE) if not path: raise ValueError("path must be provided") # Determine full path based on whether input is absolute or relative if os.path.isabs(path): full_path = os.path.abspath(path) # Just normalize the absolute path else: # For relative paths, join with allowed_directory full_path = os.path.abspath(os.path.join(state.allowed_directory, path)) if not full_path.startswith(state.allowed_directory): raise ValueError(f"Access denied: Path ({full_path}) must be within allowed directory ({state.allowed_directory})") if not os.path.exists(full_path): raise ValueError(f"File does not exist: {full_path}") if not os.path.isfile(full_path): raise ValueError(f"Path is not a file: {full_path}") # Check file size before attempting to read file_size = os.path.getsize(full_path) if file_size > max_size: raise ValueError(f"File size ({file_size} bytes) exceeds maximum allowed size ({max_size} bytes)") try: # Try to open the image with PIL to validate it's a valid image with Image.open(full_path) as img: # Get the image format image_format = img.format.lower() if not image_format: # Try to determine format from file extension ext = os.path.splitext(full_path)[1].lower().lstrip('.') if ext in ['jpg', 'jpeg']: image_format = 'jpeg' elif ext in ['png', 'gif', 'webp']: image_format = ext else: raise ValueError(f"Unsupported image format: {ext}") # Resize image if width is greater than MAX_WIDTH or less than MIN_WIDTH if img.width > MAX_WIDTH or img.width < MIN_WIDTH: # Calculate new dimensions maintaining aspect ratio if img.width > MAX_WIDTH: target_width = MAX_WIDTH else: target_width = MIN_WIDTH ratio = target_width / img.width new_height = int(img.height * ratio) img = img.resize((target_width, new_height), Image.Resampling.LANCZOS) # Convert image to bytes img_byte_arr = io.BytesIO() if image_format.lower() == 'jpeg': img.save(img_byte_arr, format=image_format, quality=85) # Specify quality for JPEG else: img.save(img_byte_arr, format=image_format) img_byte_arr = img_byte_arr.getvalue() # Convert to base64 base64_data = base64.b64encode(img_byte_arr).decode('utf-8') # Return the image data with its type return [TextContent( type="text", text=f"data:image/{image_format};base64,{base64_data}" )] except Image.UnidentifiedImageError: raise ValueError(f"File is not a valid image: {path}") except Exception as e: raise ValueError(f"Error reading image file: {str(e)}")

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/skydeckai/mcp-server-aidd'

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