glasses-mcp
Version:
A Model Context Protocol (MCP) server that provides a tool for taking screenshots of websites.
69 lines (68 loc) • 2.43 kB
JavaScript
import { z } from "zod";
import puppeteer, { KnownDevices } from "puppeteer";
function isScreenshotPath(path) {
return path.endsWith(".png") || path.endsWith(".jpeg");
}
const DEVICE_ID_MAP = {
'ios-large': 'iPhone 14 Pro Max',
'ios-small': 'iPhone SE',
'android-large': 'Pixel 6 Pro',
'android-medium': 'Galaxy S8',
'tablet-large': 'iPad Pro 11',
'tablet-small': 'iPad Mini',
'laptop-hidpi': 'Laptop with HiDPI screen',
'laptop-mdpi': 'Laptop with MDPI screen',
};
const screenshotSchema = z.object({
url: z.string().url(),
outputPath: z.string(),
format: z.enum(["png", "jpeg"]).optional(),
fullPage: z.boolean().optional(),
device: z.enum(Object.keys(DEVICE_ID_MAP)).default('laptop-hidpi'),
});
export const screenshotTool = {
title: "Website Screenshot",
description: "Takes a screenshot of a website.",
inputSchema: screenshotSchema.shape,
};
export const screenshotHandler = async ({ url, outputPath, format = "png", fullPage = true, device }) => {
try {
// Ensure the output path has the correct extension
const extension = `.${format}`;
let path = outputPath.endsWith(extension) ? outputPath : `${outputPath}${extension}`;
if (!isScreenshotPath(path)) {
// This should not happen due to the logic above, but it satisfies TypeScript
throw new Error("Invalid screenshot path");
}
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
const deviceName = DEVICE_ID_MAP[device];
const deviceToEmulate = KnownDevices[deviceName];
await page.emulate(deviceToEmulate);
await page.goto(url, { waitUntil: "networkidle2" });
await page.screenshot({ path, type: format, fullPage });
await browser.close();
return {
content: [
{
type: "text",
text: JSON.stringify({ success: true, outputPath: path }),
},
],
};
}
catch (error) {
return {
content: [
{
type: "text",
text: JSON.stringify({ success: false, error: error.message }),
},
],
isError: true,
};
}
};