@cablate/mcp-google-map 0.0.17 β 0.0.19
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 +12 -10
- package/dist/chunk-TH44WIYW.js +1 -0
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +130 -1
- package/dist/index.js +1 -1
- package/package.json +74 -73
- package/dist/chunk-W2DM2HDK.js +0 -1
package/README.md
CHANGED
|
@@ -25,6 +25,10 @@ All tools and features are confirmed functional through real-world testing.
|
|
|
25
25
|
|
|
26
26
|
## Features
|
|
27
27
|
|
|
28
|
+
### π Latest Updates
|
|
29
|
+
|
|
30
|
+
- **New Places API Integration**: Updated to use Google's new Places API (New) instead of the legacy API to resolve HTTP 403 errors and ensure continued functionality.
|
|
31
|
+
|
|
28
32
|
### πΊοΈ Google Maps Integration
|
|
29
33
|
|
|
30
34
|
- **Location Search**
|
|
@@ -125,8 +129,9 @@ API keys can be provided in three ways (priority order):
|
|
|
125
129
|
"mcp-google-map": {
|
|
126
130
|
"transport": "streamableHttp",
|
|
127
131
|
"url": "http://localhost:3000/mcp",
|
|
132
|
+
// if your MCP Client support 'headers'
|
|
128
133
|
"headers": {
|
|
129
|
-
"X-Google-Maps-API-Key": "YOUR_API_KEY"
|
|
134
|
+
"X-Google-Maps-API-Key": "YOUR_API_KEY"
|
|
130
135
|
}
|
|
131
136
|
}
|
|
132
137
|
}
|
|
@@ -194,7 +199,6 @@ src/
|
|
|
194
199
|
βββ core/
|
|
195
200
|
β βββ BaseMcpServer.ts # Base MCP server with streamable HTTP
|
|
196
201
|
βββ tools/
|
|
197
|
-
βββ echo.ts # Echo service tool
|
|
198
202
|
βββ maps/ # Google Maps tools
|
|
199
203
|
βββ toolclass.ts # Google Maps API client
|
|
200
204
|
βββ searchPlaces.ts # Maps service layer
|
|
@@ -247,14 +251,18 @@ If you have any questions or suggestions, feel free to reach out:
|
|
|
247
251
|
|
|
248
252
|
## Changelog
|
|
249
253
|
|
|
250
|
-
### v0.0.
|
|
254
|
+
### v0.0.18 (Latest)
|
|
255
|
+
|
|
256
|
+
- **Error response improvements**: Now all error messages are in English with more detailed information (previously in Chinese)
|
|
257
|
+
|
|
258
|
+
### v0.0.17
|
|
251
259
|
|
|
252
260
|
- **Added HTTP Header Authentication**: Support for passing API keys via `X-Google-Maps-API-Key` header in MCP Client config
|
|
253
261
|
- **Fixed Concurrent User Issues**: Each session now uses its own API key without conflicts
|
|
254
262
|
- **Fixed npx Execution**: Resolved module bundling issues
|
|
255
263
|
- **Improved Documentation**: Clearer setup instructions
|
|
256
264
|
|
|
257
|
-
### v0.0.
|
|
265
|
+
### v0.0.14
|
|
258
266
|
|
|
259
267
|
- Added streamable HTTP transport support
|
|
260
268
|
- Improved CLI interface with emoji indicators
|
|
@@ -262,12 +270,6 @@ If you have any questions or suggestions, feel free to reach out:
|
|
|
262
270
|
- Added comprehensive tool descriptions for LLM integration
|
|
263
271
|
- Updated to latest MCP SDK version
|
|
264
272
|
|
|
265
|
-
### v0.0.4
|
|
266
|
-
|
|
267
|
-
- Initial release with basic Google Maps integration
|
|
268
|
-
- Support for location search, geocoding, and directions
|
|
269
|
-
- Compatible with MCP protocol
|
|
270
|
-
|
|
271
273
|
## Star History
|
|
272
274
|
|
|
273
275
|
[](https://www.star-history.com/#cablate/mcp-google-map&Date)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Client as x,Language as R}from"@googlemaps/google-maps-services-js";import A from"dotenv";A.config();function y(c){let e=c?.response?.data?.error_message,r=c?.response?.status;return e?`${e} (HTTP ${r})`:c instanceof Error?c.message:String(c)}var P=class{constructor(e){this.defaultLanguage=R.en;if(this.client=new x({}),this.apiKey=e||process.env.GOOGLE_MAPS_API_KEY||"",!this.apiKey)throw new Error("Google Maps API Key is required")}async searchNearbyPlaces(e){let r={location:e.location,radius:e.radius||1e3,keyword:e.keyword,opennow:e.openNow,language:this.defaultLanguage,key:this.apiKey};try{let n=(await this.client.placesNearby({params:r})).data.results;return e.minRating&&(n=n.filter(a=>(a.rating||0)>=(e.minRating||0))),n}catch(t){throw d.error("Error in searchNearbyPlaces:",t),new Error(`Failed to search nearby places: ${y(t)}`)}}async getPlaceDetails(e){try{return(await this.client.placeDetails({params:{place_id:e,fields:["name","rating","formatted_address","opening_hours","reviews","geometry","formatted_phone_number","website","price_level","photos"],language:this.defaultLanguage,key:this.apiKey}})).data.result}catch(r){throw d.error("Error in getPlaceDetails:",r),new Error(`Failed to get place details for ${e}: ${y(r)}`)}}async geocodeAddress(e){try{let r=await this.client.geocode({params:{address:e,key:this.apiKey,language:this.defaultLanguage}});if(r.data.results.length===0)throw new Error(`No location found for address: "${e}"`);let t=r.data.results[0],n=t.geometry.location;return{lat:n.lat,lng:n.lng,formatted_address:t.formatted_address,place_id:t.place_id}}catch(r){throw d.error("Error in geocodeAddress:",r),new Error(`Failed to geocode address "${e}": ${y(r)}`)}}parseCoordinates(e){let r=e.split(",").map(t=>parseFloat(t.trim()));if(r.length!==2||isNaN(r[0])||isNaN(r[1]))throw new Error(`Invalid coordinate format: "${e}". Please use "latitude,longitude" format (e.g., "25.033,121.564"`);return{lat:r[0],lng:r[1]}}async getLocation(e){return e.isCoordinates?this.parseCoordinates(e.value):this.geocodeAddress(e.value)}async geocode(e){try{let r=await this.geocodeAddress(e);return{location:{lat:r.lat,lng:r.lng},formatted_address:r.formatted_address||"",place_id:r.place_id||""}}catch(r){throw d.error("Error in geocode:",r),new Error(`Failed to geocode address "${e}": ${y(r)}`)}}async reverseGeocode(e,r){try{let t=await this.client.reverseGeocode({params:{latlng:{lat:e,lng:r},language:this.defaultLanguage,key:this.apiKey}});if(t.data.results.length===0)throw new Error(`No address found for coordinates: (${e}, ${r})`);let n=t.data.results[0];return{formatted_address:n.formatted_address,place_id:n.place_id,address_components:n.address_components}}catch(t){throw d.error("Error in reverseGeocode:",t),new Error(`Failed to reverse geocode coordinates (${e}, ${r}): ${y(t)}`)}}async calculateDistanceMatrix(e,r,t="driving"){try{let a=(await this.client.distancematrix({params:{origins:e,destinations:r,mode:t,language:this.defaultLanguage,key:this.apiKey}})).data;if(a.status!=="OK")throw new Error(`Distance matrix calculation failed with status: ${a.status}`);let o=[],l=[];return a.rows.forEach(h=>{let u=[],m=[];h.elements.forEach(i=>{i.status==="OK"?(u.push({value:i.distance.value,text:i.distance.text}),m.push({value:i.duration.value,text:i.duration.text})):(u.push(null),m.push(null))}),o.push(u),l.push(m)}),{distances:o,durations:l,origin_addresses:a.origin_addresses,destination_addresses:a.destination_addresses}}catch(n){throw d.error("Error in calculateDistanceMatrix:",n),new Error(`Failed to calculate distance matrix: ${y(n)}`)}}async getDirections(e,r,t="driving",n,a){try{let o;a&&(o=Math.floor(a.getTime()/1e3));let l;o||(n instanceof Date?l=Math.floor(n.getTime()/1e3):n?l=n:l="now");let u=(await this.client.directions({params:{origin:e,destination:r,mode:t,language:this.defaultLanguage,key:this.apiKey,arrival_time:o,departure_time:l}})).data;if(u.status!=="OK")throw new Error(`Failed to get directions with status: ${u.status} (arrival_time: ${o}, departure_time: ${l}`);if(u.routes.length===0)throw new Error(`No route found from "${e}" to "${r}" with mode: ${t}`);let m=u.routes[0],i=m.legs[0],f=s=>{if(!s||typeof s.value!="number")return"";let g=new Date(s.value*1e3),p={year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1};return s.time_zone&&typeof s.time_zone=="string"&&(p.timeZone=s.time_zone),g.toLocaleString(this.defaultLanguage.toString(),p)};return{routes:u.routes,summary:m.summary,total_distance:{value:i.distance.value,text:i.distance.text},total_duration:{value:i.duration.value,text:i.duration.text},arrival_time:f(i.arrival_time),departure_time:f(i.departure_time)}}catch(o){throw d.error("Error in getDirections:",o),new Error(`Failed to get directions from "${e}" to "${r}": ${y(o)}`)}}async getElevation(e){try{let r=e.map(a=>({lat:a.latitude,lng:a.longitude})),n=(await this.client.elevation({params:{locations:r,key:this.apiKey}})).data;if(n.status!=="OK")throw new Error(`Failed to get elevation data with status: ${n.status}`);return n.results.map((a,o)=>({elevation:a.elevation,location:r[o]}))}catch(r){throw d.error("Error in getElevation:",r),new Error(`Failed to get elevation data for ${e.length} location(s): ${y(r)}`)}}};import{PlacesClient as T}from"@googlemaps/places";var _=class{constructor(e){this.defaultLanguage="en";this.placeFieldMask=["displayName","name","id","formattedAddress","location","utcOffsetMinutes","regularOpeningHours.periods","regularOpeningHours.weekdayDescriptions","currentOpeningHours.openNow","nationalPhoneNumber","websiteUri","priceLevel","rating","userRatingCount","reviews.rating","reviews.text","reviews.publishTime","reviews.authorAttribution.displayName","photos.heightPx","photos.widthPx","photos.name"].join(",");if(this.client=new T({apiKey:e||process.env.GOOGLE_MAPS_API_KEY||""}),!e&&!process.env.GOOGLE_MAPS_API_KEY)throw new Error("Google Maps API Key is required")}async getPlaceDetails(e){try{let r=`places/${e}`,[t]=await this.client.getPlace({name:r,languageCode:this.defaultLanguage},{otherArgs:{headers:{"X-Goog-FieldMask":this.placeFieldMask}}});return this.transformPlaceResponse(t)}catch(r){throw d.error("Error in getPlaceDetails (New API):",r),new Error(`Failed to get place details for ${e}: ${this.extractErrorMessage(r)}`)}}transformPlaceResponse(e){return{name:e.displayName?.text||e.name||"",place_id:this.extractLegacyPlaceId(e),formatted_address:e.formattedAddress||"",geometry:{location:{lat:e.location?.latitude||0,lng:e.location?.longitude||0}},rating:e.rating||0,user_ratings_total:e.userRatingCount||0,opening_hours:e.regularOpeningHours?{open_now:this.isCurrentlyOpen(e.regularOpeningHours,e.utcOffsetMinutes,e.currentOpeningHours),weekday_text:this.formatOpeningHours(e.regularOpeningHours)}:void 0,formatted_phone_number:e.nationalPhoneNumber||"",website:e.websiteUri||"",price_level:e.priceLevel||0,reviews:e.reviews?.map(r=>({rating:r.rating||0,text:r.text?.text||"",time:r.publishTime?.seconds||0,author_name:r.authorAttribution?.displayName||""}))||[],photos:e.photos?.map(r=>({photo_reference:r.name||"",height:r.heightPx||0,width:r.widthPx||0}))||[]}}extractLegacyPlaceId(e){let r=e?.name;if(typeof r=="string"&&r.startsWith("places/")){let t=r.substring(7);if(t)return t}return e?.id||""}isCurrentlyOpen(e,r,t){if(typeof t?.openNow=="boolean")return t.openNow;if(typeof e?.openNow=="boolean")return e.openNow;let n=e?.periods;if(!Array.isArray(n)||n.length===0)return!1;let a=24*60,o=a*7,{day:l,minutes:h}=this.getLocalTimeComponents(r),u=l*a+h,m={SUNDAY:0,MONDAY:1,TUESDAY:2,WEDNESDAY:3,THURSDAY:4,FRIDAY:5,SATURDAY:6},i=s=>{if(typeof s=="number"&&s>=0&&s<=6)return s;if(typeof s=="string"){let g=s.toUpperCase();if(g in m)return m[g]}},f=s=>{if(!s)return;let g=typeof s.hours=="number"?s.hours:Number(s.hours??NaN),p=typeof s.minutes=="number"?s.minutes:Number(s.minutes??NaN);if(!(!Number.isFinite(g)||!Number.isFinite(p)))return g*60+p};for(let s of n){let g=i(s?.openDay),p=i(s?.closeDay??s?.openDay),D=f(s?.openTime),N=f(s?.closeTime);if(g===void 0||D===void 0)continue;let b=g*a+D,w;p===void 0||N===void 0?w=b+a:w=p*a+N,w<=b&&(w+=o);let v=u;for(;v<b;)v+=o;if(v>=b&&v<w)return!0}return!1}getLocalTimeComponents(e){let r=new Date;if(typeof e=="number"&&Number.isFinite(e)){let t=new Date(r.getTime()+e*6e4);return{day:t.getUTCDay(),minutes:t.getUTCHours()*60+t.getUTCMinutes()}}return{day:r.getDay(),minutes:r.getHours()*60+r.getMinutes()}}formatOpeningHours(e){return e?.weekdayDescriptions||[]}extractErrorMessage(e){let r=e?.message||e?.details||e?.status;return r?`${r}`:e instanceof Error?e.message:String(e)}};var E=class{constructor(e){this.mapsTools=new P(e),this.newPlacesService=new _(e)}async searchNearby(e){try{let r=await this.mapsTools.getLocation(e.center),t=await this.mapsTools.searchNearbyPlaces({location:r,keyword:e.keyword,radius:e.radius,openNow:e.openNow,minRating:e.minRating});return{location:r,success:!0,data:t.map(n=>({name:n.name,place_id:n.place_id,address:n.formatted_address,location:n.geometry.location,rating:n.rating,total_ratings:n.user_ratings_total,open_now:n.opening_hours?.open_now}))}}catch(r){return{success:!1,error:r instanceof Error?r.message:"An error occurred during search"}}}async getPlaceDetails(e){try{let r=await this.newPlacesService.getPlaceDetails(e);return{success:!0,data:{name:r.name,address:r.formatted_address,location:r.geometry?.location,rating:r.rating,total_ratings:r.user_ratings_total,open_now:r.opening_hours?.open_now,phone:r.formatted_phone_number,website:r.website,price_level:r.price_level,reviews:r.reviews?.map(t=>({rating:t.rating,text:t.text,time:t.time,author_name:t.author_name}))}}}catch(r){return{success:!1,error:r instanceof Error?r.message:"An error occurred while getting place details"}}}async geocode(e){try{return{success:!0,data:await this.mapsTools.geocode(e)}}catch(r){return{success:!1,error:r instanceof Error?r.message:"An error occurred while geocoding address"}}}async reverseGeocode(e,r){try{return{success:!0,data:await this.mapsTools.reverseGeocode(e,r)}}catch(t){return{success:!1,error:t instanceof Error?t.message:"An error occurred during reverse geocoding"}}}async calculateDistanceMatrix(e,r,t="driving"){try{return{success:!0,data:await this.mapsTools.calculateDistanceMatrix(e,r,t)}}catch(n){return{success:!1,error:n instanceof Error?n.message:"An error occurred while calculating distance matrix"}}}async getDirections(e,r,t="driving",n,a){try{let o=n?new Date(n):new Date,l=a?new Date(a):void 0;return{success:!0,data:await this.mapsTools.getDirections(e,r,t,o,l)}}catch(o){return{success:!1,error:o instanceof Error?o.message:"An error occurred while getting directions"}}}async getElevation(e){try{return{success:!0,data:await this.mapsTools.getElevation(e)}}catch(r){return{success:!1,error:r instanceof Error?r.message:"An error occurred while getting elevation data"}}}};var d={log:(...c)=>{console.error("[INFO]",...c)},error:(...c)=>{console.error("[ERROR]",...c)}};export{_ as a,d as b,E as c};
|
package/dist/cli.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
3
|
-
`+JSON.stringify(t.data,null,2)}],isError:!1}:{content:[{type:"text",text:t.error||"\u641C\u5C0B\u5931\u6557"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`\u641C\u5C0B\u9644\u8FD1\u5730\u9EDE\u932F\u8AA4: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var h={NAME:q,DESCRIPTION:W,SCHEMA:Y,ACTION:Z};import{z as F}from"zod";var B="get_place_details",U="Get detailed information about a specific place including contact details, reviews, ratings, and operating hours",Q={placeId:F.string().describe("Google Maps place ID")};async function X(o){try{let e=u(),t=await new d(e).getPlaceDetails(o.placeId);return t.success?{content:[{type:"text",text:JSON.stringify(t.data,null,2)}],isError:!1}:{content:[{type:"text",text:t.error||"\u7372\u53D6\u8A73\u7D30\u8CC7\u8A0A\u5931\u6557"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`\u7372\u53D6\u5730\u9EDE\u8A73\u7D30\u8CC7\u8A0A\u932F\u8AA4: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var v={NAME:B,DESCRIPTION:U,SCHEMA:Q,ACTION:X};import{z as ee}from"zod";var re="maps_geocode",te="Convert addresses or place names to geographic coordinates (latitude and longitude)",se={address:ee.string().describe("Address or place name to convert to coordinates")};async function oe(o){try{let e=u(),t=await new d(e).geocode(o.address);return t.success?{content:[{type:"text",text:JSON.stringify(t.data,null,2)}],isError:!1}:{content:[{type:"text",text:t.error||"\u5730\u5740\u8F49\u63DB\u5EA7\u6A19\u5931\u6557"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`\u5730\u5740\u8F49\u63DB\u5EA7\u6A19\u932F\u8AA4: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var E={NAME:re,DESCRIPTION:te,SCHEMA:se,ACTION:oe};import{z as K}from"zod";var ne="maps_reverse_geocode",ae="Convert geographic coordinates (latitude and longitude) to a human-readable address",ie={latitude:K.number().describe("Latitude coordinate"),longitude:K.number().describe("Longitude coordinate")};async function ce(o){try{let e=u(),t=await new d(e).reverseGeocode(o.latitude,o.longitude);return t.success?{content:[{type:"text",text:JSON.stringify(t.data,null,2)}],isError:!1}:{content:[{type:"text",text:t.error||"\u5EA7\u6A19\u8F49\u63DB\u5730\u5740\u5931\u6557"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`\u5EA7\u6A19\u8F49\u63DB\u5730\u5740\u932F\u8AA4: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var b={NAME:ne,DESCRIPTION:ae,SCHEMA:ie,ACTION:ce};import{z as P}from"zod";var le="maps_distance_matrix",de="Calculate travel distances and durations between multiple origins and destinations for different travel modes",pe={origins:P.array(P.string()).describe("List of origin addresses or coordinates"),destinations:P.array(P.string()).describe("List of destination addresses or coordinates"),mode:P.enum(["driving","walking","bicycling","transit"]).default("driving").describe("Travel mode for calculation")};async function ue(o){try{let e=u(),t=await new d(e).calculateDistanceMatrix(o.origins,o.destinations,o.mode);return t.success?{content:[{type:"text",text:JSON.stringify(t.data,null,2)}],isError:!1}:{content:[{type:"text",text:t.error||"\u8A08\u7B97\u8DDD\u96E2\u77E9\u9663\u5931\u6557"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`\u8A08\u7B97\u8DDD\u96E2\u77E9\u9663\u932F\u8AA4: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var S={NAME:le,DESCRIPTION:de,SCHEMA:pe,ACTION:ue};import{z as _}from"zod";var ge="maps_directions",me="Get detailed turn-by-turn navigation directions between two locations with route information",ye={origin:_.string().describe("Starting point address or coordinates"),destination:_.string().describe("Destination address or coordinates"),mode:_.enum(["driving","walking","bicycling","transit"]).default("driving").describe("Travel mode for directions"),departure_time:_.string().optional().describe("Departure time (ISO string format)"),arrival_time:_.string().optional().describe("Arrival time (ISO string format)")};async function fe(o){try{let e=u(),t=await new d(e).getDirections(o.origin,o.destination,o.mode,o.departure_time,o.arrival_time);return t.success?{content:[{type:"text",text:JSON.stringify(t.data,null,2)}],isError:!1}:{content:[{type:"text",text:t.error||"\u7372\u53D6\u8DEF\u7DDA\u6307\u5F15\u5931\u6557"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`\u7372\u53D6\u8DEF\u7DDA\u6307\u5F15\u932F\u8AA4: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var w={NAME:ge,DESCRIPTION:me,SCHEMA:ye,ACTION:fe};import{z as N}from"zod";var he="maps_elevation",ve="Get elevation data (height above sea level) for specific geographic locations",Ee={locations:N.array(N.object({latitude:N.number().describe("Latitude coordinate"),longitude:N.number().describe("Longitude coordinate")})).describe("List of locations to get elevation data for")};async function be(o){try{let e=u(),t=await new d(e).getElevation(o.locations);return t.success?{content:[{type:"text",text:JSON.stringify(t.data,null,2)}],isError:!1}:{content:[{type:"text",text:t.error||"\u7372\u53D6\u6D77\u62D4\u6578\u64DA\u5931\u6557"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`\u7372\u53D6\u6D77\u62D4\u6578\u64DA\u932F\u8AA4: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var x={NAME:he,DESCRIPTION:ve,SCHEMA:Ee,ACTION:be};var Pe=[{name:"MCP-Server",portEnvVar:"MCP_SERVER_PORT",tools:[{name:h.NAME,description:h.DESCRIPTION,schema:h.SCHEMA,action:o=>h.ACTION(o)},{name:v.NAME,description:v.DESCRIPTION,schema:v.SCHEMA,action:o=>v.ACTION(o)},{name:E.NAME,description:E.DESCRIPTION,schema:E.SCHEMA,action:o=>E.ACTION(o)},{name:b.NAME,description:b.DESCRIPTION,schema:b.SCHEMA,action:o=>b.ACTION(o)},{name:S.NAME,description:S.DESCRIPTION,schema:S.SCHEMA,action:o=>S.ACTION(o)},{name:w.NAME,description:w.DESCRIPTION,schema:w.SCHEMA,action:o=>w.ACTION(o)},{name:x.NAME,description:x.DESCRIPTION,schema:x.SCHEMA,action:o=>x.ACTION(o)}]}],G=Pe;import{McpServer as Se}from"@modelcontextprotocol/sdk/server/mcp.js";import{StreamableHTTPServerTransport as _e}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as we}from"@modelcontextprotocol/sdk/types.js";import $ from"express";import{randomUUID as xe}from"node:crypto";var A=class o{constructor(){this.defaultApiKey=process.env.GOOGLE_MAPS_API_KEY}static getInstance(){return o.instance||(o.instance=new o),o.instance}setDefaultApiKey(e){this.defaultApiKey=e,process.env.GOOGLE_MAPS_API_KEY=e}getApiKey(e,r){if(e){let t=e.headers["x-google-maps-api-key"];if(t)return t;let s=e.headers.authorization;if(s&&s.startsWith("Bearer "))return s.substring(7)}return r||this.defaultApiKey}hasApiKey(e,r){return!!this.getApiKey(e,r)}isValidApiKeyFormat(e){return/^[A-Za-z0-9_-]{20,50}$/.test(e)}};var Ae="0.0.1",C=class{constructor(e,r){this.sessions={};this.httpServer=null;this.serverName=e,this.server=new Se({name:this.serverName,version:Ae},{capabilities:{logging:{},tools:{}}}),this.registerTools(r)}registerTools(e){e.forEach(r=>{this.server.tool(r.name,r.description,r.schema,async t=>r.action(t))})}async connect(e){await this.server.connect(e);let r=process.stdout.write.bind(process.stdout);process.stdout.write=(t,s,a)=>typeof t=="string"&&!t.startsWith("{")?!0:r(t,s,a),n.log(`${this.serverName} connected and ready to process requests`)}async startHttpServer(e){let r=$();r.use($.json()),r.post("/mcp",async(s,a)=>{let i=s.headers["mcp-session-id"],c,l=A.getInstance().getApiKey(s);if(n.log(`${this.serverName} Get API KEY: ${l}`),i&&this.sessions[i])c=this.sessions[i],l&&(c.apiKey=l);else if(!i&&we(s.body)){let g=new _e({sessionIdGenerator:()=>xe(),onsessioninitialized:p=>{this.sessions[p]=c,n.log(`[${this.serverName}] New session initialized: ${p}`)}});c={transport:g,apiKey:l},g.onclose=()=>{g.sessionId&&(delete this.sessions[g.sessionId],n.log(`[${this.serverName}] Session closed: ${g.sessionId}`))},await this.server.connect(g)}else{a.status(400).json({jsonrpc:"2.0",error:{code:-32e3,message:"Bad Request: No valid session ID provided"},id:null});return}await T({apiKey:c.apiKey,sessionId:i},async()=>{await c.transport.handleRequest(s,a,s.body)})});let t=async(s,a)=>{let i=s.headers["mcp-session-id"];if(!i||!this.sessions[i]){a.status(400).send("Invalid or missing session ID");return}let c=this.sessions[i],l=A.getInstance().getApiKey(s);l&&(c.apiKey=l),await T({apiKey:c.apiKey,sessionId:i},async()=>{await c.transport.handleRequest(s,a)})};r.get("/mcp",t),r.delete("/mcp",t),this.httpServer=r.listen(e,()=>{n.log(`[${this.serverName}] HTTP server listening on port ${e}`),n.log(`[${this.serverName}] MCP endpoint available at http://localhost:${e}/mcp`)})}async stopHttpServer(){if(!this.httpServer){n.error(`[${this.serverName}] HTTP server is not running or already stopped.`);return}return new Promise((e,r)=>{this.httpServer.close(t=>{if(t){n.error(`[${this.serverName}] Error stopping HTTP server:`,t),r(t);return}n.log(`[${this.serverName}] HTTP server stopped.`),this.httpServer=null;let s=Object.values(this.sessions).map(a=>(a.transport.sessionId&&delete this.sessions[a.transport.sessionId],Promise.resolve()));Promise.all(s).then(()=>{n.log(`[${this.serverName}] All transports closed.`),e()}).catch(a=>{n.error(`[${this.serverName}] Error during bulk transport closing:`,a),r(a)})})})}};import{fileURLToPath as Ce}from"url";import{dirname as Te}from"path";import{readFileSync as Re}from"fs";var Oe=Ce(import.meta.url),L=Te(Oe);k({path:R(process.cwd(),".env")});k({path:R(L,"../.env")});async function Ie(o,e){o&&(process.env.MCP_SERVER_PORT=o.toString()),e&&(process.env.GOOGLE_MAPS_API_KEY=e),n.log("\u{1F680} Starting Google Maps MCP Server..."),n.log("\u{1F4CD} Available tools: search_nearby, get_place_details, maps_geocode, maps_reverse_geocode, maps_distance_matrix, maps_directions, maps_elevation, echo"),n.log("");let r=G.map(async t=>{let s=process.env[t.portEnvVar];if(!s){n.error(`\u26A0\uFE0F [${t.name}] Port environment variable ${t.portEnvVar} not set.`),n.log(`\u{1F4A1} Please set ${t.portEnvVar} in your .env file or use --port parameter.`),n.log(` Example: ${t.portEnvVar}=3000 or --port 3000`);return}let a=Number(s);if(isNaN(a)||a<=0){n.error(`\u274C [${t.name}] Invalid port number "${s}" defined in ${t.portEnvVar}.`);return}try{let i=new C(t.name,t.tools);n.log(`\u{1F527} [${t.name}] Initializing MCP Server in HTTP mode on port ${a}...`),await i.startHttpServer(a),n.log(`\u2705 [${t.name}] MCP Server started successfully!`),n.log(` \u{1F310} Endpoint: http://localhost:${a}/mcp`),n.log(` \u{1F4DA} Tools: ${t.tools.length} available`)}catch(i){n.error(`\u274C [${t.name}] Failed to start MCP Server on port ${a}:`,i)}});await Promise.allSettled(r),n.log(""),n.log("\u{1F389} Server initialization completed!"),n.log("\u{1F4A1} Need help? Check the README.md for configuration details.")}var De=process.argv[1]&&(process.argv[1].endsWith("cli.ts")||process.argv[1].endsWith("cli.js")||process.argv[1].endsWith("mcp-google-map")||process.argv[1].includes("mcp-google-map")),Ke=import.meta.url===`file://${process.argv[1]}`;if(De||Ke){let o="0.0.0";try{let r=R(L,"../package.json");o=JSON.parse(Re(r,"utf-8")).version}catch{o="0.0.0"}let e=Me(Ne(process.argv)).option("port",{alias:"p",type:"number",description:"Port to run the MCP server on",default:process.env.MCP_SERVER_PORT?parseInt(process.env.MCP_SERVER_PORT):3e3}).option("apikey",{alias:"k",type:"string",description:"Google Maps API key",default:process.env.GOOGLE_MAPS_API_KEY}).option("help",{alias:"h",type:"boolean",description:"Show help"}).version(o).alias("version","v").example([["$0","Start server with default settings"],['$0 --port 3000 --apikey "your_api_key"',"Start server with custom port and API key"],['$0 -p 3001 -k "your_api_key"',"Start server with short options"]]).help().parseSync();n.log("\u{1F5FA}\uFE0F Google Maps MCP Server"),n.log(" A Model Context Protocol server for Google Maps services"),n.log(""),e.apikey||(n.log("\u26A0\uFE0F Google Maps API Key not found!"),n.log(" Please provide --apikey parameter or set GOOGLE_MAPS_API_KEY in your .env file"),n.log(" Example: mcp-google-map --apikey your_api_key_here"),n.log(" Or: GOOGLE_MAPS_API_KEY=your_api_key_here"),n.log("")),Ie(e.port,e.apikey).catch(r=>{n.error("\u274C Failed to start server:",r),process.exit(1)})}export{Ie as startServer};
|
|
2
|
+
import{b as s,c}from"./chunk-TH44WIYW.js";import{config as K}from"dotenv";import{resolve as N}from"path";import Se from"yargs";import{hideBin as Ee}from"yargs/helpers";import{z as m}from"zod";import{AsyncLocalStorage as D}from"node:async_hooks";var O=new D;function p(){return O.getStore()?.apiKey||process.env.GOOGLE_MAPS_API_KEY}function M(t,e){return O.run(t,e)}var G="search_nearby",H="Search for nearby places based on location, with optional filtering by keywords, distance, rating, and operating hours",z={center:m.object({value:m.string().describe("Address, landmark name, or coordinates (coordinate format: lat,lng)"),isCoordinates:m.boolean().default(!1).describe("Whether the value is coordinates")}).describe("Search center point"),keyword:m.string().optional().describe("Search keyword (e.g., restaurant, cafe, hotel)"),radius:m.number().default(1e3).describe("Search radius in meters"),openNow:m.boolean().default(!1).describe("Only show places that are currently open"),minRating:m.number().min(0).max(5).optional().describe("Minimum rating requirement (0-5)")};async function k(t){try{let e=p(),r=await new c(e).searchNearby(t);return r.success?{content:[{type:"text",text:`location: ${JSON.stringify(r.location,null,2)}
|
|
3
|
+
`+JSON.stringify(r.data,null,2)}],isError:!1}:{content:[{type:"text",text:r.error||"Search failed"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`Error searching nearby places: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var u={NAME:G,DESCRIPTION:H,SCHEMA:z,ACTION:k};import{z as J}from"zod";var L="get_place_details",j="Get detailed information about a specific place including contact details, reviews, ratings, and operating hours",V={placeId:J.string().describe("Google Maps place ID")};async function q(t){try{let e=p(),r=await new c(e).getPlaceDetails(t.placeId);return r.success?{content:[{type:"text",text:JSON.stringify(r.data,null,2)}],isError:!1}:{content:[{type:"text",text:r.error||"Failed to get place details"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`Error getting place details: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var y={NAME:L,DESCRIPTION:j,SCHEMA:V,ACTION:q};import{z as F}from"zod";var W="maps_geocode",Y="Convert addresses or place names to geographic coordinates (latitude and longitude)",Z={address:F.string().describe("Address or place name to convert to coordinates")};async function B(t){try{let e=p(),r=await new c(e).geocode(t.address);return r.success?{content:[{type:"text",text:JSON.stringify(r.data,null,2)}],isError:!1}:{content:[{type:"text",text:r.error||"Failed to geocode address"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`Error geocoding address: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var f={NAME:W,DESCRIPTION:Y,SCHEMA:Z,ACTION:B};import{z as T}from"zod";var U="maps_reverse_geocode",Q="Convert geographic coordinates (latitude and longitude) to a human-readable address",X={latitude:T.number().describe("Latitude coordinate"),longitude:T.number().describe("Longitude coordinate")};async function ee(t){try{let e=p(),r=await new c(e).reverseGeocode(t.latitude,t.longitude);return r.success?{content:[{type:"text",text:JSON.stringify(r.data,null,2)}],isError:!1}:{content:[{type:"text",text:r.error||"Failed to reverse geocode coordinates"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`Error reverse geocoding: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var v={NAME:U,DESCRIPTION:Q,SCHEMA:X,ACTION:ee};import{z as h}from"zod";var re="maps_distance_matrix",te="Calculate travel distances and durations between multiple origins and destinations for different travel modes",oe={origins:h.array(h.string()).describe("List of origin addresses or coordinates"),destinations:h.array(h.string()).describe("List of destination addresses or coordinates"),mode:h.enum(["driving","walking","bicycling","transit"]).default("driving").describe("Travel mode for calculation")};async function se(t){try{let e=p(),r=await new c(e).calculateDistanceMatrix(t.origins,t.destinations,t.mode);return r.success?{content:[{type:"text",text:JSON.stringify(r.data,null,2)}],isError:!1}:{content:[{type:"text",text:r.error||"Failed to calculate distance matrix"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`Error calculating distance matrix: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var S={NAME:re,DESCRIPTION:te,SCHEMA:oe,ACTION:se};import{z as E}from"zod";var ne="maps_directions",ie="Get detailed turn-by-turn navigation directions between two locations with route information",ae={origin:E.string().describe("Starting point address or coordinates"),destination:E.string().describe("Destination address or coordinates"),mode:E.enum(["driving","walking","bicycling","transit"]).default("driving").describe("Travel mode for directions"),departure_time:E.string().optional().describe("Departure time (ISO string format)"),arrival_time:E.string().optional().describe("Arrival time (ISO string format)")};async function ce(t){try{let e=p(),r=await new c(e).getDirections(t.origin,t.destination,t.mode,t.departure_time,t.arrival_time);return r.success?{content:[{type:"text",text:JSON.stringify(r.data,null,2)}],isError:!1}:{content:[{type:"text",text:r.error||"Failed to get directions"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`Error getting directions: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var P={NAME:ne,DESCRIPTION:ie,SCHEMA:ae,ACTION:ce};import{z as x}from"zod";var pe="maps_elevation",le="Get elevation data (height above sea level) for specific geographic locations",de={locations:x.array(x.object({latitude:x.number().describe("Latitude coordinate"),longitude:x.number().describe("Longitude coordinate")})).describe("List of locations to get elevation data for")};async function me(t){try{let e=p(),r=await new c(e).getElevation(t.locations);return r.success?{content:[{type:"text",text:JSON.stringify(r.data,null,2)}],isError:!1}:{content:[{type:"text",text:r.error||"Failed to get elevation data"}],isError:!0}}catch(e){return{isError:!0,content:[{type:"text",text:`Error getting elevation data: ${e instanceof Error?e.message:JSON.stringify(e)}`}]}}}var A={NAME:pe,DESCRIPTION:le,SCHEMA:de,ACTION:me};var ge=[{name:"MCP-Server",portEnvVar:"MCP_SERVER_PORT",tools:[{name:u.NAME,description:u.DESCRIPTION,schema:u.SCHEMA,action:t=>u.ACTION(t)},{name:y.NAME,description:y.DESCRIPTION,schema:y.SCHEMA,action:t=>y.ACTION(t)},{name:f.NAME,description:f.DESCRIPTION,schema:f.SCHEMA,action:t=>f.ACTION(t)},{name:v.NAME,description:v.DESCRIPTION,schema:v.SCHEMA,action:t=>v.ACTION(t)},{name:S.NAME,description:S.DESCRIPTION,schema:S.SCHEMA,action:t=>S.ACTION(t)},{name:P.NAME,description:P.DESCRIPTION,schema:P.SCHEMA,action:t=>P.ACTION(t)},{name:A.NAME,description:A.DESCRIPTION,schema:A.SCHEMA,action:t=>A.ACTION(t)}]}],_=ge;import{McpServer as ue}from"@modelcontextprotocol/sdk/server/mcp.js";import{StreamableHTTPServerTransport as ye}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{isInitializeRequest as fe}from"@modelcontextprotocol/sdk/types.js";import R from"express";import{randomUUID as ve}from"node:crypto";var b=class t{constructor(){this.defaultApiKey=process.env.GOOGLE_MAPS_API_KEY}static getInstance(){return t.instance||(t.instance=new t),t.instance}setDefaultApiKey(e){this.defaultApiKey=e,process.env.GOOGLE_MAPS_API_KEY=e}getApiKey(e,o){if(e){let r=e.headers["x-google-maps-api-key"];if(r)return r;let n=e.headers.authorization;if(n&&n.startsWith("Bearer "))return n.substring(7)}return o||this.defaultApiKey}hasApiKey(e,o){return!!this.getApiKey(e,o)}isValidApiKeyFormat(e){return/^[A-Za-z0-9_-]{20,50}$/.test(e)}};var he="0.0.1",C=class{constructor(e,o){this.sessions={};this.httpServer=null;this.serverName=e,this.server=new ue({name:this.serverName,version:he},{capabilities:{logging:{},tools:{}}}),this.registerTools(o)}registerTools(e){e.forEach(o=>{this.server.tool(o.name,o.description,o.schema,async r=>o.action(r))})}async connect(e){await this.server.connect(e);let o=process.stdout.write.bind(process.stdout);process.stdout.write=(r,n,i)=>typeof r=="string"&&!r.startsWith("{")?!0:o(r,n,i),s.log(`${this.serverName} connected and ready to process requests`)}async startHttpServer(e){let o=R();o.use(R.json()),o.post("/mcp",async(n,i)=>{let a=n.headers["mcp-session-id"],l,d=b.getInstance().getApiKey(n);if(s.log(`${this.serverName} Get API KEY: ${d}`),a&&this.sessions[a])l=this.sessions[a],d&&(l.apiKey=d);else if(!a&&fe(n.body)){let g=new ye({sessionIdGenerator:()=>ve(),onsessioninitialized:I=>{this.sessions[I]=l,s.log(`[${this.serverName}] New session initialized: ${I}`)}});l={transport:g,apiKey:d},g.onclose=()=>{g.sessionId&&(delete this.sessions[g.sessionId],s.log(`[${this.serverName}] Session closed: ${g.sessionId}`))},await this.server.connect(g)}else{i.status(400).json({jsonrpc:"2.0",error:{code:-32e3,message:"Bad Request: No valid session ID provided"},id:null});return}await M({apiKey:l.apiKey,sessionId:a},async()=>{await l.transport.handleRequest(n,i,n.body)})});let r=async(n,i)=>{let a=n.headers["mcp-session-id"];if(!a||!this.sessions[a]){i.status(400).send("Invalid or missing session ID");return}let l=this.sessions[a],d=b.getInstance().getApiKey(n);d&&(l.apiKey=d),await M({apiKey:l.apiKey,sessionId:a},async()=>{await l.transport.handleRequest(n,i)})};o.get("/mcp",r),o.delete("/mcp",r),this.httpServer=o.listen(e,()=>{s.log(`[${this.serverName}] HTTP server listening on port ${e}`),s.log(`[${this.serverName}] MCP endpoint available at http://localhost:${e}/mcp`)})}async stopHttpServer(){if(!this.httpServer){s.error(`[${this.serverName}] HTTP server is not running or already stopped.`);return}return new Promise((e,o)=>{this.httpServer.close(r=>{if(r){s.error(`[${this.serverName}] Error stopping HTTP server:`,r),o(r);return}s.log(`[${this.serverName}] HTTP server stopped.`),this.httpServer=null;let n=Object.values(this.sessions).map(i=>(i.transport.sessionId&&delete this.sessions[i.transport.sessionId],Promise.resolve()));Promise.all(n).then(()=>{s.log(`[${this.serverName}] All transports closed.`),e()}).catch(i=>{s.error(`[${this.serverName}] Error during bulk transport closing:`,i),o(i)})})})}};import{fileURLToPath as Pe}from"url";import{dirname as Ae}from"path";import{readFileSync as be}from"fs";var xe=Pe(import.meta.url),w=Ae(xe);K({path:N(process.cwd(),".env")});K({path:N(w,"../.env")});async function Ce(t,e){t&&(process.env.MCP_SERVER_PORT=t.toString()),e&&(process.env.GOOGLE_MAPS_API_KEY=e),s.log("\u{1F680} Starting Google Maps MCP Server..."),s.log("\u{1F4CD} Available tools: search_nearby, get_place_details, maps_geocode, maps_reverse_geocode, maps_distance_matrix, maps_directions, maps_elevation, echo"),s.log("\u2139\uFE0F Reminder: enable Places API (New) in https://console.cloud.google.com before using the new Place features."),s.log("");let o=_.map(async r=>{let n=process.env[r.portEnvVar];if(!n){s.error(`\u26A0\uFE0F [${r.name}] Port environment variable ${r.portEnvVar} not set.`),s.log(`\u{1F4A1} Please set ${r.portEnvVar} in your .env file or use --port parameter.`),s.log(` Example: ${r.portEnvVar}=3000 or --port 3000`);return}let i=Number(n);if(isNaN(i)||i<=0){s.error(`\u274C [${r.name}] Invalid port number "${n}" defined in ${r.portEnvVar}.`);return}try{let a=new C(r.name,r.tools);s.log(`\u{1F527} [${r.name}] Initializing MCP Server in HTTP mode on port ${i}...`),await a.startHttpServer(i),s.log(`\u2705 [${r.name}] MCP Server started successfully!`),s.log(` \u{1F310} Endpoint: http://localhost:${i}/mcp`),s.log(` \u{1F4DA} Tools: ${r.tools.length} available`)}catch(a){s.error(`\u274C [${r.name}] Failed to start MCP Server on port ${i}:`,a)}});await Promise.allSettled(o),s.log(""),s.log("\u{1F389} Server initialization completed!"),s.log("\u{1F4A1} Need help? Check the README.md for configuration details.")}var Me=process.argv[1]&&(process.argv[1].endsWith("cli.ts")||process.argv[1].endsWith("cli.js")||process.argv[1].endsWith("mcp-google-map")||process.argv[1].includes("mcp-google-map")),Ne=import.meta.url===`file://${process.argv[1]}`;if(Me||Ne){let t="0.0.0";try{let o=N(w,"../package.json");t=JSON.parse(be(o,"utf-8")).version}catch{t="0.0.0"}let e=Se(Ee(process.argv)).option("port",{alias:"p",type:"number",description:"Port to run the MCP server on",default:process.env.MCP_SERVER_PORT?parseInt(process.env.MCP_SERVER_PORT):3e3}).option("apikey",{alias:"k",type:"string",description:"Google Maps API key",default:process.env.GOOGLE_MAPS_API_KEY}).option("help",{alias:"h",type:"boolean",description:"Show help"}).version(t).alias("version","v").example([["$0","Start server with default settings"],['$0 --port 3000 --apikey "your_api_key"',"Start server with custom port and API key"],['$0 -p 3001 -k "your_api_key"',"Start server with short options"]]).help().parseSync();s.log("\u{1F5FA}\uFE0F Google Maps MCP Server"),s.log(" A Model Context Protocol server for Google Maps services"),s.log(""),e.apikey||(s.log("\u26A0\uFE0F Google Maps API Key not found!"),s.log(" Please provide --apikey parameter or set GOOGLE_MAPS_API_KEY in your .env file"),s.log(" Example: mcp-google-map --apikey your_api_key_here"),s.log(" Or: GOOGLE_MAPS_API_KEY=your_api_key_here"),s.log("")),Ce(e.port,e.apikey).catch(o=>{s.error("\u274C Failed to start server:",o),process.exit(1)})}export{Ce as startServer};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,135 @@
|
|
|
1
|
+
interface SearchNearbyResponse {
|
|
2
|
+
success: boolean;
|
|
3
|
+
error?: string;
|
|
4
|
+
data?: any[];
|
|
5
|
+
location?: any;
|
|
6
|
+
}
|
|
7
|
+
interface PlaceDetailsResponse {
|
|
8
|
+
success: boolean;
|
|
9
|
+
error?: string;
|
|
10
|
+
data?: any;
|
|
11
|
+
}
|
|
12
|
+
interface GeocodeResponse {
|
|
13
|
+
success: boolean;
|
|
14
|
+
error?: string;
|
|
15
|
+
data?: {
|
|
16
|
+
location: {
|
|
17
|
+
lat: number;
|
|
18
|
+
lng: number;
|
|
19
|
+
};
|
|
20
|
+
formatted_address: string;
|
|
21
|
+
place_id: string;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface ReverseGeocodeResponse {
|
|
25
|
+
success: boolean;
|
|
26
|
+
error?: string;
|
|
27
|
+
data?: {
|
|
28
|
+
formatted_address: string;
|
|
29
|
+
place_id: string;
|
|
30
|
+
address_components: any[];
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
interface DistanceMatrixResponse {
|
|
34
|
+
success: boolean;
|
|
35
|
+
error?: string;
|
|
36
|
+
data?: {
|
|
37
|
+
distances: any[][];
|
|
38
|
+
durations: any[][];
|
|
39
|
+
origin_addresses: string[];
|
|
40
|
+
destination_addresses: string[];
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
interface DirectionsResponse {
|
|
44
|
+
success: boolean;
|
|
45
|
+
error?: string;
|
|
46
|
+
data?: {
|
|
47
|
+
routes: any[];
|
|
48
|
+
summary: string;
|
|
49
|
+
total_distance: {
|
|
50
|
+
value: number;
|
|
51
|
+
text: string;
|
|
52
|
+
};
|
|
53
|
+
total_duration: {
|
|
54
|
+
value: number;
|
|
55
|
+
text: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
interface ElevationResponse {
|
|
60
|
+
success: boolean;
|
|
61
|
+
error?: string;
|
|
62
|
+
data?: Array<{
|
|
63
|
+
elevation: number;
|
|
64
|
+
location: {
|
|
65
|
+
lat: number;
|
|
66
|
+
lng: number;
|
|
67
|
+
};
|
|
68
|
+
}>;
|
|
69
|
+
}
|
|
70
|
+
declare class PlacesSearcher {
|
|
71
|
+
private mapsTools;
|
|
72
|
+
private newPlacesService;
|
|
73
|
+
constructor(apiKey?: string);
|
|
74
|
+
searchNearby(params: {
|
|
75
|
+
center: {
|
|
76
|
+
value: string;
|
|
77
|
+
isCoordinates: boolean;
|
|
78
|
+
};
|
|
79
|
+
keyword?: string;
|
|
80
|
+
radius?: number;
|
|
81
|
+
openNow?: boolean;
|
|
82
|
+
minRating?: number;
|
|
83
|
+
}): Promise<SearchNearbyResponse>;
|
|
84
|
+
getPlaceDetails(placeId: string): Promise<PlaceDetailsResponse>;
|
|
85
|
+
geocode(address: string): Promise<GeocodeResponse>;
|
|
86
|
+
reverseGeocode(latitude: number, longitude: number): Promise<ReverseGeocodeResponse>;
|
|
87
|
+
calculateDistanceMatrix(origins: string[], destinations: string[], mode?: "driving" | "walking" | "bicycling" | "transit"): Promise<DistanceMatrixResponse>;
|
|
88
|
+
getDirections(origin: string, destination: string, mode?: "driving" | "walking" | "bicycling" | "transit", departure_time?: string, arrival_time?: string): Promise<DirectionsResponse>;
|
|
89
|
+
getElevation(locations: Array<{
|
|
90
|
+
latitude: number;
|
|
91
|
+
longitude: number;
|
|
92
|
+
}>): Promise<ElevationResponse>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
declare class NewPlacesService {
|
|
96
|
+
private client;
|
|
97
|
+
private readonly defaultLanguage;
|
|
98
|
+
private readonly placeFieldMask;
|
|
99
|
+
constructor(apiKey?: string);
|
|
100
|
+
getPlaceDetails(placeId: string): Promise<{
|
|
101
|
+
name: any;
|
|
102
|
+
place_id: string;
|
|
103
|
+
formatted_address: any;
|
|
104
|
+
geometry: {
|
|
105
|
+
location: {
|
|
106
|
+
lat: any;
|
|
107
|
+
lng: any;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
rating: any;
|
|
111
|
+
user_ratings_total: any;
|
|
112
|
+
opening_hours: {
|
|
113
|
+
open_now: boolean;
|
|
114
|
+
weekday_text: string[];
|
|
115
|
+
} | undefined;
|
|
116
|
+
formatted_phone_number: any;
|
|
117
|
+
website: any;
|
|
118
|
+
price_level: any;
|
|
119
|
+
reviews: any;
|
|
120
|
+
photos: any;
|
|
121
|
+
}>;
|
|
122
|
+
private transformPlaceResponse;
|
|
123
|
+
private extractLegacyPlaceId;
|
|
124
|
+
private isCurrentlyOpen;
|
|
125
|
+
private getLocalTimeComponents;
|
|
126
|
+
private formatOpeningHours;
|
|
127
|
+
private extractErrorMessage;
|
|
128
|
+
}
|
|
129
|
+
|
|
1
130
|
declare const Logger: {
|
|
2
131
|
log: (...args: any[]) => void;
|
|
3
132
|
error: (...args: any[]) => void;
|
|
4
133
|
};
|
|
5
134
|
|
|
6
|
-
export { Logger };
|
|
135
|
+
export { Logger, NewPlacesService, PlacesSearcher };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a}from"./chunk-
|
|
1
|
+
import{a,b,c}from"./chunk-TH44WIYW.js";export{b as Logger,a as NewPlacesService,c as PlacesSearcher};
|
package/package.json
CHANGED
|
@@ -1,73 +1,74 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@cablate/mcp-google-map",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Google Maps MCP server with streamable HTTP transport support for location services, geocoding, and navigation",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"mcp-google-map": "dist/cli.js"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"dist",
|
|
12
|
-
"dist/**/*.map",
|
|
13
|
-
"README.md"
|
|
14
|
-
],
|
|
15
|
-
"scripts": {
|
|
16
|
-
"build": "tsup --dts",
|
|
17
|
-
"start": "node dist/cli.js",
|
|
18
|
-
"dev": "cross-env NODE_ENV=development tsup --watch",
|
|
19
|
-
"prepublishOnly": "npm run build"
|
|
20
|
-
},
|
|
21
|
-
"engines": {
|
|
22
|
-
"node": ">=18.0.0"
|
|
23
|
-
},
|
|
24
|
-
"keywords": [
|
|
25
|
-
"google",
|
|
26
|
-
"map",
|
|
27
|
-
"api",
|
|
28
|
-
"llm",
|
|
29
|
-
"typescript",
|
|
30
|
-
"mcp",
|
|
31
|
-
"server",
|
|
32
|
-
"streamable",
|
|
33
|
-
"location",
|
|
34
|
-
"geocoding",
|
|
35
|
-
"navigation"
|
|
36
|
-
],
|
|
37
|
-
"author": "CabLate",
|
|
38
|
-
"license": "MIT",
|
|
39
|
-
"homepage": "https://github.com/cablate/mcp-google-map#readme",
|
|
40
|
-
"repository": {
|
|
41
|
-
"type": "git",
|
|
42
|
-
"url": "git+https://github.com/cablate/mcp-google-map.git"
|
|
43
|
-
},
|
|
44
|
-
"bugs": {
|
|
45
|
-
"url": "https://github.com/cablate/mcp-google-map/issues"
|
|
46
|
-
},
|
|
47
|
-
"dependencies": {
|
|
48
|
-
"@googlemaps/google-maps-services-js": "^3.4.0",
|
|
49
|
-
"@
|
|
50
|
-
"@
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"@types/
|
|
60
|
-
"@types/
|
|
61
|
-
"@types/
|
|
62
|
-
"@
|
|
63
|
-
"@typescript-eslint/
|
|
64
|
-
"eslint": "^
|
|
65
|
-
"eslint
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
|
|
73
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@cablate/mcp-google-map",
|
|
3
|
+
"version": "0.0.19",
|
|
4
|
+
"description": "Google Maps MCP server with streamable HTTP transport support for location services, geocoding, and navigation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-google-map": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"dist/**/*.map",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup --dts",
|
|
17
|
+
"start": "node dist/cli.js",
|
|
18
|
+
"dev": "cross-env NODE_ENV=development tsup --watch",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18.0.0"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"google",
|
|
26
|
+
"map",
|
|
27
|
+
"api",
|
|
28
|
+
"llm",
|
|
29
|
+
"typescript",
|
|
30
|
+
"mcp",
|
|
31
|
+
"server",
|
|
32
|
+
"streamable",
|
|
33
|
+
"location",
|
|
34
|
+
"geocoding",
|
|
35
|
+
"navigation"
|
|
36
|
+
],
|
|
37
|
+
"author": "CabLate",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"homepage": "https://github.com/cablate/mcp-google-map#readme",
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/cablate/mcp-google-map.git"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/cablate/mcp-google-map/issues"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@googlemaps/google-maps-services-js": "^3.4.0",
|
|
49
|
+
"@googlemaps/places": "^2.1.0",
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.11.0",
|
|
51
|
+
"@types/yargs": "^17.0.33",
|
|
52
|
+
"cross-env": "^7.0.3",
|
|
53
|
+
"dotenv": "^16.4.7",
|
|
54
|
+
"express": "^4.21.2",
|
|
55
|
+
"yargs": "^17.7.2",
|
|
56
|
+
"zod": "^3.24.2"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/express": "^5.0.0",
|
|
60
|
+
"@types/jest": "^29.5.14",
|
|
61
|
+
"@types/js-yaml": "^4.0.9",
|
|
62
|
+
"@types/node": "^20.17.0",
|
|
63
|
+
"@typescript-eslint/eslint-plugin": "^8.24.0",
|
|
64
|
+
"@typescript-eslint/parser": "^8.24.0",
|
|
65
|
+
"eslint": "^9.20.1",
|
|
66
|
+
"eslint-config-prettier": "^10.0.1",
|
|
67
|
+
"jest": "^29.7.0",
|
|
68
|
+
"prettier": "^3.5.0",
|
|
69
|
+
"ts-jest": "^29.2.5",
|
|
70
|
+
"tsup": "^8.4.0",
|
|
71
|
+
"tsx": "^4.19.2",
|
|
72
|
+
"typescript": "^5.7.3"
|
|
73
|
+
}
|
|
74
|
+
}
|
package/dist/chunk-W2DM2HDK.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var r={log:(...o)=>{console.error("[INFO]",...o)},error:(...o)=>{console.error("[ERROR]",...o)}};export{r as a};
|