android-mock-location-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +210 -0
- package/dist/device.d.ts +10 -0
- package/dist/device.js +154 -0
- package/dist/device.js.map +1 -0
- package/dist/fetch-utils.d.ts +5 -0
- package/dist/fetch-utils.js +16 -0
- package/dist/fetch-utils.js.map +1 -0
- package/dist/geo-math.d.ts +4 -0
- package/dist/geo-math.js +20 -0
- package/dist/geo-math.js.map +1 -0
- package/dist/geocode.d.ts +7 -0
- package/dist/geocode.js +101 -0
- package/dist/geocode.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +428 -0
- package/dist/index.js.map +1 -0
- package/dist/routing.d.ts +32 -0
- package/dist/routing.js +263 -0
- package/dist/routing.js.map +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# MCP Server — android-mock-location-mcp
|
|
2
|
+
|
|
3
|
+
MCP server that exposes 8 tools for controlling Android device GPS location. Connects to an Android agent app over TCP (via ADB port forwarding) and supports geocoding and street-level routing through configurable providers.
|
|
4
|
+
|
|
5
|
+
See the [root README](../README.md) for project overview and quick start.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
**npx (no install):**
|
|
10
|
+
```bash
|
|
11
|
+
npx android-mock-location-mcp
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**Global install:**
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g android-mock-location-mcp
|
|
17
|
+
android-mock-location-mcp
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Build from source:**
|
|
21
|
+
```bash
|
|
22
|
+
cd server
|
|
23
|
+
npm install
|
|
24
|
+
npm run build
|
|
25
|
+
npm start
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Configuration
|
|
29
|
+
|
|
30
|
+
### Environment Variables
|
|
31
|
+
|
|
32
|
+
| Variable | Description | Required |
|
|
33
|
+
|----------|-------------|----------|
|
|
34
|
+
| `PROVIDER` | Provider for geocoding + routing: `osm` (default), `google`, `mapbox` | No (defaults to `osm`) |
|
|
35
|
+
| `GOOGLE_API_KEY` | Google Geocoding + Routes API key | When `PROVIDER=google` |
|
|
36
|
+
| `MAPBOX_ACCESS_TOKEN` | Mapbox Geocoding + Directions access token | When `PROVIDER=mapbox` |
|
|
37
|
+
|
|
38
|
+
Set environment variables in your MCP client configuration. See [root README](../README.md#provider-configuration) for client config examples.
|
|
39
|
+
|
|
40
|
+
### Providers
|
|
41
|
+
|
|
42
|
+
| `PROVIDER` | Geocoding Service | Routing Service | Profiles Supported | API Key | Cost |
|
|
43
|
+
|------------|-------------------|-----------------|-------------------|---------|------|
|
|
44
|
+
| `osm` (default) | Nominatim (OpenStreetMap) | OSRM | `car` only* | None | Free (rate-limited) |
|
|
45
|
+
| `google` | Google Geocoding API | Google Routes API | `car`, `foot`, `bike` | `GOOGLE_API_KEY` | Paid (free tier) |
|
|
46
|
+
| `mapbox` | Mapbox Geocoding | Mapbox Directions | `car`, `foot`, `bike` | `MAPBOX_ACCESS_TOKEN` | Paid (free tier) |
|
|
47
|
+
|
|
48
|
+
**\*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`.
|
|
49
|
+
|
|
50
|
+
**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.
|
|
51
|
+
|
|
52
|
+
## Tool Reference
|
|
53
|
+
|
|
54
|
+
### `geo_list_devices`
|
|
55
|
+
|
|
56
|
+
List connected Android devices via ADB.
|
|
57
|
+
|
|
58
|
+
No parameters.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### `geo_connect_device`
|
|
63
|
+
|
|
64
|
+
Connect to an Android device for mock location control. Sets up ADB port forwarding and opens a TCP socket.
|
|
65
|
+
|
|
66
|
+
| Parameter | Type | Required | Description |
|
|
67
|
+
|-----------|------|----------|-------------|
|
|
68
|
+
| `deviceId` | string | yes | Device serial from `geo_list_devices`, e.g. `emulator-5554` |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
### `geo_set_location`
|
|
73
|
+
|
|
74
|
+
Set device GPS to coordinates or any place name/address. Geocodes place names via the configured provider.
|
|
75
|
+
|
|
76
|
+
| Parameter | Type | Required | Default | Description |
|
|
77
|
+
|-----------|------|----------|---------|-------------|
|
|
78
|
+
| `lat` | number | no | — | Latitude (-90 to 90) |
|
|
79
|
+
| `lng` | number | no | — | Longitude (-180 to 180) |
|
|
80
|
+
| `place` | string | no | — | Place name or address, e.g. `'Times Square'`, `'Tokyo Station'` |
|
|
81
|
+
| `accuracy` | number | no | `3` | GPS accuracy in meters |
|
|
82
|
+
|
|
83
|
+
Provide either `place` or both `lat`/`lng`.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### `geo_simulate_route`
|
|
88
|
+
|
|
89
|
+
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.
|
|
90
|
+
|
|
91
|
+
| Parameter | Type | Required | Default | Description |
|
|
92
|
+
|-----------|------|----------|---------|-------------|
|
|
93
|
+
| `from` | string | no | — | Starting place name or address |
|
|
94
|
+
| `to` | string | no | — | Destination place name or address |
|
|
95
|
+
| `fromLat` | number | no | — | Starting latitude |
|
|
96
|
+
| `fromLng` | number | no | — | Starting longitude |
|
|
97
|
+
| `toLat` | number | no | — | Destination latitude |
|
|
98
|
+
| `toLng` | number | no | — | Destination longitude |
|
|
99
|
+
| `speedKmh` | number | no | `60` | Speed in km/h |
|
|
100
|
+
| `trafficMultiplier` | number | no | `1.0` | Traffic slowdown factor (e.g. `1.5` = 50% slower) |
|
|
101
|
+
| `profile` | enum | no | `car` | Routing profile: `car`, `foot`, or `bike` |
|
|
102
|
+
|
|
103
|
+
Provide either `from`/`to` (place names) or `fromLat`/`fromLng`/`toLat`/`toLng` (coordinates) for each endpoint.
|
|
104
|
+
|
|
105
|
+
#### Routing Profiles
|
|
106
|
+
|
|
107
|
+
| Profile | Use for | Routes on |
|
|
108
|
+
|---------|---------|-----------|
|
|
109
|
+
| `car` (default) | Driving simulation | Roads, highways |
|
|
110
|
+
| `foot` | Walking simulation | Sidewalks, pedestrian paths |
|
|
111
|
+
| `bike` | Cycling simulation | Bike lanes, roads |
|
|
112
|
+
|
|
113
|
+
The AI should select `profile` based on user intent (e.g. "walk to" → `foot`, "drive to" → `car`).
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
### `geo_simulate_jitter`
|
|
118
|
+
|
|
119
|
+
Simulate GPS noise/jitter at a location for testing accuracy handling.
|
|
120
|
+
|
|
121
|
+
| Parameter | Type | Required | Default | Description |
|
|
122
|
+
|-----------|------|----------|---------|-------------|
|
|
123
|
+
| `lat` | number | no | — | Center latitude |
|
|
124
|
+
| `lng` | number | no | — | Center longitude |
|
|
125
|
+
| `place` | string | no | — | Center place name or address |
|
|
126
|
+
| `radiusMeters` | number | no | `10` | Jitter radius in meters |
|
|
127
|
+
| `pattern` | enum | no | `random` | Jitter pattern: `random`, `drift`, `urban_canyon` |
|
|
128
|
+
| `durationSeconds` | number | no | `30` | Duration in seconds |
|
|
129
|
+
|
|
130
|
+
Provide either `place` or both `lat`/`lng`.
|
|
131
|
+
|
|
132
|
+
#### Jitter Patterns
|
|
133
|
+
|
|
134
|
+
| Pattern | Behavior |
|
|
135
|
+
|---------|----------|
|
|
136
|
+
| `random` | Uniform random distribution within radius |
|
|
137
|
+
| `drift` | Gradual movement in one direction |
|
|
138
|
+
| `urban_canyon` | Alternating accurate (3m) and inaccurate (50-80m) fixes, simulating tall buildings |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### `geo_test_geofence`
|
|
143
|
+
|
|
144
|
+
Test geofence enter/exit/bounce behavior at a location.
|
|
145
|
+
|
|
146
|
+
| Parameter | Type | Required | Default | Description |
|
|
147
|
+
|-----------|------|----------|---------|-------------|
|
|
148
|
+
| `lat` | number | no | — | Geofence center latitude |
|
|
149
|
+
| `lng` | number | no | — | Geofence center longitude |
|
|
150
|
+
| `place` | string | no | — | Geofence center place name or address |
|
|
151
|
+
| `radiusMeters` | number | no | `100` | Geofence radius in meters |
|
|
152
|
+
| `action` | enum | no | `enter` | Geofence action: `enter`, `exit`, `bounce` |
|
|
153
|
+
| `bounceCount` | number | no | `3` | Number of boundary crossings (for `bounce` action) |
|
|
154
|
+
|
|
155
|
+
Provide either `place` or both `lat`/`lng`.
|
|
156
|
+
|
|
157
|
+
#### Geofence Actions
|
|
158
|
+
|
|
159
|
+
| Action | Behavior |
|
|
160
|
+
|--------|----------|
|
|
161
|
+
| `enter` | Move from outside to inside the geofence |
|
|
162
|
+
| `exit` | Move from inside to outside the geofence |
|
|
163
|
+
| `bounce` | Cross the boundary `bounceCount` times |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
### `geo_stop`
|
|
168
|
+
|
|
169
|
+
Stop any active location simulation.
|
|
170
|
+
|
|
171
|
+
No parameters.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### `geo_get_status`
|
|
176
|
+
|
|
177
|
+
Get current connection and simulation status.
|
|
178
|
+
|
|
179
|
+
No parameters.
|
|
180
|
+
|
|
181
|
+
## Source Structure
|
|
182
|
+
|
|
183
|
+
| File | Purpose |
|
|
184
|
+
|------|---------|
|
|
185
|
+
| `src/index.ts` | MCP server setup, all 8 tool definitions with Zod schemas |
|
|
186
|
+
| `src/device.ts` | ADB commands (`execFileSync`), TCP socket to agent, request/response matching |
|
|
187
|
+
| `src/geocode.ts` | Geocoding providers: Nominatim, Google, Mapbox |
|
|
188
|
+
| `src/routing.ts` | Routing providers: OSRM, Google Routes API, Mapbox Directions |
|
|
189
|
+
| `src/geo-math.ts` | Haversine distance, forward bearing calculation |
|
|
190
|
+
| `src/fetch-utils.ts` | Shared `fetchWithTimeout` helper |
|
|
191
|
+
|
|
192
|
+
## Development
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
npm install # Install dependencies
|
|
196
|
+
npm run build # Compile TypeScript
|
|
197
|
+
npm run dev # Watch mode (recompile on change)
|
|
198
|
+
npm start # Run the server
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The server communicates via stdio (MCP protocol). To test interactively, use the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector).
|
|
202
|
+
|
|
203
|
+
## Adding a New Provider
|
|
204
|
+
|
|
205
|
+
Both `src/geocode.ts` and `src/routing.ts` use the same pattern:
|
|
206
|
+
|
|
207
|
+
1. Implement the `GeocodeProvider` type (in `geocode.ts`) and/or `RoutingProvider` type (in `routing.ts`)
|
|
208
|
+
2. Add a case to `selectProvider()` in the respective file
|
|
209
|
+
3. Validate required env vars in the `selectProvider()` switch case
|
|
210
|
+
4. Document the new env var in this README and in `CLAUDE.md`
|
package/dist/device.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Register a callback invoked when the device socket disconnects. */
|
|
2
|
+
export declare function onDisconnect(cb: () => void): void;
|
|
3
|
+
export declare function getConnectedDeviceId(): string | null;
|
|
4
|
+
export declare function isConnected(): boolean;
|
|
5
|
+
/** List connected ADB devices. Returns raw `adb devices -l` output. */
|
|
6
|
+
export declare function listDevices(): string;
|
|
7
|
+
/** Send a JSON command to the agent and await the response (5s timeout). */
|
|
8
|
+
export declare function sendCommand(command: Record<string, unknown>): Promise<unknown>;
|
|
9
|
+
/** Set up ADB port forwarding and open a TCP socket to the agent. */
|
|
10
|
+
export declare function connectToDevice(deviceId: string): void;
|
package/dist/device.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// ── ADB + socket communication with Android agent ───────────────────────────
|
|
2
|
+
import * as net from "node:net";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
// ── State ────────────────────────────────────────────────────────────────────
|
|
6
|
+
let socket = null;
|
|
7
|
+
let connectedDeviceId = null;
|
|
8
|
+
let socketBuffer = "";
|
|
9
|
+
let autoReconnectAttempted = false;
|
|
10
|
+
let reconnectTimer = null;
|
|
11
|
+
const pendingRequests = new Map();
|
|
12
|
+
let disconnectCallback = null;
|
|
13
|
+
// ── Public API ───────────────────────────────────────────────────────────────
|
|
14
|
+
/** Register a callback invoked when the device socket disconnects. */
|
|
15
|
+
export function onDisconnect(cb) {
|
|
16
|
+
disconnectCallback = cb;
|
|
17
|
+
}
|
|
18
|
+
export function getConnectedDeviceId() {
|
|
19
|
+
return connectedDeviceId;
|
|
20
|
+
}
|
|
21
|
+
export function isConnected() {
|
|
22
|
+
return socket !== null && !socket.destroyed;
|
|
23
|
+
}
|
|
24
|
+
/** List connected ADB devices. Returns raw `adb devices -l` output. */
|
|
25
|
+
export function listDevices() {
|
|
26
|
+
return execFileSync("adb", ["devices", "-l"], { encoding: "utf-8" });
|
|
27
|
+
}
|
|
28
|
+
/** Send a JSON command to the agent and await the response (5s timeout). */
|
|
29
|
+
export function sendCommand(command) {
|
|
30
|
+
const sock = socket;
|
|
31
|
+
if (!sock || sock.destroyed) {
|
|
32
|
+
return Promise.reject(new Error("Not connected to device. Troubleshooting: " +
|
|
33
|
+
"(1) Call geo_connect_device with the device serial from geo_list_devices. " +
|
|
34
|
+
"(2) Verify the GeoMCP Agent service is running in the app (green indicator). " +
|
|
35
|
+
"(3) Check adb port forwarding: run `adb forward tcp:5005 tcp:5005`."));
|
|
36
|
+
}
|
|
37
|
+
const id = randomUUID();
|
|
38
|
+
const msg = { ...command, id };
|
|
39
|
+
return new Promise((resolve, reject) => {
|
|
40
|
+
const timer = setTimeout(() => {
|
|
41
|
+
pendingRequests.delete(id);
|
|
42
|
+
reject(new Error("Command timed out (5s). Troubleshooting: " +
|
|
43
|
+
"(1) Verify the GeoMCP Agent service is running in the app (green indicator). " +
|
|
44
|
+
"(2) Restart adb port forwarding: `adb forward tcp:5005 tcp:5005`. " +
|
|
45
|
+
"(3) Check agent logs: `adb logcat -s GeoMCP`."));
|
|
46
|
+
}, 5000);
|
|
47
|
+
pendingRequests.set(id, { resolve, reject, timer });
|
|
48
|
+
try {
|
|
49
|
+
sock.write(JSON.stringify(msg) + "\n");
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
clearTimeout(timer);
|
|
53
|
+
pendingRequests.delete(id);
|
|
54
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/** Set up ADB port forwarding and open a TCP socket to the agent. */
|
|
59
|
+
export function connectToDevice(deviceId) {
|
|
60
|
+
// Cancel any pending auto-reconnect so it doesn't clobber this connection
|
|
61
|
+
if (reconnectTimer !== null) {
|
|
62
|
+
clearTimeout(reconnectTimer);
|
|
63
|
+
reconnectTimer = null;
|
|
64
|
+
}
|
|
65
|
+
// User-initiated connections reset the reconnect guard so the next
|
|
66
|
+
// unexpected disconnect is eligible for one automatic retry.
|
|
67
|
+
autoReconnectAttempted = false;
|
|
68
|
+
openSocket(deviceId);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Core connection logic shared by public connectToDevice and the internal
|
|
72
|
+
* auto-reconnect path. Does NOT touch autoReconnectAttempted — callers
|
|
73
|
+
* decide whether the guard should be reset.
|
|
74
|
+
*/
|
|
75
|
+
function openSocket(deviceId) {
|
|
76
|
+
if (!/^[a-zA-Z0-9._:\-]+$/.test(deviceId)) {
|
|
77
|
+
throw new Error(`Invalid device ID: ${deviceId}`);
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
execFileSync("adb", ["-s", deviceId, "forward", "tcp:5005", "tcp:5005"], { encoding: "utf-8" });
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
throw new Error(`Failed to set up adb port forwarding for ${deviceId}: ${err.message}`);
|
|
84
|
+
}
|
|
85
|
+
if (socket && !socket.destroyed) {
|
|
86
|
+
socket.destroy();
|
|
87
|
+
}
|
|
88
|
+
const sock = new net.Socket();
|
|
89
|
+
socket = sock;
|
|
90
|
+
connectedDeviceId = deviceId;
|
|
91
|
+
setupSocketHandlers(sock);
|
|
92
|
+
sock.connect({ host: "127.0.0.1", port: 5005 });
|
|
93
|
+
}
|
|
94
|
+
// ── Internal ─────────────────────────────────────────────────────────────────
|
|
95
|
+
function setupSocketHandlers(sock) {
|
|
96
|
+
socketBuffer = "";
|
|
97
|
+
sock.on("data", (data) => {
|
|
98
|
+
socketBuffer += data.toString();
|
|
99
|
+
const lines = socketBuffer.split("\n");
|
|
100
|
+
socketBuffer = lines.pop(); // keep incomplete last chunk
|
|
101
|
+
for (const line of lines) {
|
|
102
|
+
if (!line.trim())
|
|
103
|
+
continue;
|
|
104
|
+
try {
|
|
105
|
+
const parsed = JSON.parse(line);
|
|
106
|
+
const id = parsed.id;
|
|
107
|
+
if (id && pendingRequests.has(id)) {
|
|
108
|
+
const entry = pendingRequests.get(id);
|
|
109
|
+
clearTimeout(entry.timer);
|
|
110
|
+
entry.resolve(parsed);
|
|
111
|
+
pendingRequests.delete(id);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// ignore unparseable lines
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
const cleanup = () => {
|
|
120
|
+
if (socket !== sock)
|
|
121
|
+
return; // only clean up if this socket is still current
|
|
122
|
+
const previousDeviceId = connectedDeviceId;
|
|
123
|
+
for (const [id, entry] of pendingRequests) {
|
|
124
|
+
clearTimeout(entry.timer);
|
|
125
|
+
entry.reject(new Error("Socket closed. The device may have disconnected. " +
|
|
126
|
+
"Auto-reconnect will be attempted once. If it fails, call geo_connect_device again."));
|
|
127
|
+
pendingRequests.delete(id);
|
|
128
|
+
}
|
|
129
|
+
socket = null;
|
|
130
|
+
connectedDeviceId = null;
|
|
131
|
+
disconnectCallback?.();
|
|
132
|
+
// Auto-reconnect once — avoid infinite retry loop on persistent failures.
|
|
133
|
+
// Uses openSocket (not connectToDevice) so autoReconnectAttempted stays
|
|
134
|
+
// true, preventing further retries if this attempt also fails.
|
|
135
|
+
if (previousDeviceId && !autoReconnectAttempted) {
|
|
136
|
+
autoReconnectAttempted = true;
|
|
137
|
+
reconnectTimer = setTimeout(() => {
|
|
138
|
+
reconnectTimer = null;
|
|
139
|
+
try {
|
|
140
|
+
openSocket(previousDeviceId);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
console.error(`Auto-reconnect failed for ${previousDeviceId}: ${err instanceof Error ? err.message : err}`);
|
|
144
|
+
}
|
|
145
|
+
}, 1000);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
sock.on("error", (err) => {
|
|
149
|
+
console.error(`Socket error: ${err.message}`);
|
|
150
|
+
cleanup();
|
|
151
|
+
});
|
|
152
|
+
sock.on("close", cleanup);
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=device.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.js","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// ── Fetch utilities ──────────────────────────────────────────────────────────
|
|
2
|
+
/**
|
|
3
|
+
* Fetch with an AbortController-based timeout.
|
|
4
|
+
* Rejects with an AbortError if the request exceeds timeoutMs.
|
|
5
|
+
*/
|
|
6
|
+
export async function fetchWithTimeout(url, init, timeoutMs) {
|
|
7
|
+
const controller = new AbortController();
|
|
8
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
9
|
+
try {
|
|
10
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
11
|
+
}
|
|
12
|
+
finally {
|
|
13
|
+
clearTimeout(timer);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=fetch-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-utils.js","sourceRoot":"","sources":["../src/fetch-utils.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAW,EAAE,IAAiB,EAAE,SAAiB;IACtF,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAClE,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Haversine distance between two points in meters. */
|
|
2
|
+
export declare function haversineDistance(lat1: number, lng1: number, lat2: number, lng2: number): number;
|
|
3
|
+
/** Forward azimuth (bearing) in degrees 0-360 from point 1 to point 2. */
|
|
4
|
+
export declare function computeBearing(lat1: number, lng1: number, lat2: number, lng2: number): number;
|
package/dist/geo-math.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// ── Geographic math utilities ────────────────────────────────────────────────
|
|
2
|
+
const R = 6_371_000; // Earth radius in meters
|
|
3
|
+
const toRad = (d) => (d * Math.PI) / 180;
|
|
4
|
+
const toDeg = (r) => (r * 180) / Math.PI;
|
|
5
|
+
/** Haversine distance between two points in meters. */
|
|
6
|
+
export function haversineDistance(lat1, lng1, lat2, lng2) {
|
|
7
|
+
const dLat = toRad(lat2 - lat1);
|
|
8
|
+
const dLng = toRad(lng2 - lng1);
|
|
9
|
+
const a = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLng / 2) ** 2;
|
|
10
|
+
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
11
|
+
}
|
|
12
|
+
/** Forward azimuth (bearing) in degrees 0-360 from point 1 to point 2. */
|
|
13
|
+
export function computeBearing(lat1, lng1, lat2, lng2) {
|
|
14
|
+
const dLng = toRad(lng2 - lng1);
|
|
15
|
+
const y = Math.sin(dLng) * Math.cos(toRad(lat2));
|
|
16
|
+
const x = Math.cos(toRad(lat1)) * Math.sin(toRad(lat2)) -
|
|
17
|
+
Math.sin(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.cos(dLng);
|
|
18
|
+
return (toDeg(Math.atan2(y, x)) + 360) % 360;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=geo-math.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geo-math.js","sourceRoot":"","sources":["../src/geo-math.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAEhF,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,yBAAyB;AAC9C,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;AACjD,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;AAEjD,uDAAuD;AACvD,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,IAAY,EAAE,IAAY,EAAE,IAAY;IACtF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,GACL,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IACpG,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,IAAY,EAAE,IAAY,EAAE,IAAY;IACnF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,MAAM,CAAC,GACL,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AAC/C,CAAC"}
|
package/dist/geocode.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// ── Geocoding ────────────────────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// The active geocoding provider is selected via the PROVIDER environment variable:
|
|
4
|
+
//
|
|
5
|
+
// All providers use a 10-second fetch timeout to prevent indefinite hangs.
|
|
6
|
+
//
|
|
7
|
+
// PROVIDER=osm → Nominatim (default, free, no API key)
|
|
8
|
+
// PROVIDER=google → Google Geocoding API (requires GOOGLE_API_KEY)
|
|
9
|
+
// PROVIDER=mapbox → Mapbox Geocoding (requires MAPBOX_ACCESS_TOKEN)
|
|
10
|
+
//
|
|
11
|
+
// To add a new provider, implement the GeocodeProvider signature and add a
|
|
12
|
+
// case to selectProvider().
|
|
13
|
+
import { fetchWithTimeout } from "./fetch-utils.js";
|
|
14
|
+
// ── Nominatim (OpenStreetMap) ────────────────────────────────────────────────
|
|
15
|
+
const nominatimGeocode = async (place) => {
|
|
16
|
+
const url = `https://nominatim.openstreetmap.org/search?${new URLSearchParams({
|
|
17
|
+
q: place,
|
|
18
|
+
format: "json",
|
|
19
|
+
limit: "1",
|
|
20
|
+
})}`;
|
|
21
|
+
const res = await fetchWithTimeout(url, {
|
|
22
|
+
headers: { "User-Agent": "android-mock-location-mcp/0.1.0" },
|
|
23
|
+
}, 10_000);
|
|
24
|
+
if (!res.ok)
|
|
25
|
+
return null;
|
|
26
|
+
const data = (await res.json());
|
|
27
|
+
if (data.length === 0)
|
|
28
|
+
return null;
|
|
29
|
+
return { lat: parseFloat(data[0].lat), lng: parseFloat(data[0].lon), displayName: data[0].display_name };
|
|
30
|
+
};
|
|
31
|
+
// ── Google Geocoding API ─────────────────────────────────────────────────────
|
|
32
|
+
const googleGeocode = async (place) => {
|
|
33
|
+
const apiKey = process.env.GOOGLE_API_KEY; // Validated by selectProvider()
|
|
34
|
+
const url = `https://maps.googleapis.com/maps/api/geocode/json?${new URLSearchParams({
|
|
35
|
+
address: place,
|
|
36
|
+
key: apiKey,
|
|
37
|
+
})}`;
|
|
38
|
+
const res = await fetchWithTimeout(url, {}, 10_000);
|
|
39
|
+
if (!res.ok)
|
|
40
|
+
return null;
|
|
41
|
+
const data = (await res.json());
|
|
42
|
+
if (data.status !== "OK" || !data.results?.length)
|
|
43
|
+
return null;
|
|
44
|
+
const result = data.results[0];
|
|
45
|
+
return {
|
|
46
|
+
lat: result.geometry.location.lat,
|
|
47
|
+
lng: result.geometry.location.lng,
|
|
48
|
+
displayName: result.formatted_address,
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
// ── Mapbox Geocoding API ─────────────────────────────────────────────────────
|
|
52
|
+
const mapboxGeocode = async (place) => {
|
|
53
|
+
const token = process.env.MAPBOX_ACCESS_TOKEN; // Validated by selectProvider()
|
|
54
|
+
const url = `https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(place)}.json?` +
|
|
55
|
+
new URLSearchParams({ access_token: token, limit: "1" });
|
|
56
|
+
const res = await fetchWithTimeout(url, {
|
|
57
|
+
headers: { "User-Agent": "android-mock-location-mcp/0.1.0" },
|
|
58
|
+
}, 10_000);
|
|
59
|
+
if (!res.ok)
|
|
60
|
+
return null;
|
|
61
|
+
const data = (await res.json());
|
|
62
|
+
if (!data.features?.length)
|
|
63
|
+
return null;
|
|
64
|
+
const feature = data.features[0];
|
|
65
|
+
return {
|
|
66
|
+
lat: feature.center[1],
|
|
67
|
+
lng: feature.center[0],
|
|
68
|
+
displayName: feature.place_name,
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
// ── Provider Selection ───────────────────────────────────────────────────────
|
|
72
|
+
// To switch providers, set PROVIDER env var to "osm", "google", or "mapbox".
|
|
73
|
+
function selectProvider() {
|
|
74
|
+
const name = (process.env.PROVIDER ?? "osm").toLowerCase();
|
|
75
|
+
switch (name) {
|
|
76
|
+
case "google": {
|
|
77
|
+
if (!process.env.GOOGLE_API_KEY) {
|
|
78
|
+
throw new Error("PROVIDER=google requires GOOGLE_API_KEY environment variable");
|
|
79
|
+
}
|
|
80
|
+
return googleGeocode;
|
|
81
|
+
}
|
|
82
|
+
case "mapbox": {
|
|
83
|
+
if (!process.env.MAPBOX_ACCESS_TOKEN) {
|
|
84
|
+
throw new Error("PROVIDER=mapbox requires MAPBOX_ACCESS_TOKEN environment variable");
|
|
85
|
+
}
|
|
86
|
+
return mapboxGeocode;
|
|
87
|
+
}
|
|
88
|
+
default:
|
|
89
|
+
return nominatimGeocode;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const activeProvider = selectProvider();
|
|
93
|
+
export async function geocodePlace(place) {
|
|
94
|
+
try {
|
|
95
|
+
return await activeProvider(place);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=geocode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"geocode.js","sourceRoot":"","sources":["../src/geocode.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED