Building Geospatial AI Agents with Mapbox MCP and CrewAI
Overview

Geospatial context remains one of the most challenging data types for Large Language Models to handle accurately. Standard LLMs often hallucinate coordinates or fail to grasp the nuances of routing and travel times. This guide demonstrates how to bridge that gap using the
Prerequisites
To follow this tutorial, you should have a solid grasp of Python and basic web development concepts. Specifically, you'll need:
- A Mapboxaccess token for API calls.
- An OpenAIAPI key (though the framework supports other providers).
- Basic familiarity with Flask for creating the web interface.
- VS Code or a similar IDE for project management.
Key Libraries & Tools
- Mapbox MCP: A server that provides structured tools for LLMs to access Mapbox APIs (Search, Routing, Isochrones).
- CrewAI: A framework for orchestrating a "crew" of autonomous AI agents that work collaboratively.
- Mapbox GL JS: A JavaScript library for rendering interactive, customizable maps in the browser.
- Flask: A lightweight Python web framework used to serve the chat interface and the map.
- Pydantic: Used for defining structured data schemas to ensure the agent's output is predictable.
Code Walkthrough
Building a sophisticated agent requires an iterative approach. We start with a single helpful assistant and evolve it into a multi-agent system that controls a live map.
1. Project Initialization and Environment
Every project starts with a clean environment. You need a .env file to store your secrets. This keeps your tokens out of the source code and allows the
# .env example
MAPBOX_ACCESS_TOKEN=your_token_here
OPENAI_API_KEY=your_key_here
2. Defining the Crew and Agents
We use helpful_agent tasked with answering general location queries.
# agents.yaml
helpful_agent:
role: "Helpful Assistant"
goal: "Assist the user with location-based queries using provided tools."
backstory: "You are an expert in geography and navigation with access to real-time data."
In the crew.py file, we instantiate this agent and attach the poi_search or get_directions.
from crewai import Agent, Crew, Task, Process
# Instantiate the agent with MCP tools
helpful_agent = Agent(
config=self.agents_config['helpful_agent'],
tools=get_mcp_tools(), # Discovers tools from Mapbox MCP
verbose=True
)
3. Adding Structured Output for Map Visualization
To move beyond text, we need a second agent: the geo_json_enrichment_agent. This agent's job is to take the text findings from the first agent and convert them into a valid GeoJSON object that
# Define the structured output schema
class MapOutput(BaseModel):
text: str
geojson: Optional[dict] = None
map_commands: Optional[list] = None
# Update the task to require this schema
geojson_task = Task(
description="Convert the location findings into a GeoJSON format.",
expected_output="A structured JSON object with text and GeoJSON.",
output_json=MapOutput,
agent=geojson_agent
)
4. Choreographing the Map Camera
In the final iteration, we add a camera_choreographer_agent. This agent produces a sequence of commands—like flyTo, setFog, or setPaintProperty—that the frontend interprets to create a cinematic tour. This makes the map feel alive rather than static.
// Frontend interpretation of agent commands
function executeMapCommand(command) {
switch(command.type) {
case 'flyTo':
map.flyTo({ center: command.coords, zoom: 14 });
break;
case 'setSnow':
map.setConfigProperty('basemap', 'snow', command.intensity);
break;
}
}
Syntax Notes
- YAML for Agent Personas: Using YAML for agent definitions is a best practice in CrewAI. It allows non-developers to tweak the agent's "personality" without touching Python code.
- Pydantic Schemas: Notice the use of
BaseModel. This is critical when working with LLMs. It forces the model to return a valid JSON structure, preventing the frontend from crashing due to malformed text responses. - Template Variables: In CrewAI, tasks use curly braces
{prompt}to inject user input. This templating system allows the same task logic to be reused across different user queries.
Practical Examples
- Real Estate Discovery: An agent could search for schools, grocery stores, and parks within a 15-minute drive of a specific address, then highlight the overlapping "ideal" zones on the map using an isochrone tool.
- Logistics Dashboards: A shipping agent can calculate ETAs between multiple warehouses and visualize the current traffic-influenced routes, allowing operators to see the actual path suggested by the MapboxDirections API.
- Tourism Guides: A "City Tour" agent can take a user's interest in "Art Deco architecture" and choreograph a flying tour over New York City, stopping at specific landmarks while adjusting the map's lighting to sunset for better visuals.
Tips & Gotchas
- Token Limits with Geometry: Do not pass massive GeoJSON objects between agents. A detailed route can have thousands of coordinates, which will exhaust your token window and increase costs. Always ask the agent to "simplify" the geometry to 10–20 key points for internal reasoning.
- Latency Management: Multi-agent systems are sequential by nature, which is slow. To speed things up, use the
hierarchicalprocess inCrewAIor set certain tasks to runasync. This allows the camera agent to start planning while the GeoJSON agent is still formatting data. - Tool Overload: Giving an agent too many tools can lead to confusion. If the agent struggles to pick the right API, split the tools among specialized agents (e.g., one agent for search, another for routing).