Skip to main content
Glama

Code Screenshot Generator

index.ts10.4 kB
#!/usr/bin/env node /** * Code Screenshot Generator MCP Server * Generates beautiful code screenshots directly from Claude */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import { generateScreenshot, screenshotFromFile, screenshotGitDiff, batchScreenshot, closeBrowser } from "./generator.js"; import { themes } from "./templates.js"; // Server instance const server = new Server( { name: "code-screenshot-mcp", version: "0.1.0", }, { capabilities: { tools: {}, }, } ); // List available tools server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "generate_code_screenshot", description: "Generate a beautiful screenshot of code with syntax highlighting and themes", inputSchema: { type: "object", properties: { code: { type: "string", description: "The code to screenshot", }, language: { type: "string", description: "Programming language (e.g., javascript, python, rust)", }, theme: { type: "string", description: "Color theme (dracula, nord, monokai, github-light, github-dark)", enum: ["dracula", "nord", "monokai", "github-light", "github-dark"], }, }, required: ["code", "language"], }, }, { name: "screenshot_from_file", description: "Screenshot code directly from a file path, with optional line range selection. Auto-detects language from file extension.", inputSchema: { type: "object", properties: { filePath: { type: "string", description: "Path to the code file", }, startLine: { type: "number", description: "Start line number (1-indexed, optional)", }, endLine: { type: "number", description: "End line number (optional)", }, theme: { type: "string", description: "Color theme (dracula, nord, monokai, github-light, github-dark)", enum: ["dracula", "nord", "monokai", "github-light", "github-dark"], }, }, required: ["filePath"], }, }, { name: "screenshot_git_diff", description: "Generate a screenshot of git diff output. Shows changes in your working directory or staged changes.", inputSchema: { type: "object", properties: { filePath: { type: "string", description: "Optional: Specific file to diff. If not provided, shows diff for all changes.", }, staged: { type: "boolean", description: "Show staged changes (git diff --staged) instead of unstaged changes", }, theme: { type: "string", description: "Color theme (dracula, nord, monokai, github-light, github-dark)", enum: ["dracula", "nord", "monokai", "github-light", "github-dark"], }, }, required: [], }, }, { name: "batch_screenshot", description: "Generate screenshots for multiple files at once. Useful for documenting multiple code files quickly.", inputSchema: { type: "object", properties: { filePaths: { type: "array", items: { type: "string", }, description: "Array of file paths to screenshot", }, theme: { type: "string", description: "Color theme to apply to all screenshots (dracula, nord, monokai, github-light, github-dark)", enum: ["dracula", "nord", "monokai", "github-light", "github-dark"], }, }, required: ["filePaths"], }, }, ], }; }); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (name === "generate_code_screenshot") { if (!args) { throw new Error("Arguments are required"); } try { const { code, language, theme = "dracula" } = args as { code: string; language: string; theme?: string; }; if (!code || !language) { throw new Error("Both 'code' and 'language' are required"); } // Generate the screenshot const result = await generateScreenshot({ code, language, theme, }); return { content: [ { type: "text", text: `✅ Screenshot generated successfully!\n\nFile saved to: ${result.path}\n\nTheme: ${theme}\nLanguage: ${language}\n\nYou can view the image in your file browser.`, }, { type: "image", data: result.base64, mimeType: "image/png", }, ], }; } catch (error) { return { content: [ { type: "text", text: `❌ Error generating screenshot: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } } if (name === "screenshot_from_file") { if (!args) { throw new Error("Arguments are required"); } try { const { filePath, startLine, endLine, theme = "dracula" } = args as { filePath: string; startLine?: number; endLine?: number; theme?: string; }; if (!filePath) { throw new Error("filePath is required"); } // Generate the screenshot from file const result = await screenshotFromFile({ filePath, startLine, endLine, theme, }); const lineInfo = startLine || endLine ? `\nLines: ${startLine || 1}-${endLine || 'end'}` : '\nFull file'; return { content: [ { type: "text", text: `✅ Screenshot from file generated successfully!\n\nFile: ${filePath}${lineInfo}\nSaved to: ${result.path}\n\nTheme: ${theme}\n\nYou can view the image in your file browser.`, }, { type: "image", data: result.base64, mimeType: "image/png", }, ], }; } catch (error) { return { content: [ { type: "text", text: `❌ Error generating screenshot from file: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } } if (name === "screenshot_git_diff") { try { const { filePath, staged, theme = "dracula" } = (args || {}) as { filePath?: string; staged?: boolean; theme?: string; }; // Generate the screenshot from git diff const result = await screenshotGitDiff({ filePath, staged, theme, }); const diffType = staged ? "Staged changes" : "Unstaged changes"; const fileInfo = filePath ? `\nFile: ${filePath}` : "\nAll files"; return { content: [ { type: "text", text: `✅ Git diff screenshot generated successfully!\n\n${diffType}${fileInfo}\nSaved to: ${result.path}\n\nTheme: ${theme}\n\nYou can view the image in your file browser.`, }, { type: "image", data: result.base64, mimeType: "image/png", }, ], }; } catch (error) { return { content: [ { type: "text", text: `❌ Error generating git diff screenshot: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } } if (name === "batch_screenshot") { if (!args) { throw new Error("Arguments are required"); } try { const { filePaths, theme = "dracula" } = args as { filePaths: string[]; theme?: string; }; if (!filePaths || !Array.isArray(filePaths) || filePaths.length === 0) { throw new Error("filePaths array is required and must not be empty"); } // Generate batch screenshots const batchResult = await batchScreenshot({ filePaths, theme, }); // Build response content const content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> = [ { type: "text", text: `✅ Batch screenshot completed!\n\nTotal files: ${filePaths.length}\nSuccessful: ${batchResult.successCount}\nFailed: ${batchResult.failureCount}\n\nTheme: ${theme}\n\n`, }, ]; // Add each screenshot or error message for (const result of batchResult.results) { if (result.error) { content[0].text += `\n❌ ${result.filePath}: ${result.error}`; } else { content[0].text += `\n✅ ${result.filePath}: ${result.screenshot.path}`; content.push({ type: "image", data: result.screenshot.base64, mimeType: "image/png", }); } } return { content }; } catch (error) { return { content: [ { type: "text", text: `❌ Error in batch screenshot: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } } throw new Error(`Unknown tool: ${name}`); }); // Start the server async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Code Screenshot MCP Server running on stdio"); } // Graceful shutdown process.on("SIGINT", async () => { console.error("Shutting down..."); await closeBrowser(); process.exit(0); }); main().catch(async (error) => { console.error("Fatal error:", error); await closeBrowser(); process.exit(1); });

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/MoussaabBadla/code-screenshot-mcp'

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