Skip to main content
Glama
kesslerio

YOURLS-MCP

by kesslerio

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
NameRequiredDescriptionDefault
formatNoImage format (png, svg, etc.)
marginNoMargin size
shorturlYesThe short URL to generate a QR code for
sizeNoSize of the QR code in pixels

Implementation Reference

  • 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
        });
      }
    }
  • 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
    );
  • 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;
      }
    }
  • 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
    );
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/kesslerio/yourls-mcp'

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