@jwalsh/mcp-server-qrcode
Version:
Model Context Protocol server for generating QR codes
105 lines (104 loc) • 3.94 kB
JavaScript
/**
* QR Code Generator Core Functionality
*
* This module provides QR code generation capabilities that can be used
* by both the CLI interface and MCP server implementation.
*/
import * as qrcode from 'qrcode';
import { exec } from 'child_process';
import { promisify } from 'util';
import { readFile } from 'fs/promises';
import { tmpdir } from 'os';
import { join } from 'path';
import { randomUUID } from 'crypto';
const execAsync = promisify(exec);
/**
* Generate a QR code with various output formats
*/
export async function generateQRCode(options) {
const { content, size = 200, errorCorrectionLevel = 'M', format = 'dataURL' } = options;
if (!content) {
throw new Error('Content is required for QR code generation');
}
if (size < 100 || size > 1000) {
throw new Error('QR code size must be between 100 and 1000 pixels');
}
try {
// Different output formats
if (format === 'dataURL') {
// Generate QR code as data URL (base64 image)
const dataUrl = await qrcode.toDataURL(content, {
width: size,
errorCorrectionLevel,
});
return {
content,
format: 'dataURL',
data: dataUrl,
mimeType: 'image/png',
};
}
else if (format === 'utf8' || format === 'terminal') {
// Generate QR code as UTF8 text
try {
// Try to use system qrencode for best terminal output
const sizeOption = Math.max(1, Math.floor(size / 100)); // Convert pixel size to qrencode size (1-10)
const { stdout } = await execAsync(`qrencode -o - -t UTF8 -l ${errorCorrectionLevel} -s ${sizeOption} '${content.replace(/'/g, "'\\''")}'`);
return {
content,
format: 'terminal',
data: stdout,
};
}
catch (err) {
// Fallback to qrcode library if qrencode not available
const qrCodeText = await qrcode.toString(content, {
type: format === 'terminal' ? 'terminal' : 'utf8',
errorCorrectionLevel,
});
return {
content,
format: format,
data: qrCodeText,
};
}
}
else if (format === 'png' || format === 'base64') {
// For MCP server - generate QR code as PNG and return as base64
const tempFilePath = join(tmpdir(), `qrcode-${randomUUID()}.png`);
try {
// Try using qrencode first (better quality)
const sizeOption = Math.max(1, Math.floor(size / 100));
await execAsync(`qrencode -o "${tempFilePath}" -l ${errorCorrectionLevel} -s ${sizeOption} '${content.replace(/'/g, "'\\''")}'`);
}
catch (err) {
// Fallback to qrcode library
await qrcode.toFile(tempFilePath, content, {
width: size,
errorCorrectionLevel,
});
}
// Read the file as buffer and encode as base64
const imageBuffer = await readFile(tempFilePath);
const base64Image = imageBuffer.toString('base64');
return {
content,
format: 'base64',
data: base64Image,
mimeType: 'image/png',
};
}
else {
throw new Error(`Unsupported format: ${format}`);
}
}
catch (error) {
throw new Error(`QR code generation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Validate QR code input content
*/
export function validateQRCodeInput(content) {
return content.trim().length > 0;
}