android-mock-location-mcp
v0.3.0
Published
MCP server for Android mock location testing
Downloads
206
Maintainers
Readme
MCP Server — android-mock-location-mcp
MCP server that exposes 11 tools for controlling Android emulator GPS location. Sets mock locations via adb emu geo fix and supports geocoding and street-level routing through configurable providers.
See the root README for project overview and quick start.
Installation
The server is launched automatically by your MCP client — you don't run it directly. The installation method determines how the client finds and starts it.
npx (no install needed): Use npx -y android-mock-location-mcp as the command in your MCP client config. The client will download and run it automatically.
Global install: Pre-install the package so the client can launch it without download delay:
npm install -g android-mock-location-mcpBuild from source:
cd server
npm install
npm run buildUpdating:
npxcaches packages after the first download. To force an update, temporarily change the command in your MCP client config tonpx -y android-mock-location-mcp@latestand restart the client.
See the Configuration section below for how to set up your MCP client to launch the server.
Configuration
Environment Variables
| Variable | Description | Required |
|----------|-------------|----------|
| PROVIDER | Provider for geocoding + routing: osm (default), google, mapbox | No (defaults to osm) |
| GOOGLE_API_KEY | Google Places + Routes API key | When PROVIDER=google |
| MAPBOX_ACCESS_TOKEN | Mapbox Geocoding + Directions access token | When PROVIDER=mapbox |
Provider selection is resolved once at server startup. Changing PROVIDER or API keys requires restarting the MCP client (which restarts the server).
Set environment variables in your MCP client configuration:
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"android-mock-location-mcp": {
"command": "npx",
"args": ["-y", "android-mock-location-mcp"]
}
}
}No API key required. Uses free Nominatim geocoding and OSRM routing (car profile only).
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"android-mock-location-mcp": {
"command": "npx",
"args": ["-y", "android-mock-location-mcp"],
"env": {
"PROVIDER": "google",
"GOOGLE_API_KEY": "your-google-api-key"
}
}
}
}Prerequisites: Enable both the Places API (New) and Routes API in your Google Cloud project.
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"android-mock-location-mcp": {
"command": "npx",
"args": ["-y", "android-mock-location-mcp"],
"env": {
"PROVIDER": "mapbox",
"MAPBOX_ACCESS_TOKEN": "your-mapbox-access-token"
}
}
}
}After editing the config, restart Claude Desktop to apply the changes (this restarts the MCP server automatically).
claude mcp add android-mock-location-mcp -- npx -y android-mock-location-mcpNo API key required. Uses free Nominatim geocoding and OSRM routing (car profile only).
GOOGLE_API_KEY=your-google-api-key
claude mcp add android-mock-location-mcp \
-e PROVIDER=google \
-e GOOGLE_API_KEY=$GOOGLE_API_KEY \
-- npx -y android-mock-location-mcpPrerequisites: Enable both the Places API (New) and Routes API in your Google Cloud project.
MAPBOX_ACCESS_TOKEN=your-mapbox-access-token
claude mcp add android-mock-location-mcp \
-e PROVIDER=mapbox \
-e MAPBOX_ACCESS_TOKEN=$MAPBOX_ACCESS_TOKEN \
-- npx -y android-mock-location-mcpTo switch from one provider to another (e.g. osm → google), remove and re-add the server with new env vars, then restart Claude Code:
# 1. Remove existing server
claude mcp remove android-mock-location-mcp
# 2. Re-add with new provider
GOOGLE_API_KEY=your-google-api-key
claude mcp add android-mock-location-mcp \
-e PROVIDER=google \
-e GOOGLE_API_KEY=$GOOGLE_API_KEY \
-- npx -y android-mock-location-mcp
# 3. Restart Claude Code (this restarts the MCP server automatically)Provider selection is resolved once at server startup, so restarting is required for changes to take effect.
Providers
Google and Mapbox providers produce better results than the default OSM provider — more accurate geocoding, full routing profile support (car/foot/bike), and higher rate limits. Both offer free tiers.
| PROVIDER | Geocoding Service | Routing Service | Profiles Supported | API Key | Cost |
| ------------- | --------------------------- | --------------- | ------------------ | ---------------------- | -------------------- |
| osm (default) | Nominatim (OpenStreetMap) | OSRM | car only* | None | Free (rate-limited) |
| google | Google Places API | Google Routes API | car, foot, bike | GOOGLE_API_KEY | Paid (free tier) |
| mapbox | Mapbox Geocoding | Mapbox Directions | car, foot, bike | MAPBOX_ACCESS_TOKEN | Paid (free tier) |
*OSRM limitation: The public OSRM demo server (router.project-osrm.org) only supports the car profile. Requesting foot or bike silently returns a driving route. For walking/cycling routing, use google or mapbox.
Nominatim rate limit: The OSM Nominatim API is rate-limited to 1 request per second. When using the osm provider, the server hints the AI to resolve place names to coordinates itself and pass lat/lng directly.
Tool Reference
geo_list_devices
List connected Android emulators via ADB.
No parameters.
geo_connect_device
Connect to an Android emulator for mock location control. Only emulators are supported (e.g. emulator-5554). Locations are set via the emulator's geo fix command.
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| deviceId | string | yes | Emulator serial from geo_list_devices, e.g. emulator-5554 |
geo_set_location
Set emulator GPS to coordinates or any place name/address. Geocodes place names via the configured provider.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| lat | number | no | — | Latitude (-90 to 90) |
| lng | number | no | — | Longitude (-180 to 180) |
| place | string | no | — | Place name or address, e.g. 'Times Square', 'Tokyo Station' |
Provide either place or both lat/lng.
geo_simulate_route
Simulate movement along a route between two points at a given speed. Routes follow real streets via the configured routing provider. Falls back to straight-line if the provider fails.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| from | string | no | — | Starting place name or address |
| to | string | no | — | Destination place name or address |
| fromLat | number | no | — | Starting latitude |
| fromLng | number | no | — | Starting longitude |
| toLat | number | no | — | Destination latitude |
| toLng | number | no | — | Destination longitude |
| speedKmh | number | no | 60 | Speed in km/h |
| trafficMultiplier | number | no | 1.0 | Traffic slowdown factor (e.g. 1.5 = 50% slower) |
| profile | enum | no | car | Routing profile: car, foot, or bike |
Provide either from/to (place names) or fromLat/fromLng/toLat/toLng (coordinates) for each endpoint.
Starting location auto-resolve: If no from/fromLat/fromLng is provided, the tool automatically tries (in order): the last mock location, the emulator's current GPS position via geo_get_location, or returns an error asking the user for their starting location.
Routing Profiles
| Profile | Use for | Routes on |
|---------|---------|-----------|
| car (default) | Driving simulation | Roads, highways |
| foot | Walking simulation | Sidewalks, pedestrian paths |
| bike | Cycling simulation | Bike lanes, roads |
The AI should select profile based on user intent (e.g. "walk to" → foot, "drive to" → car).
geo_simulate_multi_stop
Simulate movement along a multi-stop route (e.g. delivery route, rideshare pickups). Routes between consecutive waypoints follow real streets. Each waypoint can have a dwell time (time spent stationary at the stop before continuing). Runs as one continuous 1 Hz simulation with no gaps between legs.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| waypoints | array | yes | — | Ordered list of waypoints (min 2). Each: { lat?, lng?, place?, dwellSeconds? } |
| speedKmh | number | no | 60 | Travel speed between waypoints (km/h) |
| trafficMultiplier | number | no | 1.0 | Traffic slowdown factor (e.g. 1.5 = 50% slower) |
| profile | enum | no | car | Routing profile: car, foot, or bike |
Each waypoint object:
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| lat | number | no | — | Waypoint latitude |
| lng | number | no | — | Waypoint longitude |
| place | string | no | — | Waypoint place name or address |
| dwellSeconds | number | no | 0 | Time to stay at this waypoint before continuing (seconds) |
Provide either place or both lat/lng per waypoint. If the first waypoint has no coordinates or place, the tool auto-resolves from the current mock location or emulator GPS position.
geo_simulate_jitter
Simulate GPS noise/jitter at a location for testing accuracy handling.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| lat | number | no | — | Center latitude |
| lng | number | no | — | Center longitude |
| place | string | no | — | Center place name or address |
| radiusMeters | number | no | 10 | Jitter radius in meters |
| pattern | enum | no | random | Jitter pattern: random, drift, urban_canyon |
| durationSeconds | number | no | 30 | Duration in seconds |
Provide either place or both lat/lng.
Jitter Patterns
| Pattern | Behavior |
|---------|----------|
| random | Uniform random distribution within radius |
| drift | Gradual movement in one direction |
| urban_canyon | Alternating accurate (3m) and inaccurate (50-80m) fixes, simulating tall buildings |
geo_test_geofence
Test geofence enter/exit/bounce behavior at a location.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| lat | number | no | — | Geofence center latitude |
| lng | number | no | — | Geofence center longitude |
| place | string | no | — | Geofence center place name or address |
| radiusMeters | number | no | 100 | Geofence radius in meters |
| action | enum | no | enter | Geofence action: enter, exit, bounce |
| bounceCount | number | no | 3 | Number of boundary crossings (for bounce action) |
Provide either place or both lat/lng.
Geofence Actions
| Action | Behavior |
|--------|----------|
| enter | Move from outside to inside the geofence |
| exit | Move from inside to outside the geofence |
| bounce | Cross the boundary bounceCount times |
geo_replay_gpx_kml
Replay a GPX or KML track file on the emulator. Auto-detects format from the XML content.
| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| fileContent | string | no* | — | Raw GPX or KML file content (XML string) |
| filePath | string | no* | — | Absolute path to a GPX or KML file on the host |
| speedMultiplier | number | no | 1.0 | Playback speed multiplier for time-based replay (e.g. 2.0 = 2x faster) |
| speedKmh | number | no | 60 | Travel speed for distance-based replay (km/h) |
*Provide either fileContent or filePath.
Replay Modes
| Mode | When used | Speed control |
|------|-----------|---------------|
| Time-based | GPX files with timestamps on ≥80% of trackpoints | speedMultiplier — preserves original speed profile |
| Distance-based | KML files, or GPX without timestamps | speedKmh — constant speed along the track |
GPX support: Extracts <trkpt> elements from <trk>/<trkseg> with optional <ele> (elevation) and <time> (timestamp).
KML support: Extracts <coordinates> from <LineString> elements. Coordinate format is lng,lat,ele tuples separated by whitespace.
geo_stop
Stop any active location simulation.
No parameters.
geo_get_status
Get current connection and simulation status.
No parameters.
geo_get_location
Get the emulator's current GPS location (last known position from the emulator's location providers). Reads the location via adb shell dumpsys location. Use this to determine where the emulator is before simulating a route.
No parameters.
Returns the emulator's latitude and longitude if a recent GPS fix is available, along with accuracy (horizontal accuracy in meters) when provided. If the emulator has no location fix, the tool returns an error message — in that case, ask the user for their current location.
How It Works
The server sets emulator GPS location using adb emu geo fix, which updates the emulator's stored GPS state. The command format is:
geo fix <longitude> <latitude> [<altitude> [<satellites> [<velocity>]]]Unlike geo nmea (which injects one-shot NMEA sentences), geo fix updates the emulator's internal state so the position persists across the emulator's 1 Hz GPS update loop.
The geo fix command is processed directly by the emulator's GPS simulation layer.
Source Structure
| File | Purpose |
|------|---------|
| src/index.ts | MCP server setup, all 11 tool definitions with Zod schemas |
| src/emulator.ts | Emulator connection management, location setting via geo fix |
| src/adb.ts | ADB command execution with timeouts, emulator validation |
| src/geocode.ts | Geocoding providers: Nominatim, Google, Mapbox |
| src/routing.ts | Routing providers: OSRM, Google Routes API, Mapbox Directions |
| src/gpx-kml.ts | GPX/KML file parsing for track replay |
| src/geo-math.ts | Haversine distance calculation |
| src/fetch-utils.ts | Shared fetchWithTimeout helper |
Development
npm install # Install dependencies
npm run build # Compile TypeScript
npm run dev # Watch mode (recompile on change)
npm start # Run the serverThe server communicates via stdio (MCP protocol). To test interactively, use the MCP Inspector.
Known Limitations
- Emulators only. The server uses
adb emu geo fixwhich only works with Android emulators. Physical devices are not supported. - Single emulator. The server connects to one emulator at a time. Calling
geo_connect_devicewith a different serial disconnects the previous one and stops any active simulation. - Single simulation. Only one simulation (route, jitter, or geofence) runs at a time. Starting a new one stops the previous.
See also: provider-specific limitations in the Providers table above.
Adding a New Provider
Both src/geocode.ts and src/routing.ts use the same pattern:
- Implement the
GeocodeProvidertype (ingeocode.ts) and/orRoutingProvidertype (inrouting.ts) - Add a case to
selectProvider()in the respective file - Validate required env vars in the
selectProvider()switch case - Document the new env var in this README and in
CLAUDE.md
