Skip to main content
Glama
Nam0101

android-mcp-toolkit

SVG to VectorDrawable

convert-svg-to-android-drawable

Convert SVG markup or files to Android VectorDrawable XML. Configure decimal precision, tint color, fill black, XML tag, and caching. Optionally write output to disk.

Instructions

Convert SVG markup or files into Android VectorDrawable XML quickly, optionally writing to disk.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
svgNoInline SVG markup to convert
svgPathNoPath to an SVG file to read
outputPathNoOptional output path for generated VectorDrawable XML
floatPrecisionNoDecimal precision when serializing coordinates
fillBlackNoForce fill color black when missing
xmlTagNoInclude XML declaration
tintNoAndroid tint color (e.g. #FF000000)
cacheNoReuse cached result for identical inputs within this process

Implementation Reference

  • Tool registration for 'convert-svg-to-android-drawable' — registers the tool with input schema and the async handler function that loads SVG, converts via svg2vectordrawable, caches results, optionally writes output, and returns the XML.
    function registerSvgTool(server) {
      server.registerTool(
        'convert-svg-to-android-drawable',
        {
          title: 'SVG to VectorDrawable',
          description:
            'Convert SVG markup or files into Android VectorDrawable XML quickly, optionally writing to disk.',
          inputSchema: convertInputSchema
        },
        async (params, extra) => {
          const svgCode = await loadSvg(params);
          const options = {
            floatPrecision: params.floatPrecision,
            fillBlack: params.fillBlack,
            xmlTag: params.xmlTag,
            tint: params.tint
          };
    
          const cacheKey = makeCacheKey(svgCode, options);
          const startTime = process.hrtime.bigint();
    
          let xml = null;
          if (params.cache) {
            xml = getCached(cacheKey);
          }
    
          if (!xml) {
            xml = await svg2vectordrawable(svgCode, options);
            if (!xml || typeof xml !== 'string') {
              throw new Error('Conversion did not produce XML');
            }
            setCache(cacheKey, xml);
          }
    
          const savedPath = await maybeWriteOutput(params.outputPath, xml);
          const elapsedMs = Number(process.hrtime.bigint() - startTime) / 1_000_000;
    
          if (extra && typeof extra.sessionId === 'string') {
            server
              .sendLoggingMessage(
                {
                  level: 'info',
                  data:
                    `Converted SVG in ${elapsedMs.toFixed(2)}ms` +
                    (savedPath ? ` (saved to ${savedPath})` : '')
                },
                extra.sessionId
              )
              .catch(() => {
                /* best-effort logging */
              });
          }
    
          const content = [];
          if (savedPath) {
            content.push({ type: 'text', text: `Saved VectorDrawable to ${savedPath}` });
          }
          content.push({ type: 'text', text: xml });
    
          return { content };
        }
      );
    }
  • Async handler for 'convert-svg-to-android-drawable' — loads SVG (inline or file), constructs options, checks cache, calls svg2vectordrawable for conversion, handles caching, optionally writes to outputPath, logs timing, and returns XML content.
    async (params, extra) => {
      const svgCode = await loadSvg(params);
      const options = {
        floatPrecision: params.floatPrecision,
        fillBlack: params.fillBlack,
        xmlTag: params.xmlTag,
        tint: params.tint
      };
    
      const cacheKey = makeCacheKey(svgCode, options);
      const startTime = process.hrtime.bigint();
    
      let xml = null;
      if (params.cache) {
        xml = getCached(cacheKey);
      }
    
      if (!xml) {
        xml = await svg2vectordrawable(svgCode, options);
        if (!xml || typeof xml !== 'string') {
          throw new Error('Conversion did not produce XML');
        }
        setCache(cacheKey, xml);
      }
    
      const savedPath = await maybeWriteOutput(params.outputPath, xml);
      const elapsedMs = Number(process.hrtime.bigint() - startTime) / 1_000_000;
    
      if (extra && typeof extra.sessionId === 'string') {
        server
          .sendLoggingMessage(
            {
              level: 'info',
              data:
                `Converted SVG in ${elapsedMs.toFixed(2)}ms` +
                (savedPath ? ` (saved to ${savedPath})` : '')
            },
            extra.sessionId
          )
          .catch(() => {
            /* best-effort logging */
          });
      }
    
      const content = [];
      if (savedPath) {
        content.push({ type: 'text', text: `Saved VectorDrawable to ${savedPath}` });
      }
      content.push({ type: 'text', text: xml });
    
      return { content };
    }
  • Input schema (convertInputSchema) using Zod v4 — defines svg/svgPath, outputPath, floatPrecision (default 2), fillBlack (default false), xmlTag (default false), tint, and cache (default true) with a refinement requiring svg or svgPath.
    const convertInputSchema = z
      .object({
        svg: z.string().min(1).describe('Inline SVG markup to convert').optional(),
        svgPath: z.string().min(1).describe('Path to an SVG file to read').optional(),
        outputPath: z
          .string()
          .min(1)
          .describe('Optional output path for generated VectorDrawable XML')
          .optional(),
        floatPrecision: z
          .number()
          .int()
          .min(0)
          .max(6)
          .default(2)
          .describe('Decimal precision when serializing coordinates'),
        fillBlack: z.boolean().default(false).describe('Force fill color black when missing'),
        xmlTag: z.boolean().default(false).describe('Include XML declaration'),
        tint: z.string().min(1).optional().describe('Android tint color (e.g. #FF000000)'),
        cache: z
          .boolean()
          .default(true)
          .describe('Reuse cached result for identical inputs within this process')
      })
      .refine(data => data.svg || data.svgPath, { message: 'Provide either svg or svgPath' });
  • Main entry point for the svg2vectordrawable vendor module — first optimizes SVG via SVGO with configurable floatPrecision, then delegates to svg-to-vectordrawable for the actual SVG-to-VectorDrawable conversion.
    const { optimize } = require('svgo');
    const svg2vectordrawable = require('./svg-to-vectordrawable');
    const svgoConfig = require('./svgo-config');
    module.exports = function(svgCode, options) {
        let floatPrecision = options ? options.floatPrecision : 2;
        const result = optimize(svgCode, svgoConfig(floatPrecision));
        svgCode = result.data;
        return svg2vectordrawable(svgCode, options)
    };
  • Core conversion function — parses SVG, instantiates JS2XML converter, runs convert() to transform SVG AST into Android VectorDrawable XML, optionally prepends XML declaration.
    module.exports = function(svgCode, options) {
        let floatPrecision = 2;
        let strict = false;
        let fillBlack = false;
        let xmlTag = false;
        let tint;
        if (options) {
            if (options.floatPrecision) {
                floatPrecision = options.floatPrecision;
            }
            if (options.strict) {
                strict = options.strict;
            }
            if (options.fillBlack) {
                fillBlack = options.fillBlack;
            }
            if (options.xmlTag) {
                xmlTag = options.xmlTag;
            }
            if (options.tint) {
                tint = options.tint;
            }
        }
        return new Promise((resolve, reject) => {
            let data = parseSvg(svgCode);
            if (data.error) {
                reject(data.error);
            }
            else {
                let xml = new JS2XML().convert(data, floatPrecision, strict, fillBlack, tint);
                if (xmlTag) {
                    xml = '<?xml version="1.0" encoding="utf-8"?>\n' + xml;
                }
                resolve(xml);
            }
        });
    };
Behavior3/5

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

No annotations provided; the description mentions conversion and optional disk write, but does not detail caching, precision, tint, or error handling. Schema covers parameters but tool behavior beyond that is not disclosed.

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?

Single sentence of 16 words, efficient and front-loaded with the action. No unnecessary words.

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

Completeness2/5

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

With 8 parameters, no output schema, and no annotations, the description is too minimal. It does not clarify what the tool returns (e.g., XML string) when no output path is given, nor error conditions.

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 baseline is 3. The description adds no additional meaning beyond the schema parameter descriptions.

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 tool converts SVG markup or files into Android VectorDrawable XML, with an optional disk write. The verb and resource are specific, and no sibling tools overlap.

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

Usage Guidelines3/5

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

No explicit guidance on when to use this tool vs alternatives, but sibling tools are unrelated, so differentiation is not critical. The description could mention caching or precision settings but does not.

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

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/Nam0101/android-mcp-toolkit'

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