@haivx/tripmind-maps-mcp 0.3.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.
Files changed (46) hide show
  1. package/README.md +226 -0
  2. package/build/index.d.ts +3 -0
  3. package/build/index.d.ts.map +1 -0
  4. package/build/index.js +80 -0
  5. package/build/index.js.map +1 -0
  6. package/build/tools/directions.d.ts +44 -0
  7. package/build/tools/directions.d.ts.map +1 -0
  8. package/build/tools/directions.js +54 -0
  9. package/build/tools/directions.js.map +1 -0
  10. package/build/tools/distance-matrix.d.ts +41 -0
  11. package/build/tools/distance-matrix.d.ts.map +1 -0
  12. package/build/tools/distance-matrix.js +59 -0
  13. package/build/tools/distance-matrix.js.map +1 -0
  14. package/build/tools/geocode.d.ts +51 -0
  15. package/build/tools/geocode.d.ts.map +1 -0
  16. package/build/tools/geocode.js +90 -0
  17. package/build/tools/geocode.js.map +1 -0
  18. package/build/tools/place-details.d.ts +41 -0
  19. package/build/tools/place-details.d.ts.map +1 -0
  20. package/build/tools/place-details.js +57 -0
  21. package/build/tools/place-details.js.map +1 -0
  22. package/build/tools/search-places.d.ts +50 -0
  23. package/build/tools/search-places.d.ts.map +1 -0
  24. package/build/tools/search-places.js +57 -0
  25. package/build/tools/search-places.js.map +1 -0
  26. package/build/tools/timezone.d.ts +41 -0
  27. package/build/tools/timezone.d.ts.map +1 -0
  28. package/build/tools/timezone.js +47 -0
  29. package/build/tools/timezone.js.map +1 -0
  30. package/build/types.d.ts +107 -0
  31. package/build/types.d.ts.map +1 -0
  32. package/build/types.js +2 -0
  33. package/build/types.js.map +1 -0
  34. package/build/utils/cache.d.ts +21 -0
  35. package/build/utils/cache.d.ts.map +1 -0
  36. package/build/utils/cache.js +41 -0
  37. package/build/utils/cache.js.map +1 -0
  38. package/build/utils/google-client.d.ts +83 -0
  39. package/build/utils/google-client.d.ts.map +1 -0
  40. package/build/utils/google-client.js +330 -0
  41. package/build/utils/google-client.js.map +1 -0
  42. package/build/utils/rate-limiter.d.ts +25 -0
  43. package/build/utils/rate-limiter.d.ts.map +1 -0
  44. package/build/utils/rate-limiter.js +41 -0
  45. package/build/utils/rate-limiter.js.map +1 -0
  46. package/package.json +57 -0
@@ -0,0 +1,83 @@
1
+ import type { GeocodeResult, PlaceSearchResult, PlaceDetailsResult, DirectionsResult, DistanceMatrixResult, TimezoneResult } from "../types.js";
2
+ /**
3
+ * Retry a fallible async function with exponential backoff.
4
+ * Backoff: 1 s, 2 s, 4 s (maxRetries = 3 attempts total).
5
+ * Only retries when `isRetryable` returns true.
6
+ */
7
+ export declare function withRetry<T>(fn: () => Promise<T>, maxRetries?: number): Promise<T>;
8
+ /** Input options for geocode/reverse-geocode calls. */
9
+ export interface GeocodeInput {
10
+ address?: string;
11
+ latlng?: {
12
+ lat: number;
13
+ lng: number;
14
+ };
15
+ language?: string;
16
+ }
17
+ /**
18
+ * Forward geocode an address or reverse geocode a lat/lng pair.
19
+ * Routes to the correct Google Maps API SKU:
20
+ * - Forward: Geocoding API (address → latlng)
21
+ * - Reverse: Reverse Geocoding API (latlng → address)
22
+ */
23
+ export declare function geocode(input: GeocodeInput): Promise<GeocodeResult[]>;
24
+ /** Input options for Places Text Search. */
25
+ export interface SearchPlacesInput {
26
+ query: string;
27
+ location?: {
28
+ lat: number;
29
+ lng: number;
30
+ };
31
+ radius?: number;
32
+ type?: string;
33
+ language?: string;
34
+ }
35
+ /**
36
+ * Search for places by text query.
37
+ * SKU: Text Search — fields: name, formatted_address, geometry, rating, types, place_id
38
+ */
39
+ export declare function searchPlaces(input: SearchPlacesInput): Promise<PlaceSearchResult[]>;
40
+ /** Input options for Place Details lookup. */
41
+ export interface PlaceDetailsInput {
42
+ place_id: string;
43
+ fields?: string[];
44
+ language?: string;
45
+ }
46
+ /**
47
+ * Fetch rich details for a place by place_id.
48
+ * SKU: Place Details
49
+ */
50
+ export declare function placeDetails(input: PlaceDetailsInput): Promise<PlaceDetailsResult>;
51
+ export interface ComputeRouteInput {
52
+ origin: string;
53
+ destination: string;
54
+ mode?: "DRIVE" | "WALK" | "TRANSIT" | "BICYCLE";
55
+ departure_time?: string;
56
+ }
57
+ /**
58
+ * Compute a route between two points using the Google Routes API.
59
+ * SKU: Routes API — Compute Routes
60
+ * Field mask: routes.distanceMeters,routes.duration,routes.localizedValues,routes.legs.steps
61
+ */
62
+ export declare function computeRoute(input: ComputeRouteInput): Promise<DirectionsResult>;
63
+ export interface DistanceMatrixInput {
64
+ origins: string[];
65
+ destinations: string[];
66
+ mode?: "DRIVE" | "WALK" | "TRANSIT" | "BICYCLE";
67
+ }
68
+ /**
69
+ * Calculate travel distances between multiple origins and destinations.
70
+ * SKU: Distance Matrix API
71
+ */
72
+ export declare function distanceMatrix(input: DistanceMatrixInput): Promise<DistanceMatrixResult>;
73
+ export interface TimezoneInput {
74
+ lat: number;
75
+ lng: number;
76
+ timestamp?: number;
77
+ }
78
+ /**
79
+ * Look up timezone info for a coordinate.
80
+ * SKU: Time Zone API
81
+ */
82
+ export declare function timezoneInfo(input: TimezoneInput): Promise<TimezoneResult>;
83
+ //# sourceMappingURL=google-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-client.d.ts","sourceRoot":"","sources":["../../src/utils/google-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAiDhJ;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,SAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAgBnF;AAMD,uDAAuD;AACvD,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAkD3E;AAMD,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA8BzF;AAMD,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAOD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAuCxF;AAsBD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwEtF;AAaD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;CACjD;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAyB9F;AAMD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAsBhF"}
@@ -0,0 +1,330 @@
1
+ import { Client, TravelMode } from "@googlemaps/google-maps-services-js";
2
+ const client = new Client({});
3
+ function getApiKey() {
4
+ const key = process.env["GOOGLE_MAPS_API_KEY"];
5
+ if (!key) {
6
+ throw new Error("GOOGLE_MAPS_API_KEY is not set. Add it to your .env file.");
7
+ }
8
+ return key;
9
+ }
10
+ // ---------------------------------------------------------------------------
11
+ // Retry helpers
12
+ // ---------------------------------------------------------------------------
13
+ function sleep(ms) {
14
+ return new Promise((resolve) => setTimeout(resolve, ms));
15
+ }
16
+ /**
17
+ * Determine if a thrown error is transient and worth retrying.
18
+ * Retries on: network errors, HTTP 5xx, HTTP 429 (rate limit), OVER_QUERY_LIMIT, UNKNOWN_ERROR.
19
+ * Does NOT retry on: 4xx client errors (bad input, invalid key).
20
+ */
21
+ function isRetryable(err) {
22
+ const msg = err.message;
23
+ // Network / connection errors
24
+ if (/ECONNRESET|ETIMEDOUT|ENOTFOUND|ENETUNREACH|ECONNREFUSED/i.test(msg))
25
+ return true;
26
+ // HTTP status codes embedded in error message (e.g. "error: 429 Too Many Requests")
27
+ const statusMatch = msg.match(/:\s*(\d{3})(?:\s|$)/);
28
+ if (statusMatch) {
29
+ const code = parseInt(statusMatch[1], 10);
30
+ if (code === 429)
31
+ return true;
32
+ if (code >= 500)
33
+ return true;
34
+ return false; // 4xx client errors — do not retry
35
+ }
36
+ // Google Maps API status codes in error message
37
+ if (msg.includes("OVER_QUERY_LIMIT"))
38
+ return true;
39
+ if (msg.includes("UNKNOWN_ERROR"))
40
+ return true;
41
+ return false;
42
+ }
43
+ /**
44
+ * Retry a fallible async function with exponential backoff.
45
+ * Backoff: 1 s, 2 s, 4 s (maxRetries = 3 attempts total).
46
+ * Only retries when `isRetryable` returns true.
47
+ */
48
+ export async function withRetry(fn, maxRetries = 3) {
49
+ let lastError = new Error("Unknown error");
50
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
51
+ try {
52
+ return await fn();
53
+ }
54
+ catch (err) {
55
+ lastError = err instanceof Error ? err : new Error(String(err));
56
+ if (!isRetryable(lastError))
57
+ throw lastError;
58
+ const delay = Math.pow(2, attempt) * 1000;
59
+ console.error(`[retry] attempt ${attempt + 1}/${maxRetries} failed: ${lastError.message}. Retrying in ${delay}ms...`);
60
+ await sleep(delay);
61
+ }
62
+ }
63
+ throw lastError;
64
+ }
65
+ /**
66
+ * Forward geocode an address or reverse geocode a lat/lng pair.
67
+ * Routes to the correct Google Maps API SKU:
68
+ * - Forward: Geocoding API (address → latlng)
69
+ * - Reverse: Reverse Geocoding API (latlng → address)
70
+ */
71
+ export async function geocode(input) {
72
+ const key = getApiKey();
73
+ let rawResults;
74
+ if (input.latlng) {
75
+ rawResults = await withRetry(async () => {
76
+ const res = await client.reverseGeocode({
77
+ params: {
78
+ latlng: input.latlng,
79
+ language: input.language,
80
+ key,
81
+ },
82
+ });
83
+ if (res.data.status !== "OK" && res.data.status !== "ZERO_RESULTS") {
84
+ throw new Error(`Google Reverse Geocoding API error: ${res.data.status}`);
85
+ }
86
+ return res.data.results;
87
+ });
88
+ }
89
+ else if (input.address) {
90
+ rawResults = await withRetry(async () => {
91
+ const res = await client.geocode({
92
+ params: {
93
+ address: input.address,
94
+ language: input.language,
95
+ key,
96
+ },
97
+ });
98
+ if (res.data.status !== "OK" && res.data.status !== "ZERO_RESULTS") {
99
+ throw new Error(`Google Geocoding API error: ${res.data.status}`);
100
+ }
101
+ return res.data.results;
102
+ });
103
+ }
104
+ else {
105
+ throw new Error("Either address or latlng must be provided.");
106
+ }
107
+ return rawResults.map((r) => ({
108
+ formatted_address: r.formatted_address,
109
+ location: {
110
+ lat: r.geometry.location.lat,
111
+ lng: r.geometry.location.lng,
112
+ },
113
+ place_id: r.place_id,
114
+ types: r.types,
115
+ }));
116
+ }
117
+ /**
118
+ * Search for places by text query.
119
+ * SKU: Text Search — fields: name, formatted_address, geometry, rating, types, place_id
120
+ */
121
+ export async function searchPlaces(input) {
122
+ const key = getApiKey();
123
+ const results = await withRetry(async () => {
124
+ const res = await client.textSearch({
125
+ params: {
126
+ query: input.query,
127
+ ...(input.location && { location: input.location }),
128
+ ...(input.radius && { radius: input.radius }),
129
+ type: input.type,
130
+ language: input.language,
131
+ key,
132
+ },
133
+ });
134
+ if (res.data.status !== "OK" && res.data.status !== "ZERO_RESULTS") {
135
+ throw new Error(`Google Places Text Search error: ${res.data.status}`);
136
+ }
137
+ return res.data.results ?? [];
138
+ });
139
+ return results.map((r) => ({
140
+ place_id: r.place_id ?? "",
141
+ name: r.name ?? "",
142
+ formatted_address: r.formatted_address ?? "",
143
+ location: {
144
+ lat: r.geometry?.location.lat ?? 0,
145
+ lng: r.geometry?.location.lng ?? 0,
146
+ },
147
+ rating: r.rating,
148
+ types: r.types ?? [],
149
+ }));
150
+ }
151
+ const DEFAULT_DETAIL_FIELDS = [
152
+ "name", "formatted_address", "geometry", "rating",
153
+ "opening_hours", "international_phone_number", "website", "reviews", "types",
154
+ ];
155
+ /**
156
+ * Fetch rich details for a place by place_id.
157
+ * SKU: Place Details
158
+ */
159
+ export async function placeDetails(input) {
160
+ const key = getApiKey();
161
+ const r = await withRetry(async () => {
162
+ const res = await client.placeDetails({
163
+ params: {
164
+ place_id: input.place_id,
165
+ fields: input.fields ?? DEFAULT_DETAIL_FIELDS,
166
+ language: input.language,
167
+ key,
168
+ },
169
+ });
170
+ if (res.data.status !== "OK") {
171
+ throw new Error(`Google Place Details error: ${res.data.status}`);
172
+ }
173
+ return res.data.result;
174
+ });
175
+ return {
176
+ place_id: input.place_id,
177
+ name: r.name ?? "",
178
+ formatted_address: r.formatted_address ?? "",
179
+ location: {
180
+ lat: r.geometry?.location.lat ?? 0,
181
+ lng: r.geometry?.location.lng ?? 0,
182
+ },
183
+ rating: r.rating,
184
+ opening_hours: r.opening_hours
185
+ ? { open_now: r.opening_hours.open_now, weekday_text: r.opening_hours.weekday_text }
186
+ : undefined,
187
+ phone: r.international_phone_number,
188
+ website: r.website,
189
+ reviews: r.reviews?.map((rev) => ({
190
+ author_name: rev.author_name,
191
+ rating: rev.rating,
192
+ text: rev.text,
193
+ time: rev.time,
194
+ })),
195
+ types: r.types,
196
+ };
197
+ }
198
+ const ROUTES_API_URL = "https://routes.googleapis.com/directions/v2:computeRoutes";
199
+ /**
200
+ * Compute a route between two points using the Google Routes API.
201
+ * SKU: Routes API — Compute Routes
202
+ * Field mask: routes.distanceMeters,routes.duration,routes.localizedValues,routes.legs.steps
203
+ */
204
+ export async function computeRoute(input) {
205
+ const key = getApiKey();
206
+ const fieldMask = [
207
+ "routes.distanceMeters",
208
+ "routes.duration",
209
+ "routes.localizedValues",
210
+ "routes.legs.steps.navigationInstruction",
211
+ "routes.legs.steps.distanceMeters",
212
+ "routes.legs.steps.duration",
213
+ "routes.legs.steps.localizedValues",
214
+ ].join(",");
215
+ const body = {
216
+ origin: { address: input.origin },
217
+ destination: { address: input.destination },
218
+ travelMode: input.mode ?? "TRANSIT",
219
+ ...(input.departure_time && { departureTime: input.departure_time }),
220
+ computeAlternativeRoutes: false,
221
+ units: "METRIC",
222
+ };
223
+ const data = await withRetry(async () => {
224
+ const res = await fetch(ROUTES_API_URL, {
225
+ method: "POST",
226
+ headers: {
227
+ "Content-Type": "application/json",
228
+ "X-Goog-Api-Key": key,
229
+ "X-Goog-FieldMask": fieldMask,
230
+ },
231
+ body: JSON.stringify(body),
232
+ });
233
+ if (!res.ok) {
234
+ throw new Error(`Google Routes API error: ${res.status} ${res.statusText}`);
235
+ }
236
+ return res.json();
237
+ });
238
+ if (!data.routes || data.routes.length === 0) {
239
+ throw new Error("Google Routes API returned no routes for this request.");
240
+ }
241
+ const route = data.routes[0];
242
+ const distanceM = route.distanceMeters ?? 0;
243
+ const durationSec = parseInt((route.duration ?? "0s").replace("s", ""), 10);
244
+ const steps = route.legs?.[0]?.steps ?? [];
245
+ return {
246
+ summary: route.localizedValues?.distance?.text
247
+ ? `${route.localizedValues.distance.text} — ${route.localizedValues.duration?.text ?? ""}`
248
+ : `${(distanceM / 1000).toFixed(1)} km`,
249
+ distance: {
250
+ text: route.localizedValues?.distance?.text ?? `${(distanceM / 1000).toFixed(1)} km`,
251
+ value: distanceM,
252
+ },
253
+ duration: {
254
+ text: route.localizedValues?.duration?.text ?? `${Math.round(durationSec / 60)} mins`,
255
+ value: durationSec,
256
+ },
257
+ steps: steps.map((s) => ({
258
+ instruction: s.navigationInstruction?.instructions ?? "",
259
+ distance: {
260
+ text: s.localizedValues?.distance?.text ?? `${s.distanceMeters ?? 0} m`,
261
+ value: s.distanceMeters ?? 0,
262
+ },
263
+ duration: {
264
+ text: s.localizedValues?.duration?.text ?? "",
265
+ value: parseInt((s.duration ?? "0s").replace("s", ""), 10),
266
+ },
267
+ })),
268
+ };
269
+ }
270
+ // ---------------------------------------------------------------------------
271
+ // Distance Matrix
272
+ // ---------------------------------------------------------------------------
273
+ const TRAVEL_MODE_MAP = {
274
+ DRIVE: TravelMode.driving,
275
+ WALK: TravelMode.walking,
276
+ TRANSIT: TravelMode.transit,
277
+ BICYCLE: TravelMode.bicycling,
278
+ };
279
+ /**
280
+ * Calculate travel distances between multiple origins and destinations.
281
+ * SKU: Distance Matrix API
282
+ */
283
+ export async function distanceMatrix(input) {
284
+ const key = getApiKey();
285
+ const mode = TRAVEL_MODE_MAP[input.mode ?? "TRANSIT"] ?? TravelMode.transit;
286
+ const res = await withRetry(async () => {
287
+ const r = await client.distancematrix({
288
+ params: { origins: input.origins, destinations: input.destinations, mode, key },
289
+ });
290
+ if (r.data.status !== "OK") {
291
+ throw new Error(`Google Distance Matrix API error: ${r.data.status}`);
292
+ }
293
+ return r.data;
294
+ });
295
+ const elements = res.rows.flatMap((row, rowIdx) => row.elements.map((el, colIdx) => ({
296
+ origin: res.origin_addresses[rowIdx] ?? input.origins[rowIdx] ?? "",
297
+ destination: res.destination_addresses[colIdx] ?? input.destinations[colIdx] ?? "",
298
+ distance: { text: el.distance?.text ?? "", value: el.distance?.value ?? 0 },
299
+ duration: { text: el.duration?.text ?? "", value: el.duration?.value ?? 0 },
300
+ status: el.status,
301
+ })));
302
+ return { elements };
303
+ }
304
+ /**
305
+ * Look up timezone info for a coordinate.
306
+ * SKU: Time Zone API
307
+ */
308
+ export async function timezoneInfo(input) {
309
+ const key = getApiKey();
310
+ const data = await withRetry(async () => {
311
+ const res = await client.timezone({
312
+ params: {
313
+ location: { lat: input.lat, lng: input.lng },
314
+ timestamp: input.timestamp ?? Math.floor(Date.now() / 1000),
315
+ key,
316
+ },
317
+ });
318
+ if (res.data.status !== "OK") {
319
+ throw new Error(`Google Timezone API error: ${res.data.status}`);
320
+ }
321
+ return res.data;
322
+ });
323
+ return {
324
+ timezone_id: data.timeZoneId,
325
+ timezone_name: data.timeZoneName,
326
+ utc_offset_seconds: data.rawOffset,
327
+ dst_offset_seconds: data.dstOffset,
328
+ };
329
+ }
330
+ //# sourceMappingURL=google-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google-client.js","sourceRoot":"","sources":["../../src/utils/google-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /** Result from a rate limit check. */
2
+ export interface RateLimitResult {
3
+ allowed: boolean;
4
+ remaining: number;
5
+ reset_at: number;
6
+ }
7
+ declare class RateLimiter {
8
+ /** Maps a key to an array of request timestamps within the current window. */
9
+ private windows;
10
+ /**
11
+ * Check whether a request identified by `key` is within the rate limit.
12
+ * Uses a sliding window of 60 seconds.
13
+ */
14
+ checkLimit(key: string): RateLimitResult;
15
+ }
16
+ /** Singleton rate limiter shared across all tools. */
17
+ export declare const rateLimiter: RateLimiter;
18
+ /**
19
+ * Assert that the given key has not exceeded the rate limit.
20
+ * Throws a descriptive Error if the limit is exceeded.
21
+ * For stdio mode, use key = "stdio". For HTTP mode, use the client IP.
22
+ */
23
+ export declare function assertRateLimit(key: string): void;
24
+ export {};
25
+ //# sourceMappingURL=rate-limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"AAGA,sCAAsC;AACtC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,cAAM,WAAW;IACf,8EAA8E;IAC9E,OAAO,CAAC,OAAO,CAA+B;IAE9C;;;OAGG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe;CAqBzC;AAED,sDAAsD;AACtD,eAAO,MAAM,WAAW,aAAoB,CAAC;AAE7C;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAQjD"}
@@ -0,0 +1,41 @@
1
+ const WINDOW_MS = 60_000;
2
+ const RPM_LIMIT = parseInt(process.env["RATE_LIMIT_RPM"] ?? "100", 10);
3
+ class RateLimiter {
4
+ /** Maps a key to an array of request timestamps within the current window. */
5
+ windows = new Map();
6
+ /**
7
+ * Check whether a request identified by `key` is within the rate limit.
8
+ * Uses a sliding window of 60 seconds.
9
+ */
10
+ checkLimit(key) {
11
+ const now = Date.now();
12
+ const windowStart = now - WINDOW_MS;
13
+ // Get existing timestamps, drop expired ones
14
+ const timestamps = (this.windows.get(key) ?? []).filter((t) => t > windowStart);
15
+ const allowed = timestamps.length < RPM_LIMIT;
16
+ if (allowed) {
17
+ timestamps.push(now);
18
+ }
19
+ this.windows.set(key, timestamps);
20
+ return {
21
+ allowed,
22
+ remaining: Math.max(0, RPM_LIMIT - timestamps.length),
23
+ reset_at: timestamps[0] ? timestamps[0] + WINDOW_MS : now + WINDOW_MS,
24
+ };
25
+ }
26
+ }
27
+ /** Singleton rate limiter shared across all tools. */
28
+ export const rateLimiter = new RateLimiter();
29
+ /**
30
+ * Assert that the given key has not exceeded the rate limit.
31
+ * Throws a descriptive Error if the limit is exceeded.
32
+ * For stdio mode, use key = "stdio". For HTTP mode, use the client IP.
33
+ */
34
+ export function assertRateLimit(key) {
35
+ const result = rateLimiter.checkLimit(key);
36
+ if (!result.allowed) {
37
+ const resetIn = Math.ceil((result.reset_at - Date.now()) / 1000);
38
+ throw new Error(`Rate limit exceeded. ${result.remaining} requests remaining. Resets in ${resetIn}s.`);
39
+ }
40
+ }
41
+ //# sourceMappingURL=rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/utils/rate-limiter.ts"],"names":[],"mappings":"AAAA,MAAM,SAAS,GAAG,MAAM,CAAC;AACzB,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC,CAAC;AASvE,MAAM,WAAW;IACf,8EAA8E;IACtE,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE9C;;;OAGG;IACH,UAAU,CAAC,GAAW;QACpB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,WAAW,GAAG,GAAG,GAAG,SAAS,CAAC;QAEpC,6CAA6C;QAC7C,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CACrD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,WAAW,CACvB,CAAC;QAEF,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,GAAG,SAAS,CAAC;QAC9C,IAAI,OAAO,EAAE,CAAC;YACZ,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAElC,OAAO;YACL,OAAO;YACP,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC;YACrD,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,SAAS;SACtE,CAAC;IACJ,CAAC;CACF;AAED,sDAAsD;AACtD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AAE7C;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACjE,MAAM,IAAI,KAAK,CACb,wBAAwB,MAAM,CAAC,SAAS,kCAAkC,OAAO,IAAI,CACtF,CAAC;IACJ,CAAC;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@haivx/tripmind-maps-mcp",
3
+ "version": "0.3.0",
4
+ "description": "Travel-focused MCP server wrapping Google Maps API for TripMind",
5
+ "type": "module",
6
+ "bin": {
7
+ "tripmind-maps-mcp": "build/index.js"
8
+ },
9
+ "files": [
10
+ "build"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc && chmod 755 build/index.js",
14
+ "dev": "node --import tsx --watch src/index.ts",
15
+ "start": "node build/index.js",
16
+ "start:http": "PORT=3000 node build/index.js --http",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest",
19
+ "typecheck": "tsc --noEmit",
20
+ "lint": "eslint src/ --ext .ts",
21
+ "inspect": "npx @modelcontextprotocol/inspector node build/index.js"
22
+ },
23
+ "dependencies": {
24
+ "@googlemaps/google-maps-services-js": "^3.4.0",
25
+ "@modelcontextprotocol/sdk": "^1.27.0",
26
+ "dotenv": "^16.4.0",
27
+ "express": "^4.21.0",
28
+ "zod": "^3.24.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/express": "^5.0.0",
32
+ "@types/node": "^22.0.0",
33
+ "eslint": "^9.0.0",
34
+ "tsx": "^4.19.0",
35
+ "typescript": "^5.7.0",
36
+ "typescript-eslint": "^8.57.1",
37
+ "vitest": "^3.0.0"
38
+ },
39
+ "engines": {
40
+ "node": ">=20.0.0"
41
+ },
42
+ "keywords": [
43
+ "mcp",
44
+ "model-context-protocol",
45
+ "google-maps",
46
+ "travel",
47
+ "geocoding",
48
+ "claude",
49
+ "ai"
50
+ ],
51
+ "author": "haivx",
52
+ "license": "MIT",
53
+ "repository": {
54
+ "type": "git",
55
+ "url": "git+https://github.com/haivx/tripmind-maps-mcp.git"
56
+ }
57
+ }