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/dist/index.js
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { geocodePlace } from "./geocode.js";
|
|
6
|
+
import { haversineDistance } from "./geo-math.js";
|
|
7
|
+
import { getRoute, interpolateAlongRoute, bearingAlongRoute } from "./routing.js";
|
|
8
|
+
import { sendCommand, connectToDevice, listDevices, getConnectedDeviceId, isConnected, onDisconnect, } from "./device.js";
|
|
9
|
+
// ── Simulation State ─────────────────────────────────────────────────────────
|
|
10
|
+
let simulationTimer = null;
|
|
11
|
+
let lastLat = null;
|
|
12
|
+
let lastLng = null;
|
|
13
|
+
function stopSimulation() {
|
|
14
|
+
if (simulationTimer !== null) {
|
|
15
|
+
clearInterval(simulationTimer);
|
|
16
|
+
simulationTimer = null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
// Stop any running simulation when the device disconnects.
|
|
20
|
+
onDisconnect(() => stopSimulation());
|
|
21
|
+
function text(msg) {
|
|
22
|
+
return { content: [{ type: "text", text: msg }] };
|
|
23
|
+
}
|
|
24
|
+
const isOsmProvider = !process.env.PROVIDER || ["osm", "osrm"].includes(process.env.PROVIDER.toLowerCase());
|
|
25
|
+
const geocodeHint = isOsmProvider
|
|
26
|
+
? " Prefer resolving place names to lat/lng coordinates yourself and passing them directly, as the default geocoder (Nominatim) is rate-limited."
|
|
27
|
+
: "";
|
|
28
|
+
// ── MCP Server ──────────────────────────────────────────────────────────────
|
|
29
|
+
const server = new McpServer({
|
|
30
|
+
name: "android-mock-location-mcp",
|
|
31
|
+
version: "0.1.0",
|
|
32
|
+
});
|
|
33
|
+
// 1. geo_list_devices
|
|
34
|
+
server.registerTool("geo_list_devices", { description: "List connected Android devices via ADB" }, async () => {
|
|
35
|
+
try {
|
|
36
|
+
const raw = listDevices();
|
|
37
|
+
const lines = raw.split("\n").slice(1).filter((l) => l.trim());
|
|
38
|
+
if (lines.length === 0)
|
|
39
|
+
return text("No devices found. Ensure USB debugging is enabled.");
|
|
40
|
+
const devices = lines.map((l) => {
|
|
41
|
+
const parts = l.split(/\s+/);
|
|
42
|
+
return ` ${parts[0]} ${parts.slice(1).join(" ")}`;
|
|
43
|
+
});
|
|
44
|
+
return text(`Devices:\n${devices.join("\n")}`);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return text("Error: adb not found. Install Android SDK Platform Tools and ensure adb is on PATH.");
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
// 2. geo_connect_device
|
|
51
|
+
server.registerTool("geo_connect_device", {
|
|
52
|
+
description: "Connect to an Android device for mock location control",
|
|
53
|
+
inputSchema: { deviceId: z.string().describe("Device serial from geo_list_devices, e.g. emulator-5554") },
|
|
54
|
+
}, async ({ deviceId }) => {
|
|
55
|
+
try {
|
|
56
|
+
connectToDevice(deviceId);
|
|
57
|
+
// Verify with status ping
|
|
58
|
+
const res = (await sendCommand({ type: "status" }));
|
|
59
|
+
if (res.success)
|
|
60
|
+
return text(`Connected to ${deviceId}. Agent is running.`);
|
|
61
|
+
return text(`Connected to ${deviceId}, but agent returned unexpected response.`);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
return text(`Failed to connect to ${deviceId}: ${err.message}`);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
// 3. geo_set_location
|
|
68
|
+
server.registerTool("geo_set_location", {
|
|
69
|
+
description: "Set device GPS to coordinates or any place name/address (geocoded via configured provider)." + geocodeHint,
|
|
70
|
+
inputSchema: {
|
|
71
|
+
lat: z.number().optional().describe("Latitude (-90 to 90)"),
|
|
72
|
+
lng: z.number().optional().describe("Longitude (-180 to 180)"),
|
|
73
|
+
place: z.string().optional().describe("Any place name or address, e.g. 'Uber HQ', 'Tokyo Station', '123 Main St Denver'"),
|
|
74
|
+
accuracy: z.number().default(3.0).describe("GPS accuracy in meters"),
|
|
75
|
+
},
|
|
76
|
+
}, async ({ lat, lng, place, accuracy }) => {
|
|
77
|
+
let coords;
|
|
78
|
+
let resolvedName;
|
|
79
|
+
if (place) {
|
|
80
|
+
const resolved = await geocodePlace(place);
|
|
81
|
+
if (!resolved) {
|
|
82
|
+
return text(`Could not geocode "${place}". Try a more specific name or pass lat/lng directly.`);
|
|
83
|
+
}
|
|
84
|
+
coords = resolved;
|
|
85
|
+
resolvedName = resolved.displayName;
|
|
86
|
+
}
|
|
87
|
+
else if (lat !== undefined && lng !== undefined) {
|
|
88
|
+
coords = { lat, lng };
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
return text("Provide either 'place' or both 'lat' and 'lng'.");
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const res = (await sendCommand({
|
|
95
|
+
type: "set_location",
|
|
96
|
+
lat: coords.lat,
|
|
97
|
+
lng: coords.lng,
|
|
98
|
+
accuracy,
|
|
99
|
+
altitude: 0,
|
|
100
|
+
speed: 0,
|
|
101
|
+
bearing: 0,
|
|
102
|
+
}));
|
|
103
|
+
let msg = `Location set to ${coords.lat.toFixed(6)}, ${coords.lng.toFixed(6)}`;
|
|
104
|
+
if (resolvedName)
|
|
105
|
+
msg += ` (${resolvedName})`;
|
|
106
|
+
if (lastLat !== null && lastLng !== null) {
|
|
107
|
+
const dist = haversineDistance(lastLat, lastLng, coords.lat, coords.lng);
|
|
108
|
+
if (dist > 100_000) {
|
|
109
|
+
msg += `\n Warning: Teleported ${(dist / 1000).toFixed(0)} km. Apps may flag this.`;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
lastLat = coords.lat;
|
|
113
|
+
lastLng = coords.lng;
|
|
114
|
+
return text(res.success ? msg : `Agent error: ${JSON.stringify(res)}`);
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
return text(`Error: ${err.message}`);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
// 4. geo_simulate_route
|
|
121
|
+
server.registerTool("geo_simulate_route", {
|
|
122
|
+
description: "Simulate movement along a route between two points at a given speed. " +
|
|
123
|
+
"Routes follow real streets via a routing provider (configurable via PROVIDER env var). " +
|
|
124
|
+
"Accepts place names (geocoded via configured provider) or lat/lng coordinates." + geocodeHint,
|
|
125
|
+
inputSchema: {
|
|
126
|
+
from: z.string().optional().describe("Starting place name or address"),
|
|
127
|
+
to: z.string().optional().describe("Destination place name or address"),
|
|
128
|
+
fromLat: z.number().optional().describe("Starting latitude"),
|
|
129
|
+
fromLng: z.number().optional().describe("Starting longitude"),
|
|
130
|
+
toLat: z.number().optional().describe("Destination latitude"),
|
|
131
|
+
toLng: z.number().optional().describe("Destination longitude"),
|
|
132
|
+
speedKmh: z.number().default(60).describe("Speed in km/h"),
|
|
133
|
+
trafficMultiplier: z.number().default(1.0).describe("Traffic slowdown factor (e.g. 1.5 = 50% slower)"),
|
|
134
|
+
profile: z
|
|
135
|
+
.enum(["car", "foot", "bike"])
|
|
136
|
+
.default("car")
|
|
137
|
+
.describe("Routing profile. Use 'foot' for walking, 'bike' for cycling, 'car' for driving. Choose based on the user's intent."),
|
|
138
|
+
},
|
|
139
|
+
}, async ({ from, to, fromLat, fromLng, toLat, toLng, speedKmh, trafficMultiplier, profile }) => {
|
|
140
|
+
const resolveEndpoint = async (name, lat, lng, label) => {
|
|
141
|
+
if (name) {
|
|
142
|
+
const r = await geocodePlace(name);
|
|
143
|
+
if (!r)
|
|
144
|
+
return {
|
|
145
|
+
error: `Could not geocode "${name}" for ${label}. Try a more specific name or use ${label}Lat/${label}Lng.`,
|
|
146
|
+
};
|
|
147
|
+
return { lat: r.lat, lng: r.lng };
|
|
148
|
+
}
|
|
149
|
+
if (lat !== undefined && lng !== undefined)
|
|
150
|
+
return { lat, lng };
|
|
151
|
+
return { error: `Provide '${label}' place name or ${label}Lat/${label}Lng coordinates` };
|
|
152
|
+
};
|
|
153
|
+
const start = await resolveEndpoint(from, fromLat, fromLng, "from");
|
|
154
|
+
const end = await resolveEndpoint(to, toLat, toLng, "to");
|
|
155
|
+
if ("error" in start)
|
|
156
|
+
return text(start.error);
|
|
157
|
+
if ("error" in end)
|
|
158
|
+
return text(end.error);
|
|
159
|
+
// Fetch street-level route (falls back to straight-line if provider fails)
|
|
160
|
+
const route = await getRoute(start.lat, start.lng, end.lat, end.lng, profile);
|
|
161
|
+
const effectiveSpeed = (speedKmh / trafficMultiplier) * (1000 / 3600); // m/s
|
|
162
|
+
const totalSeconds = Math.max(1, Math.round(route.distanceMeters / effectiveSpeed));
|
|
163
|
+
stopSimulation();
|
|
164
|
+
let step = 0;
|
|
165
|
+
// Send starting position immediately
|
|
166
|
+
const startPoint = route.points[0];
|
|
167
|
+
sendCommand({
|
|
168
|
+
type: "set_location",
|
|
169
|
+
lat: startPoint.lat,
|
|
170
|
+
lng: startPoint.lng,
|
|
171
|
+
accuracy: 3,
|
|
172
|
+
altitude: 0,
|
|
173
|
+
speed: 0,
|
|
174
|
+
bearing: bearingAlongRoute(route, 0),
|
|
175
|
+
}).catch(() => { });
|
|
176
|
+
lastLat = startPoint.lat;
|
|
177
|
+
lastLng = startPoint.lng;
|
|
178
|
+
simulationTimer = setInterval(() => {
|
|
179
|
+
step++;
|
|
180
|
+
if (step > totalSeconds) {
|
|
181
|
+
const endPoint = route.points[route.points.length - 1];
|
|
182
|
+
sendCommand({
|
|
183
|
+
type: "set_location",
|
|
184
|
+
lat: endPoint.lat,
|
|
185
|
+
lng: endPoint.lng,
|
|
186
|
+
accuracy: 3,
|
|
187
|
+
altitude: 0,
|
|
188
|
+
speed: 0,
|
|
189
|
+
bearing: 0,
|
|
190
|
+
}).catch(() => { });
|
|
191
|
+
lastLat = endPoint.lat;
|
|
192
|
+
lastLng = endPoint.lng;
|
|
193
|
+
stopSimulation();
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const frac = step / totalSeconds;
|
|
197
|
+
const pos = interpolateAlongRoute(route, frac);
|
|
198
|
+
const bearing = bearingAlongRoute(route, frac);
|
|
199
|
+
sendCommand({
|
|
200
|
+
type: "set_location",
|
|
201
|
+
lat: pos.lat,
|
|
202
|
+
lng: pos.lng,
|
|
203
|
+
accuracy: 3,
|
|
204
|
+
altitude: 0,
|
|
205
|
+
speed: effectiveSpeed,
|
|
206
|
+
bearing,
|
|
207
|
+
}).catch(() => { });
|
|
208
|
+
lastLat = pos.lat;
|
|
209
|
+
lastLng = pos.lng;
|
|
210
|
+
}, 1000);
|
|
211
|
+
const etaMin = (totalSeconds / 60).toFixed(1);
|
|
212
|
+
const routeInfo = route.source === "straight-line"
|
|
213
|
+
? "straight-line (fallback)"
|
|
214
|
+
: `${route.source}, profile: ${profile}, ${route.points.length} waypoints`;
|
|
215
|
+
return text(`Route simulation started.\n` +
|
|
216
|
+
` Routing: ${routeInfo}\n` +
|
|
217
|
+
` Distance: ${(route.distanceMeters / 1000).toFixed(2)} km\n` +
|
|
218
|
+
` Speed: ${(effectiveSpeed * 3.6).toFixed(1)} km/h (traffic x${trafficMultiplier})\n` +
|
|
219
|
+
` ETA: ${etaMin} min (${totalSeconds} steps at 1 Hz)`);
|
|
220
|
+
});
|
|
221
|
+
// 5. geo_simulate_jitter
|
|
222
|
+
server.registerTool("geo_simulate_jitter", {
|
|
223
|
+
description: "Simulate GPS noise/jitter at a location for testing accuracy handling. Accepts place names (geocoded via configured provider) or lat/lng coordinates." + geocodeHint,
|
|
224
|
+
inputSchema: {
|
|
225
|
+
lat: z.number().optional().describe("Center latitude"),
|
|
226
|
+
lng: z.number().optional().describe("Center longitude"),
|
|
227
|
+
place: z.string().optional().describe("Center place name or address"),
|
|
228
|
+
radiusMeters: z.number().default(10).describe("Jitter radius in meters"),
|
|
229
|
+
pattern: z.enum(["random", "drift", "urban_canyon"]).default("random"),
|
|
230
|
+
durationSeconds: z.number().default(30).describe("Duration in seconds"),
|
|
231
|
+
},
|
|
232
|
+
}, async ({ lat, lng, place, radiusMeters, pattern, durationSeconds }) => {
|
|
233
|
+
let center;
|
|
234
|
+
if (place) {
|
|
235
|
+
const r = await geocodePlace(place);
|
|
236
|
+
if (!r)
|
|
237
|
+
return text(`Could not geocode "${place}". Try a more specific name or pass lat/lng directly.`);
|
|
238
|
+
center = r;
|
|
239
|
+
}
|
|
240
|
+
else if (lat !== undefined && lng !== undefined) {
|
|
241
|
+
center = { lat, lng };
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
return text("Provide 'place' or both 'lat' and 'lng'.");
|
|
245
|
+
}
|
|
246
|
+
stopSimulation();
|
|
247
|
+
let tick = 0;
|
|
248
|
+
let driftAngle = Math.random() * 2 * Math.PI;
|
|
249
|
+
let canyonBad = false;
|
|
250
|
+
let canyonStreakLeft = 0;
|
|
251
|
+
simulationTimer = setInterval(() => {
|
|
252
|
+
tick++;
|
|
253
|
+
if (tick > durationSeconds) {
|
|
254
|
+
stopSimulation();
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const mPerDegLat = 111_320;
|
|
258
|
+
const mPerDegLng = 111_320 * Math.cos((center.lat * Math.PI) / 180);
|
|
259
|
+
let offsetLat = 0;
|
|
260
|
+
let offsetLng = 0;
|
|
261
|
+
let acc = radiusMeters;
|
|
262
|
+
if (pattern === "random") {
|
|
263
|
+
const angle = Math.random() * 2 * Math.PI;
|
|
264
|
+
const dist = Math.random() * radiusMeters;
|
|
265
|
+
offsetLat = (Math.sin(angle) * dist) / mPerDegLat;
|
|
266
|
+
offsetLng = (Math.cos(angle) * dist) / mPerDegLng;
|
|
267
|
+
acc = radiusMeters + Math.random() * radiusMeters;
|
|
268
|
+
}
|
|
269
|
+
else if (pattern === "drift") {
|
|
270
|
+
driftAngle += (Math.random() - 0.5) * 0.3;
|
|
271
|
+
const dist = (radiusMeters * tick) / durationSeconds;
|
|
272
|
+
offsetLat = (Math.sin(driftAngle) * dist) / mPerDegLat;
|
|
273
|
+
offsetLng = (Math.cos(driftAngle) * dist) / mPerDegLng;
|
|
274
|
+
acc = dist + Math.random() * radiusMeters;
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
// urban_canyon: streaks of good/bad GPS (3-5s each)
|
|
278
|
+
if (canyonStreakLeft <= 0) {
|
|
279
|
+
canyonBad = !canyonBad;
|
|
280
|
+
canyonStreakLeft = 3 + Math.floor(Math.random() * 3); // 3-5 ticks
|
|
281
|
+
}
|
|
282
|
+
canyonStreakLeft--;
|
|
283
|
+
if (!canyonBad) {
|
|
284
|
+
// Good GPS: send center with tight accuracy
|
|
285
|
+
acc = 3 + Math.random() * 2;
|
|
286
|
+
// fall through to sendCommand with offsetLat/offsetLng = 0
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
acc = radiusMeters + Math.random() * radiusMeters;
|
|
290
|
+
const dist = radiusMeters + Math.random() * 30;
|
|
291
|
+
const angle = Math.random() * 2 * Math.PI;
|
|
292
|
+
offsetLat = (Math.sin(angle) * dist) / mPerDegLat;
|
|
293
|
+
offsetLng = (Math.cos(angle) * dist) / mPerDegLng;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
sendCommand({
|
|
297
|
+
type: "set_location",
|
|
298
|
+
lat: center.lat + offsetLat,
|
|
299
|
+
lng: center.lng + offsetLng,
|
|
300
|
+
accuracy: acc,
|
|
301
|
+
altitude: 0,
|
|
302
|
+
speed: 0,
|
|
303
|
+
bearing: 0,
|
|
304
|
+
}).catch(() => { });
|
|
305
|
+
lastLat = center.lat + offsetLat;
|
|
306
|
+
lastLng = center.lng + offsetLng;
|
|
307
|
+
}, 1000);
|
|
308
|
+
return text(`Jitter simulation started.\n` +
|
|
309
|
+
` Center: ${center.lat.toFixed(6)}, ${center.lng.toFixed(6)}\n` +
|
|
310
|
+
` Pattern: ${pattern}, Radius: ${radiusMeters}m\n` +
|
|
311
|
+
` Duration: ${durationSeconds}s`);
|
|
312
|
+
});
|
|
313
|
+
// 6. geo_test_geofence
|
|
314
|
+
server.registerTool("geo_test_geofence", {
|
|
315
|
+
description: "Test geofence enter/exit/bounce behavior at a location. Accepts place names (geocoded via configured provider) or lat/lng coordinates." + geocodeHint,
|
|
316
|
+
inputSchema: {
|
|
317
|
+
lat: z.number().optional().describe("Geofence center latitude"),
|
|
318
|
+
lng: z.number().optional().describe("Geofence center longitude"),
|
|
319
|
+
place: z.string().optional().describe("Geofence center place name or address"),
|
|
320
|
+
radiusMeters: z.number().default(100).describe("Geofence radius in meters"),
|
|
321
|
+
action: z.enum(["enter", "exit", "bounce"]).default("enter"),
|
|
322
|
+
bounceCount: z.number().default(3).describe("Number of boundary crossings for bounce action"),
|
|
323
|
+
},
|
|
324
|
+
}, async ({ lat, lng, place, radiusMeters, action, bounceCount }) => {
|
|
325
|
+
let center;
|
|
326
|
+
if (place) {
|
|
327
|
+
const r = await geocodePlace(place);
|
|
328
|
+
if (!r)
|
|
329
|
+
return text(`Could not geocode "${place}". Try a more specific name or pass lat/lng directly.`);
|
|
330
|
+
center = r;
|
|
331
|
+
}
|
|
332
|
+
else if (lat !== undefined && lng !== undefined) {
|
|
333
|
+
center = { lat, lng };
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
return text("Provide 'place' or both 'lat' and 'lng'.");
|
|
337
|
+
}
|
|
338
|
+
stopSimulation();
|
|
339
|
+
const outside = 1.5 * radiusMeters;
|
|
340
|
+
const inside = 0.3 * radiusMeters;
|
|
341
|
+
const mPerDegLat = 111_320;
|
|
342
|
+
const offsetDeg = (m) => m / mPerDegLat;
|
|
343
|
+
const positions = [];
|
|
344
|
+
const steps = 5;
|
|
345
|
+
if (action === "enter") {
|
|
346
|
+
for (let i = 0; i <= steps; i++) {
|
|
347
|
+
const dist = outside - ((outside - inside) * i) / steps;
|
|
348
|
+
positions.push({ lat: center.lat + offsetDeg(dist), lng: center.lng });
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
else if (action === "exit") {
|
|
352
|
+
for (let i = 0; i <= steps; i++) {
|
|
353
|
+
const dist = inside + ((outside - inside) * i) / steps;
|
|
354
|
+
positions.push({ lat: center.lat + offsetDeg(dist), lng: center.lng });
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
// bounce
|
|
359
|
+
for (let b = 0; b < bounceCount; b++) {
|
|
360
|
+
const goingIn = b % 2 === 0;
|
|
361
|
+
for (let i = 0; i <= steps; i++) {
|
|
362
|
+
const dist = goingIn
|
|
363
|
+
? outside - ((outside - inside) * i) / steps
|
|
364
|
+
: inside + ((outside - inside) * i) / steps;
|
|
365
|
+
positions.push({ lat: center.lat + offsetDeg(dist), lng: center.lng });
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
let idx = 0;
|
|
370
|
+
simulationTimer = setInterval(() => {
|
|
371
|
+
if (idx >= positions.length) {
|
|
372
|
+
stopSimulation();
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
const pos = positions[idx];
|
|
376
|
+
sendCommand({
|
|
377
|
+
type: "set_location",
|
|
378
|
+
lat: pos.lat,
|
|
379
|
+
lng: pos.lng,
|
|
380
|
+
accuracy: 3,
|
|
381
|
+
altitude: 0,
|
|
382
|
+
speed: 0,
|
|
383
|
+
bearing: 0,
|
|
384
|
+
}).catch(() => { });
|
|
385
|
+
lastLat = pos.lat;
|
|
386
|
+
lastLng = pos.lng;
|
|
387
|
+
idx++;
|
|
388
|
+
}, 2000);
|
|
389
|
+
return text(`Geofence test started.\n` +
|
|
390
|
+
` Center: ${center.lat.toFixed(6)}, ${center.lng.toFixed(6)}\n` +
|
|
391
|
+
` Radius: ${radiusMeters}m, Action: ${action}\n` +
|
|
392
|
+
` Steps: ${positions.length} at 2s intervals (${(positions.length * 2)}s total)`);
|
|
393
|
+
});
|
|
394
|
+
// 7. geo_stop
|
|
395
|
+
server.registerTool("geo_stop", { description: "Stop any active location simulation" }, async () => {
|
|
396
|
+
stopSimulation();
|
|
397
|
+
try {
|
|
398
|
+
if (isConnected())
|
|
399
|
+
await sendCommand({ type: "stop" });
|
|
400
|
+
}
|
|
401
|
+
catch {
|
|
402
|
+
// agent may not be connected
|
|
403
|
+
}
|
|
404
|
+
return text("Simulation stopped.");
|
|
405
|
+
});
|
|
406
|
+
// 8. geo_get_status
|
|
407
|
+
server.registerTool("geo_get_status", { description: "Get current connection and simulation status" }, async () => {
|
|
408
|
+
const lines = [];
|
|
409
|
+
lines.push(`Device: ${getConnectedDeviceId() ?? "not connected"}`);
|
|
410
|
+
lines.push(`Simulation: ${simulationTimer ? "active" : "idle"}`);
|
|
411
|
+
if (lastLat !== null && lastLng !== null) {
|
|
412
|
+
lines.push(`Last position: ${lastLat.toFixed(6)}, ${lastLng.toFixed(6)}`);
|
|
413
|
+
}
|
|
414
|
+
if (isConnected()) {
|
|
415
|
+
try {
|
|
416
|
+
const res = (await sendCommand({ type: "status" }));
|
|
417
|
+
lines.push(`Agent: ${JSON.stringify(res)}`);
|
|
418
|
+
}
|
|
419
|
+
catch (err) {
|
|
420
|
+
lines.push(`Agent: unreachable (${err.message})`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return text(lines.join("\n"));
|
|
424
|
+
});
|
|
425
|
+
// ── Start ───────────────────────────────────────────────────────────────────
|
|
426
|
+
const transport = new StdioServerTransport();
|
|
427
|
+
await server.connect(transport);
|
|
428
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface RoutePoint {
|
|
2
|
+
lat: number;
|
|
3
|
+
lng: number;
|
|
4
|
+
}
|
|
5
|
+
export interface RouteResult {
|
|
6
|
+
/** Ordered polyline coordinates along the road. */
|
|
7
|
+
points: RoutePoint[];
|
|
8
|
+
/** Total route distance in meters (along the road). */
|
|
9
|
+
distanceMeters: number;
|
|
10
|
+
/** Cumulative distance from points[0] to points[i]. cumulativeDistances[0] = 0. */
|
|
11
|
+
cumulativeDistances: number[];
|
|
12
|
+
/** Which provider produced this route. */
|
|
13
|
+
source: string;
|
|
14
|
+
}
|
|
15
|
+
export type RoutingProfile = "car" | "foot" | "bike";
|
|
16
|
+
/**
|
|
17
|
+
* A routing provider fetches a street-level route between two coordinates.
|
|
18
|
+
* Returns null on failure (network error, no route found, etc.).
|
|
19
|
+
*/
|
|
20
|
+
export type RoutingProvider = (fromLat: number, fromLng: number, toLat: number, toLng: number, profile: RoutingProfile) => Promise<RouteResult | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Fetch a street-level route. Falls back to straight-line if the provider fails.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getRoute(fromLat: number, fromLng: number, toLat: number, toLng: number, profile: RoutingProfile): Promise<RouteResult>;
|
|
25
|
+
/**
|
|
26
|
+
* Interpolate a position along a route polyline at the given progress fraction (0–1).
|
|
27
|
+
*/
|
|
28
|
+
export declare function interpolateAlongRoute(route: RouteResult, fraction: number): RoutePoint;
|
|
29
|
+
/**
|
|
30
|
+
* Compute bearing along the route polyline at the given progress fraction.
|
|
31
|
+
*/
|
|
32
|
+
export declare function bearingAlongRoute(route: RouteResult, fraction: number): number;
|