Skip to main content
Glama

take_screenshot

Capture a screenshot of any Electron application window and return base64 image data. Optionally save the image to a specified path for further AI analysis or processing.

Instructions

Take a screenshot of any running Electron application window. Returns base64 image data for AI analysis. No files created unless outputPath is specified.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
outputPathNoPath to save the screenshot (optional, defaults to temp directory)
windowTitleNoSpecific window title to screenshot (optional)

Implementation Reference

  • Core handler function that connects to running Electron apps via Chrome DevTools Protocol (CDP), takes a screenshot of the target page, encrypts the image data, optionally saves to file, and returns base64-encoded image for AI analysis.
    export async function takeScreenshot(
      outputPath?: string,
      windowTitle?: string,
    ): Promise<{
      filePath?: string;
      base64: string;
      data: string;
      error?: string;
    }> {
      // Validate output path for security
      if (outputPath && !validateScreenshotPath(outputPath)) {
        throw new Error(
          `Invalid output path: ${outputPath}. Path appears to target a restricted system location.`,
        );
      }
    
      // Inform user about screenshot
      logger.info('📸 Taking screenshot of Electron application', {
        outputPath,
        windowTitle,
        timestamp: new Date().toISOString(),
      });
      try {
        // Find running Electron applications
        const apps = await scanForElectronApps();
        if (apps.length === 0) {
          throw new Error('No running Electron applications found with remote debugging enabled');
        }
    
        // Use the first app found (or find by title if specified)
        let targetApp = apps[0];
        if (windowTitle) {
          const namedApp = apps.find((app) =>
            app.targets.some((target) =>
              target.title?.toLowerCase().includes(windowTitle.toLowerCase()),
            ),
          );
          if (namedApp) {
            targetApp = namedApp;
          }
        }
    
        // Connect to the Electron app's debugging port
        const browser = await chromium.connectOverCDP(`http://localhost:${targetApp.port}`);
        const contexts = browser.contexts();
    
        if (contexts.length === 0) {
          throw new Error(
            'No browser contexts found - make sure Electron app is running with remote debugging enabled',
          );
        }
    
        const context = contexts[0];
        const pages = context.pages();
    
        if (pages.length === 0) {
          throw new Error('No pages found in the browser context');
        }
    
        // Find the main application page (skip DevTools pages)
        let targetPage = pages[0];
        for (const page of pages) {
          const url = page.url();
          const title = await page.title().catch(() => '');
    
          // Skip DevTools and about:blank pages
          if (
            !url.includes('devtools://') &&
            !url.includes('about:blank') &&
            title &&
            !title.includes('DevTools')
          ) {
            // If windowTitle is specified, try to match it
            if (windowTitle && title.toLowerCase().includes(windowTitle.toLowerCase())) {
              targetPage = page;
              break;
            } else if (!windowTitle) {
              targetPage = page;
              break;
            }
          }
        }
    
        logger.info(`Taking screenshot of page: ${targetPage.url()} (${await targetPage.title()})`);
    
        // Take screenshot as buffer (in memory)
        const screenshotBuffer = await targetPage.screenshot({
          type: 'png',
          fullPage: false,
        });
    
        await browser.close();
    
        // Encrypt screenshot data for security
        const encryptedScreenshot = encryptScreenshotData(screenshotBuffer);
    
        // Convert buffer to base64 for transmission
        const base64Data = screenshotBuffer.toString('base64');
        logger.info(
          `Screenshot captured and encrypted successfully (${screenshotBuffer.length} bytes)`,
        );
    
        // If outputPath is provided, save encrypted data to file
        if (outputPath) {
          await fs.writeFile(outputPath + '.encrypted', JSON.stringify(encryptedScreenshot));
          // Also save unencrypted for compatibility (in production, consider removing this)
          await fs.writeFile(outputPath, screenshotBuffer);
          return {
            filePath: outputPath,
            base64: base64Data,
            data: `Screenshot saved to: ${outputPath} (encrypted backup: ${outputPath}.encrypted) and returned as base64 data`,
          };
        } else {
          return {
            base64: base64Data,
            data: `Screenshot captured as base64 data (${screenshotBuffer.length} bytes) - no file saved`,
          };
        }
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        throw new Error(
          `Screenshot failed: ${errorMessage}. Make sure the Electron app is running with remote debugging enabled (--remote-debugging-port=9222)`,
        );
      }
    }
  • Zod schema defining the input parameters for the take_screenshot tool: optional outputPath and windowTitle.
    export const TakeScreenshotSchema = z.object({
      outputPath: z
        .string()
        .optional()
        .describe('Path to save the screenshot (optional, defaults to temp directory)'),
      windowTitle: z.string().optional().describe('Specific window title to screenshot (optional)'),
    });
  • src/tools.ts:26-31 (registration)
    Tool registration in the tools array, defining name 'take_screenshot', description, and input schema.
    {
      name: ToolName.TAKE_SCREENSHOT,
      description:
        'Take a screenshot of any running Electron application window. Returns base64 image data for AI analysis. No files created unless outputPath is specified.',
      inputSchema: zodToJsonSchema(TakeScreenshotSchema) as ToolInput,
    },
  • src/handlers.ts:62-109 (registration)
    Handler dispatch in handleToolCall switch statement: validates args, calls takeScreenshot, and formats MCP response with base64 image.
    case ToolName.TAKE_SCREENSHOT: {
      // Security check for screenshot operation
      const securityResult = await securityManager.executeSecurely({
        command: 'take_screenshot',
        args,
        sourceIP,
        userAgent,
        operationType: 'screenshot',
      });
    
      if (securityResult.blocked) {
        return {
          content: [
            {
              type: 'text',
              text: `Screenshot blocked: ${securityResult.error}`,
            },
          ],
          isError: true,
        };
      }
      const { outputPath, windowTitle } = TakeScreenshotSchema.parse(args);
      const result = await takeScreenshot(outputPath, windowTitle);
    
      // Return the screenshot as base64 data for AI to evaluate
      const content: any[] = [];
    
      if (result.filePath) {
        content.push({
          type: 'text',
          text: `Screenshot saved to: ${result.filePath}`,
        });
      } else {
        content.push({
          type: 'text',
          text: 'Screenshot captured in memory (no file saved)',
        });
      }
    
      // Add the image data for AI evaluation
      content.push({
        type: 'image',
        data: result.base64!,
        mimeType: 'image/png',
      });
    
      return { content, isError: false };
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses key behavioral traits: that it returns base64 image data, creates no files by default, and only creates files when outputPath is specified. However, it doesn't mention potential limitations like what happens if no Electron windows are running, performance characteristics, or error conditions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is perfectly concise with three sentences that each earn their place: states the action and target, specifies the return format and purpose, and clarifies the file creation behavior. No wasted words, front-loaded with the core functionality.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a screenshot tool with 2 parameters, 100% schema coverage, and no output schema, the description provides good context about what the tool does and its behavior. However, without annotations or output schema, it could benefit from more detail about the return format structure or error handling, though the base64 return is mentioned.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents both parameters well. The description adds minimal value beyond the schema - it mentions that outputPath is optional and defaults to temp directory (already in schema) and implies windowTitle is optional (already in schema). Baseline 3 is appropriate when schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Take a screenshot') and resource ('any running Electron application window'), distinguishing it from sibling tools like get_electron_window_info (which provides info) or send_command_to_electron (which sends commands). It explicitly mentions what the tool does and what it returns.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context about when to use this tool (for capturing screenshots of Electron apps for AI analysis) and mentions the optional outputPath parameter for file creation. However, it doesn't explicitly state when NOT to use it or name specific alternatives among the sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

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/halilural/electron-mcp-server'

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