All skills
mapbox avatar

/mapbox-mcp-runtime-patterns

@7cac917 official
by mapboxmapbox/mapbox-agent-skills80 stars
17

Integration patterns for Mapbox MCP Server in AI applications and agent frameworks. Covers runtime integration with pydantic-ai, mastra, LangChain, and custom agents. Use when building AI-powered applications that need geospatial capabilities.

Use this Skill: https://skilld.dev/gh/mapbox/mapbox-agent-skills/mapbox-mcp-runtime-patterns

This session only. Nothing lands on disk.

referencescustom-agent.md

≈1.9k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Custom Agent Integration

Use case: Building domain-specific AI applications (Zillow-style, TripAdvisor-style)

interface MCPTool {
  name: string;
  description: string;
  inputSchema: any;
}

class CustomMapboxAgent {
  private url = 'https://mcp.mapbox.com/mcp';
  private headers: Record<string, string>;
  private tools: Map<string, MCPTool> = new Map();

  constructor(token?: string) {
    const mapboxToken = token || process.env.MAPBOX_ACCESS_TOKEN;
    this.headers = {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${mapboxToken}`
    };
  }

  async initialize() {
    // Discover available tools from MCP server
    await this.discoverTools();
  }

  private async discoverTools() {
    const request = {
      jsonrpc: '2.0',
      id: 1,
      method: 'tools/list'
    };

    const response = await this.sendMCPRequest(request);
    response.result.tools.forEach((tool: MCPTool) => {
      this.tools.set(tool.name, tool);
    });
  }

  async callTool(toolName: string, params: any): Promise<any> {
    const request = {
      jsonrpc: '2.0',
      id: Date.now(),
      method: 'tools/call',
      params: { name: toolName, arguments: params }
    };

    const response = await this.sendMCPRequest(request);
    return response.result.content[0].text;
  }

  private async sendMCPRequest(request: any): Promise<any> {
    const response = await fetch(this.url, {
      method: 'POST',
      headers: this.headers,
      body: JSON.stringify(request)
    });

    const data = await response.json();

    if (data.error) {
      throw new Error(data.error.message);
    }

    return data;
  }

  // Domain-specific methods
  async findPropertiesWithCommute(
    homeLocation: [number, number],
    workLocation: [number, number],
    maxCommuteMinutes: number
  ) {
    // Get isochrone from work location
    const isochrone = await this.callTool('isochrone_tool', {
      coordinates: { longitude: workLocation[0], latitude: workLocation[1] },
      contours_minutes: [maxCommuteMinutes],
      profile: 'mapbox/driving-traffic'
    });

    // Check if home is within isochrone
    const isInRange = await this.callTool('point_in_polygon_tool', {
      point: { longitude: homeLocation[0], latitude: homeLocation[1] },
      polygon: JSON.parse(isochrone).features[0].geometry
    });

    return JSON.parse(isInRange);
  }

  async findRestaurantsNearby(location: [number, number], radiusMiles: number) {
    // Search restaurants
    const results = await this.callTool('category_search_tool', {
      category: 'restaurant',
      proximity: { longitude: location[0], latitude: location[1] }
    });

    // Filter by distance
    const restaurants = JSON.parse(results);
    const filtered = [];

    for (const restaurant of restaurants) {
      const distance = await this.callTool('distance_tool', {
        from: { longitude: location[0], latitude: location[1] },
        to: { longitude: restaurant.coordinates[0], latitude: restaurant.coordinates[1] },
        units: 'miles'
      });

      if (parseFloat(distance) <= radiusMiles) {
        filtered.push({
          ...restaurant,
          distance: parseFloat(distance)
        });
      }
    }

    return filtered.sort((a, b) => a.distance - b.distance);
  }
}

// Usage in Zillow-style app
const agent = new CustomMapboxAgent();
await agent.initialize();

const properties = await agent.findPropertiesWithCommute(
  [-122.4194, 37.7749], // Home in SF
  [-122.4, 37.79], // Work downtown
  30 // Max 30min commute
);

// Usage in TripAdvisor-style app
const restaurants = await agent.findRestaurantsNearby(
  [-73.9857, 40.7484], // Times Square
  0.5 // Within 0.5 miles
);

Benefits:

  • Full control over agent behavior
  • Domain-specific abstractions
  • Custom error handling

Architecture Patterns

Pattern: MCP as Service Layer

┌─────────────────────────────────────┐
│         Your Application            │
│  (Next.js, Express, FastAPI, etc.)  │
└────────────────┬────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────┐
│        AI Agent Layer               │
│   (pydantic-ai, mastra, custom)     │
└────────────────┬────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────┐
│     Mapbox MCP Server               │
│  (Geospatial tools abstraction)     │
└────────────────┬────────────────────┘
                 │
          ┌──────┴──────┐
          ▼             ▼
    ┌─────────┐   ┌──────────┐
    │ Turf.js │   │ Mapbox   │
    │ (Local) │   │   APIs   │
    └─────────┘   └──────────┘

Benefits:

  • Clean separation of concerns
  • Easy to swap MCP server versions
  • Centralized geospatial logic

Pattern: Hybrid Approach

You can use MCP for AI agent features while using direct Mapbox APIs for other parts of your app.

class GeospatialService {
  constructor(
    private mcpServer: MapboxMCPServer, // For AI features
    private mapboxSdk: MapboxSDK // For direct app features
  ) {}

  // AI Agent Feature: Natural language search
  async aiSearchNearby(userQuery: string): Promise<string> {
    // Let AI agent use MCP tools to interpret query and find places
    // Returns natural language response
    return await this.agent.execute(userQuery, [
      this.mcpServer.tools.category_search_tool,
      this.mcpServer.tools.directions_tool
    ]);
  }

  // Direct App Feature: Display route on map
  async getRouteGeometry(origin: Point, dest: Point): Promise<LineString> {
    // Direct API call for map rendering - returns GeoJSON
    const result = await this.mapboxSdk.directions.getDirections({
      waypoints: [origin, dest],
      geometries: 'geojson'
    });
    return result.routes[0].geometry;
  }

  // Offline Feature: Distance calculations (always use MCP/Turf.js)
  async calculateDistance(from: Point, to: Point): Promise<number> {
    // No API cost, instant
    return await this.mcpServer.callTool('distance_tool', {
      from,
      to,
      units: 'miles'
    });
  }
}

Architecture Decision Guide:

Use Case Use This Why
AI agent natural language features MCP Server Simplified tool interface, AI-friendly responses
Map rendering, direct UI controls Mapbox SDK More control, better performance
Distance/area calculations MCP Server (offline tools) Free, instant, no API calls
Custom map styling Mapbox SDK Fine-grained style control
Conversational geospatial queries MCP Server AI agent can chain tools

Source: SKILL.md on GitHub

1 warning17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill provides legitimate integration patterns and code examples for using Mapbox geospatial tools with various AI agent frameworks. It uses standard developer practices for package management, environment configuration, and API interaction with official vendor services.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer6mo

    2/12 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 7cac917. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 9 hours ago.

Activeupdated 6 months ago
  • MCP
  • TypeScript
  • mapbox
  • geospatial
  • routing
  • geocoding
  • pydantic-ai
  • langchain
  • mastra
  • agents

README badge

README badge for mapbox/mapbox-agent-skills/mapbox-mcp-runtime-patterns

Demonstrates runtime integration patterns for the Mapbox MCP Server across pydantic-ai, mastra, LangChain, and custom agents, covering offline tools (Turf.js), API-backed geospatial features (routing, geocoding, isochrones), and production considerations. Use this when building AI applications that need to query maps, calculate distances, search POIs, or optimize routes without manual API integration.

Generated from the current SKILL.md.

What's the difference between offline tools like distance_tool and API tools like directions_tool?
Offline tools (distance, bearing, point-in-polygon) use Turf.js, return instant results, and have no API cost. API tools (directions, geocoding, isochrones) call Mapbox APIs, return real-time data like traffic-aware routing, and count against your token usage.
Can I use the hosted Mapbox MCP server or do I need to self-host?
The hosted server at https://mcp.mapbox.com/mcp is recommended for production — no server management, always up-to-date, and lower latency. Self-hosting via npm is available for custom deployments or development.
Which frameworks does this skill cover?
Integration patterns for Pydantic AI, Mastra, LangChain, CrewAI, Smolagents, and custom agent architectures. Real-estate, food-delivery, and travel-planning use cases are included.
When should I use category_search_tool vs search_and_geocode_tool?
Use category_search_tool to browse by type (e.g. 'find coffee shops nearby'). Use search_and_geocode_tool for specific places or street addresses (e.g. '123 Main Street').
Does this skill include production guidance like caching, rate limiting, and error handling?
Yes. The skill references a production-patterns file covering caching, batch operations, tool descriptions, error handling, security, rate limiting, and testing.

Generated from the current SKILL.md. These answers refresh after source changes.