Skip to main content
Glama
editTool.ts6.49 kB
import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { TextContent, RequestMeta } from '@modelcontextprotocol/sdk/types.js'; import { z } from 'zod'; import { zodToJsonSchema } from 'zod-to-json-schema'; import * as svgmakerService from '../services/svgmakerService.js'; import * as fileUtils from '../utils/fileUtils.js'; import { logToFile } from '../utils/logUtils.js'; import { ProgressManager } from '../utils/progressUtils.js'; const EditToolInputSchema = z.object({ input_path: z .string() .min(1, 'Input path cannot be empty.') .describe( 'Absolute path to the existing image/SVG file to be edited. Supports various formats including PNG, JPEG, SVG, and other common image types. Example: "/Users/username/Documents/logo.svg"' ), prompt: z .string() .min(1, 'Prompt cannot be empty.') .describe( 'Detailed instructions for how to modify the image. Be specific about changes like style adjustments, color modifications, element additions/removals, or layout changes. Example: "Change the background to blue and add a white border"' ), output_path: z .string() .min(1, 'Output path cannot be empty.') .describe( 'Absolute file path where the generated SVG will be saved. Must include the .svg extension. Example: "/Users/username/Documents/modified-artwork.svg"' ), quality: z .enum(['low', 'medium', 'high']) .optional() .default('medium') .describe( 'Quality level for SVG editing. Do not specifiy if not explicitely mentioned by the user. Affects processing time and detail level: low (fast, basic edits), medium (balanced quality and speed, default), high (best quality, forces square aspect ratio)' ), aspectRatio: z .enum(['auto', 'portrait', 'landscape', 'square']) .optional() .describe( 'Aspect ratio for the edited SVG: auto (maintain original proportions), square (1:1, good for logos), portrait (taller, good for posters), landscape (wider, good for banners). Do not specifiy if not explicitely mentioned by the user. When not specified the quality will determine the default (low and medium use auto, high forces square aspect ratio)' ), background: z .enum(['auto', 'transparent', 'opaque']) .optional() .default('auto') .describe( 'Background style for the edited SVG: auto (AI determines best, default), transparent (no background, preserves transparency), opaque (solid background color). Do not specify if not explicitly mentioned by the user.' ), }); export const editToolDefinition = { name: 'svgmaker_edit', description: 'Edits an existing image/SVG file based on a text prompt using SVGMaker API and saves it to a specified local path. Provide specific instructions on how to modify the image, including style changes, color adjustments, element additions or removals, and layout modifications.', inputSchema: zodToJsonSchema(EditToolInputSchema), }; export async function handleEditTool( server: Server, request: { params: { name: string; _meta?: RequestMeta; arguments?: any } } ) { const { arguments: args } = request.params; // Log that the tool is being called logToFile('========== SVG EDIT TOOL CALLED =========='); logToFile(`Arguments: ${JSON.stringify(args, null, 2)}`); logToFile(`Request meta: ${JSON.stringify(request.params._meta, null, 2)}`); try { const validatedArgs = EditToolInputSchema.parse(args); // Note: In a real implementation, we'd need to get roots from the client // For now, we'll use a simple path validation const clientRoots: any[] = []; // server.getRoots() is not available in this SDK version const validatedInputPath = await fileUtils.resolveAndValidatePath( validatedArgs.input_path, clientRoots, 'read' ); const validatedOutputPath = await fileUtils.resolveAndValidatePath( validatedArgs.output_path, clientRoots, 'write' ); // Read the input file const inputImage = await fileUtils.readFileToBuffer(validatedInputPath); // Determine aspect ratio based on quality and explicit aspectRatio let finalAspectRatio = validatedArgs.aspectRatio; if (!finalAspectRatio) { if (validatedArgs.quality === 'high') { finalAspectRatio = 'square'; } else { finalAspectRatio = 'auto' as any; // low and medium use auto } } const progressManager = new ProgressManager({ server, progressToken: request.params._meta?.progressToken, totalSteps: 4, messages: { initial: 'Initializing SVG editing...', preparing: 'Preparing image for editing...', processing: 'AI is editing your SVG...', saving: 'Saving edited SVG file...', complete: 'SVG editing complete!', }, }); // Send initial progress await progressManager.sendInitialProgress(); try { const sdkParams = { image: inputImage, prompt: validatedArgs.prompt, quality: validatedArgs.quality, aspectRatio: finalAspectRatio, background: validatedArgs.background, svgText: true, }; // Update progress: preparing request await progressManager.sendPreparingProgress(); // Update progress: making API call with periodic updates await progressManager.startProcessingProgress(); let result; try { // The actual API call result = await svgmakerService.editSVG(sdkParams as any); } finally { // Clean up the progress interval progressManager.stopProcessingProgress(); } // Update progress: processing complete await progressManager.sendSavingProgress(); if (result.svgText) { await fileUtils.writeFile(validatedOutputPath, result.svgText); // Send final progress await progressManager.sendFinalProgress(); return { content: [ { type: 'text', text: `SVG edited successfully: ${validatedOutputPath}`, } as TextContent, ], }; } else { throw new Error('SVGMaker API did not return SVG content.'); } } catch (error: any) { // Ensure cleanup on error progressManager.cleanup(); throw error; } } catch (error: any) { return { isError: true, content: [{ type: 'text', text: `Error editing SVG: ${error.message}` } as TextContent], }; } }

Latest Blog Posts

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/GenWaveLLC/svgmaker-mcp'

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