places-search
Find nearby businesses, landmarks, and points of interest using text search queries with location-based filtering.
Instructions
Search for places using text query
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| location | No | Bias results around this location (e.g., 'lat,lng') | |
| query | Yes | The search query | |
| radius | No | Search radius in meters |
Input Schema (JSON Schema)
{
"properties": {
"location": {
"description": "Bias results around this location (e.g., 'lat,lng')",
"type": "string"
},
"query": {
"description": "The search query",
"type": "string"
},
"radius": {
"description": "Search radius in meters",
"type": "number"
}
},
"required": [
"query"
],
"type": "object"
}
Implementation Reference
- src/maps.ts:261-329 (handler)The handler function that performs the places search using Google Maps Text Search API, processes up to 5 results, formats them with formatPlacesToMarkdown, and returns markdown content or error.export async function placesSearch( params: z.infer<typeof placesSearchSchema>, extra?: any ) { const apiKey = process.env.GOOGLE_MAPS_API_KEY; if (!apiKey) { throw new Error("GOOGLE_MAPS_API_KEY is required"); } try { const requestParams: any = { query: params.query, key: apiKey, }; if (params.location) { requestParams.location = params.location; } if (params.radius) { requestParams.radius = params.radius; } const response = await googleMapsClient.textSearch({ params: requestParams, }); const results = response.data.results; if (results.length === 0) { return { content: [ { type: "text" as const, text: "No places found for the given query.", }, ], }; } const places = results.slice(0, 5).map((place) => ({ name: place.name, formatted_address: place.formatted_address, latitude: place.geometry?.location.lat, longitude: place.geometry?.location.lng, place_id: place.place_id, rating: place.rating, types: place.types, })); return { content: [ { type: "text" as const, text: formatPlacesToMarkdown(places), }, ], }; } catch (error) { return { content: [ { type: "text" as const, text: `Error searching places: ${ error instanceof Error ? error.message : String(error) }`, }, ], }; } }
- src/maps.ts:114-121 (schema)Zod schema defining input parameters for the places-search tool: query (required), optional location bias and radius.export const placesSearchSchema = z.object({ query: z.string().describe("The search query"), location: z .string() .optional() .describe("Bias results around this location (e.g., 'lat,lng')"), radius: z.number().optional().describe("Search radius in meters"), });
- src/index.ts:80-87 (registration)Registration of the 'places-search' tool on the MCP server, linking to the handler and schema from maps.ts.server.tool( "places-search", "Search for places using text query", placesSearchSchema.shape, async (params) => { return await placesSearch(params); } );
- src/maps.ts:16-38 (helper)Helper function to format the list of places into a structured markdown output used by the handler.function formatPlacesToMarkdown(places: any[]): string { if (!places.length) return "No places found."; let markdown = `# Places Search Results (${places.length})\n\n`; places.forEach((place, index) => { markdown += `## ${index + 1}. ${place.name}\n`; markdown += `Address: ${place.formatted_address} \n`; if (place.rating) { markdown += `Rating: ${place.rating}β \n`; } if (place.latitude && place.longitude) { markdown += `Location: ${place.latitude}, ${place.longitude} \n`; markdown += `Maps: [View](https://maps.google.com/?q=${place.latitude},${place.longitude}) \n`; } if (place.place_id) { markdown += `Place ID: \`${place.place_id}\` \n`; } markdown += `\n`; }); return markdown; }