generate_qr_code
Create QR codes for shortened URLs with customizable size, format, and margin. Integrates with YOURLS-MCP to simplify sharing and tracking.
Instructions
Generate a QR code for a shortened URL
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| format | No | Image format (png, svg, etc.) | |
| margin | No | Margin size | |
| shorturl | Yes | The short URL to generate a QR code for | |
| size | No | Size of the QR code in pixels |
Implementation Reference
- src/tools/generateQrCode.js:43-115 (handler)The main handler function (execute) for the generate_qr_code MCP tool. Validates inputs, calls yourlsClient.generateQrCode, and formats the MCP response.execute: async ({ shorturl, size, border, ecc, format }) => { try { // Validate size if provided if (size !== undefined) { const sizeNum = Number(size); if (isNaN(sizeNum) || sizeNum <= 0) { throw new Error('Size must be a positive number'); } // Add upper limit check for QR code size if (sizeNum > 1000) { throw new Error('QR code size cannot exceed 1000 pixels for performance reasons'); } } // Validate border if provided if (border !== undefined) { const borderNum = Number(border); if (isNaN(borderNum) || borderNum < 0) { throw new Error('Border must be a non-negative number'); } } // Validate ecc if provided if (ecc && !['L', 'M', 'Q', 'H'].includes(ecc.toUpperCase())) { throw new Error(`Error correction level '${ecc}' is not supported. Must be one of: L (low), M (medium), Q (quartile), or H (high)`); } // Normalize ecc to uppercase if (ecc) { ecc = ecc.toUpperCase(); } // Validate format if provided if (format && !['png', 'jpg', 'jpeg', 'gif', 'svg'].includes(format.toLowerCase())) { throw new Error(`Format '${format}' is not supported. Must be one of: png, jpg, jpeg, gif, svg`); } // Define MIME type mapping to ensure consistency const formatToMimeType = { 'png': 'image/png', 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'svg': 'image/svg+xml', 'gif': 'image/gif' }; // Generate QR code const result = await yourlsClient.generateQrCode(shorturl, { size: size !== undefined ? Number(size) : undefined, border: border !== undefined ? Number(border) : undefined, ecc, format }); if (result.status === 'success') { return createMcpResponse(true, { shorturl: shorturl, data: result.data, contentType: result.contentType, url: result.url, config: result.config }); } else { throw new Error(result.message || 'Unknown error'); } } catch (error) { return createMcpResponse(false, { message: error.message, shorturl: shorturl }); } }
- src/tools/generateQrCode.js:17-42 (schema)Input schema definition for the generate_qr_code tool, defining parameters and validation rules.inputSchema: { type: 'object', properties: { shorturl: { type: 'string', description: 'The short URL or keyword to generate a QR code for' }, size: { type: 'number', description: 'QR code size in pixels (default: depends on plugin configuration)' }, border: { type: 'number', description: 'Border width around the QR code (default: depends on plugin configuration)' }, ecc: { type: 'string', description: 'Error correction level: L (low), M (medium), Q (quartile), or H (high)' }, format: { type: 'string', description: 'Image format (e.g., png, jpg, svg)' } }, required: ['shorturl'] },
- src/index.js:242-252 (registration)Registration of the generate_qr_code tool on the MCP server in the main entry point.server.tool( generateQrCodeTool.name, generateQrCodeTool.description, { shorturl: z.string().describe('The short URL to generate a QR code for'), size: z.number().optional().describe('Size of the QR code in pixels'), format: z.string().optional().describe('Image format (png, svg, etc.)'), margin: z.number().optional().describe('Margin size') }, generateQrCodeTool.execute );
- src/api.js:1194-1304 (helper)Underlying YOURLS API client method that generates the QR code image by calling the YOURLS-IQRCodes plugin endpoint.async generateQrCode(shorturl, { size, border, ecc, format } = {}) { // Define MIME type mapping to ensure consistency const formatToMimeType = { 'png': 'image/png', 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', 'svg': 'image/svg+xml', 'gif': 'image/gif' }; try { // First check if the shorturl exists await this.expand(shorturl); // Construct the QR code URL (YOURLS-IQRCodes plugin appends .qr to the shorturl) const baseUrl = this.api_url.replace('yourls-api.php', ''); let qrUrl = `${baseUrl}${shorturl}.qr`; // Validate and normalize the parameters let normalizedSize, normalizedBorder, normalizedEcc, normalizedFormat; // Validate size if (size !== undefined) { normalizedSize = Number(size); if (isNaN(normalizedSize) || normalizedSize <= 0) { throw new Error('Size must be a positive number'); } if (normalizedSize > 1000) { throw new Error('QR code size cannot exceed 1000 pixels for performance reasons'); } } // Validate border if (border !== undefined) { normalizedBorder = Number(border); if (isNaN(normalizedBorder) || normalizedBorder < 0) { throw new Error('Border must be a non-negative number'); } } // Validate and normalize ECC if (ecc !== undefined) { if (!['L', 'M', 'Q', 'H', 'l', 'm', 'q', 'h'].includes(ecc)) { throw new Error(`Error correction level '${ecc}' is not supported. Must be one of: L, M, Q, H`); } normalizedEcc = ecc.toUpperCase(); } // Validate and normalize format if (format !== undefined) { normalizedFormat = format.toLowerCase(); if (!Object.keys(formatToMimeType).includes(normalizedFormat)) { throw new Error(`Format '${format}' is not supported. Must be one of: png, jpg, jpeg, gif, svg`); } } // Add query parameters if provided const params = new URLSearchParams(); if (normalizedSize !== undefined) params.append('size', normalizedSize); if (normalizedBorder !== undefined) params.append('border', normalizedBorder); if (normalizedEcc !== undefined) params.append('ecc', normalizedEcc); if (normalizedFormat !== undefined) params.append('format', normalizedFormat); const queryString = params.toString(); if (queryString) { qrUrl += `?${queryString}`; } // Fetch the QR code image const response = await axios.get(qrUrl, { responseType: 'arraybuffer' }); // Convert to base64 const base64Image = Buffer.from(response.data, 'binary').toString('base64'); // Determine MIME type - use our mapping if we know the format, otherwise use server-provided const contentType = normalizedFormat ? formatToMimeType[normalizedFormat] : (response.headers['content-type'] || 'image/png'); return { status: 'success', data: base64Image, contentType: contentType, url: qrUrl, config: { size: normalizedSize, border: normalizedBorder, ecc: normalizedEcc, format: normalizedFormat } }; } catch (error) { // If the error is from the expand method (meaning the shorturl doesn't exist) if (error.response && error.response.status === 404) { throw new Error(`The short URL or keyword '${shorturl}' was not found in the database.`); } // If the error is from fetching the QR code (meaning the IQRCodes plugin isn't installed) if (error.response && (error.response.status === 404 || error.response.status === 500 || error.response.status === 501)) { throw new Error('QR code generation is not available. Please install the YOURLS-IQRCodes plugin.'); } // For other errors, just throw them throw error; } }
- src/tools/index.js:196-206 (registration)Alternative registration of the tool in the tools index module (not used in main entry).server.tool( generateQrCodeTool.name, generateQrCodeTool.description, { shorturl: z.string().describe('The short URL to generate a QR code for'), size: z.number().optional().describe('Size of the QR code in pixels'), format: z.string().optional().describe('Image format (png, svg, etc.)'), margin: z.number().optional().describe('Margin size') }, generateQrCodeTool.execute );