Skip to main content
Glama
tomtom-international

TomTom MCP Server

Official

tomtom-static-map

Generate static maps with customizable parameters like center coordinates, zoom level, size, style, and layer type using the TomTom MCP Server. Supports multiple formats and geopolitical views for precise map rendering.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
bboxNoBounding box in format [west, south, east, north]. Alternative to center+zoom. Example: [-122.42, 37.77, -122.40, 37.79] for part of San Francisco.
centerYesMap center coordinates. Use results from geocoding or search operations for best positioning.
formatNoImage format: 'png' (better quality, supports transparency), 'jpg' (smaller file size).
heightNoMap height in pixels (50-2048). Examples: 300-500 (preview), 800-1200 (detailed). Default: 512.
languageNoLanguage for map labels (IETF language tag). Examples: 'en-US', 'es-ES', 'fr-FR'.
layerNoMap layer type: 'basic' (streets), 'labels' (text only, transparent background), 'hybrid' (satellite with labels).
styleNoMap style: 'main' (default daytime), 'night' (dark theme).
viewNoGeopolitical view for border disputes and territories. 'Unified' is the international standard view.
widthNoMap width in pixels (50-2048). Examples: 300-500 (preview), 800-1200 (detailed). Default: 512.
zoomNoZoom level (0-22). Examples: 3 (continent), 6 (country), 10 (city), 15 (neighborhood), 18 (street). Default: 15.

Implementation Reference

  • Factory function creating the MCP tool handler for tomtom-static-map. Processes input parameters, fetches the static map image via service, and returns it as base64 image content or error.
    export function createStaticMapHandler() {
      return async (params: any) => {
        logger.info(`πŸ—ΊοΈ Generating static map: (${params.center.lat}, ${params.center.lon})`);
        try {
          const { base64, contentType } = await getStaticMapImage(params);
          logger.info(`βœ… Static map generated successfully`);
          return {
            content: [{ type: "image" as const, data: base64, mimeType: contentType }],
          };
        } catch (error: any) {
          logger.error(`❌ Static map generation failed: ${error.message}`);
          return {
            content: [{ type: "text" as const, text: JSON.stringify({ error: error.message }) }],
            isError: true,
          };
        }
      };
    }
  • Zod schema definition for input validation of tomtom-static-map tool parameters including center, bbox, zoom, dimensions, styles, layers, etc.
    export const tomtomMapSchema = {
      center: coordinateSchema.describe(
        "Map center coordinates. Use results from geocoding or search operations for best positioning."
      ),
    
      // Fix: Use z.array() instead of z.tuple()
      bbox: z
        .array(z.number())
        .length(4)
        .optional()
        .describe(
          "Bounding box in format [west, south, east, north]. Alternative to center+zoom. Example: [-122.42, 37.77, -122.40, 37.79] for part of San Francisco."
        ),
    
      zoom: z
        .number()
        .min(0)
        .max(22)
        .optional()
        .describe(
          "Zoom level (0-22). Examples: 3 (continent), 6 (country), 10 (city), 15 (neighborhood), 18 (street). Default: 15."
        ),
    
      width: z
        .number()
        .min(50)
        .max(2048)
        .optional()
        .describe(
          "Map width in pixels (50-2048). Examples: 300-500 (preview), 800-1200 (detailed). Default: 512."
        ),
    
      height: z
        .number()
        .min(50)
        .max(2048)
        .optional()
        .describe(
          "Map height in pixels (50-2048). Examples: 300-500 (preview), 800-1200 (detailed). Default: 512."
        ),
    
      style: z
        .enum(["main", "night"])
        .optional()
        .describe("Map style: 'main' (default daytime), 'night' (dark theme)."),
    
      layer: z
        .enum(["basic", "labels", "hybrid"])
        .optional()
        .describe(
          "Map layer type: 'basic' (streets), 'labels' (text only, transparent background), 'hybrid' (satellite with labels)."
        ),
    
      format: z
        .enum(["png", "jpg"])
        .optional()
        .describe(
          "Image format: 'png' (better quality, supports transparency), 'jpg' (smaller file size)."
        ),
    
      view: z
        .enum(["Unified", "IL", "IN", "MA", "PK", "AR", "Arabic", "RU", "TR", "CN", "US"])
        .optional()
        .describe(
          "Geopolitical view for border disputes and territories. 'Unified' is the international standard view."
        ),
    
      language: z
        .string()
        .optional()
        .describe("Language for map labels (IETF language tag). Examples: 'en-US', 'es-ES', 'fr-FR'."),
    };
  • Registration of the tomtom-static-map tool with MCP server, linking schema and handler.
    server.registerTool(
      "tomtom-static-map",
      {
        title: "TomTom Static Map",
        description: "Generate custom map images from TomTom Maps with specified center coordinates, zoom levels, and style options",
        inputSchema: schemas.tomtomMapSchema,
      },
      createStaticMapHandler()
    );
  • Core service function that constructs the TomTom Static Maps API URL, fetches the image, adds copyright overlay if canvas available, and returns base64-encoded image data used by the handler.
    export async function getStaticMapImage(
      options: MapOptions
    ): Promise<{ base64: string; contentType: string }> {
      try {
        // Get the URL first
        const mapUrl = getStaticMapUrl(options);
    
        // Log the URL before making the request
        logger.info(`Making static map request to: ${tomtomClient.defaults.baseURL}${mapUrl}`);
    
        // Use tomtomClient to download the image (it automatically includes proper headers)
        const response = await tomtomClient.get(mapUrl, {
          responseType: "arraybuffer",
        });
    
        // Log the actual URL that was requested (including any modifications made by axios)
        if (response.config && response.config.url) {
          logger.info(`Full request URL was: ${response.config.url}`);
        }
    
        if (!response.status || response.status >= 400) {
          throw new Error(`Failed to fetch map image: HTTP ${response.status}`);
        }
    
        // Get the content type from the response headers
        const contentType = response.headers?.["content-type"] || "image/png";
    
        // The image data is already in the response
        const imageBuffer = response.data;
    
        // Add copyright overlay to the static map image
        let finalImageBuffer = imageBuffer;
        
        // Try to load Canvas dynamically
        const canvasAvailable = await loadCanvasIfAvailable();
        
        if (canvasAvailable) {
          try {
            // Fetch Genesis copyright text (static maps are Genesis only)
            const copyrightText = await fetchCopyrightCaption(false);
            logger.info(`πŸ“„ Static map copyright text: ${copyrightText}`);
            
            // Get image dimensions from options
            const width = options.width || DEFAULT_MAP_OPTIONS.width;
            const height = options.height || DEFAULT_MAP_OPTIONS.height;
            
            // Create canvas and load the original image
            const canvas = createCanvas(width, height);
            const ctx = canvas.getContext('2d');
            
            // Load and draw the original image
            const buffer = Buffer.from(imageBuffer);
            const { loadImage } = await import('canvas');
            const img = await loadImage(buffer);
            ctx.drawImage(img, 0, 0, width, height);
            
            // Add copyright overlay using shared utility
            addCopyrightOverlay(ctx, copyrightText, width, height);
            
            // Convert canvas back to buffer
            finalImageBuffer = canvas.toBuffer('image/png');
            
            logger.debug(`Added copyright overlay to static map image`);
            
          } catch (overlayError: any) {
            logger.error(`Failed to add copyright overlay to static map: ${overlayError.message}. Using original image.`);
            // Use original image if overlay fails
            finalImageBuffer = imageBuffer;
          }
        } else {
          logger.debug('Canvas not available, skipping copyright overlay for static map');
        }
    
        // Convert the buffer to base64
        const base64 = Buffer.from(finalImageBuffer).toString("base64");
    
        logger.debug(`Downloaded and processed static map image (${(finalImageBuffer.byteLength / 1024).toFixed(2)} KB)`);
    
        return { base64, contentType };
      } catch (error) {
        logger.error(`Failed to download static map: ${error}`);
        throw error;
      }
    }
Behavior1/5

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

Tool has no description.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness1/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Tool has no description.

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

Completeness1/5

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

Tool has no description.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Tool has no description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose1/5

Does the description clearly state what the tool does and how it differs from similar tools?

Tool has no description.

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

Usage Guidelines1/5

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

Tool has no description.

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

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/tomtom-international/tomtom-mcp'

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