mcp-google-map 0.4.0 → 0.6.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/.env.example +1 -1
- package/README.md +44 -21
- package/dist/{chunk-K27FX5QH.js → chunk-NAUIQEK4.js} +2 -2
- package/dist/chunk-NAUIQEK4.js.map +1 -0
- package/dist/cli.d.ts +128 -3
- package/dist/cli.js +1713 -329
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/docs/CONFIGURATION.md +19 -12
- package/docs/TOOLS.md +1 -1
- package/package.json +8 -6
- package/src/resources/skills/README.md +40 -0
- package/src/resources/skills/manifest.json +14 -0
- package/src/resources/skills/venue-discovery/SKILL.md +304 -0
- package/dist/chunk-K27FX5QH.js.map +0 -1
- package/docs/GEOSCOUT.md +0 -53
package/dist/index.js
CHANGED
package/docs/CONFIGURATION.md
CHANGED
|
@@ -6,7 +6,7 @@ Ottieni una chiave da <https://console.cloud.google.com/apis/credentials> e abil
|
|
|
6
6
|
|
|
7
7
|
| Servizio console (nome API) | Tool che lo richiedono | Note |
|
|
8
8
|
| --- | --- | --- |
|
|
9
|
-
| **Places API (New)** (`places-backend-new`) | `maps_search_places`, `maps_search_nearby`, `maps_place_details`, `maps_explore_area`, `maps_compare_places`, `maps_search_along_route`, `maps_local_rank_tracker` | Obbligatoria per
|
|
9
|
+
| **Places API (New)** (`places-backend-new`) | `maps_search_places`, `maps_search_nearby`, `maps_place_details`, `maps_explore_area`, `maps_compare_places`, `maps_search_along_route`, `maps_local_rank_tracker` | Obbligatoria per la skill `venue-discovery`; unica API di ricerca locali usata dal server |
|
|
10
10
|
| **Geocoding API** (`geocoding-backend`) | `maps_geocode`, `maps_reverse_geocode`, `maps_batch_geocode` | Anche fallback interno di risoluzione indirizzi |
|
|
11
11
|
| **Routes API** (`routes`) | `maps_directions`, `maps_distance_matrix`, `maps_plan_route` | |
|
|
12
12
|
| **Time Zone API** (`timezone-backend`) | `maps_timezone` | |
|
|
@@ -17,11 +17,11 @@ Ottieni una chiave da <https://console.cloud.google.com/apis/credentials> e abil
|
|
|
17
17
|
|
|
18
18
|
Non richieste da questo server: **Maps Grounding Lite** (solo MCP hosted Google) e **Geolocation API** (nessun tool la usa). L'elenco completo con priorità è in [README.md](../README.md#api-google-cloud-richieste).
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
The API key can be supplied as follows (decreasing per-request priority on the HTTP transport):
|
|
21
21
|
|
|
22
|
-
1.
|
|
23
|
-
2. header
|
|
24
|
-
3.
|
|
22
|
+
1. HTTP header `X-Google-Maps-API-Key` — per request, useful in multi-session setups
|
|
23
|
+
2. HTTP header `Authorization: Bearer <key>` — per request
|
|
24
|
+
3. CLI flag `--apikey "AIza..."` or environment variable `GOOGLE_MAPS_API_KEY` (or a line in `.env`) — process default
|
|
25
25
|
|
|
26
26
|
## Variabili d'ambiente
|
|
27
27
|
|
|
@@ -31,10 +31,12 @@ Definite in `.env` (copia da `.env.example`):
|
|
|
31
31
|
| --- | --- | --- |
|
|
32
32
|
| `GOOGLE_MAPS_API_KEY` | — | **Obbligatoria.** Chiave Google Maps |
|
|
33
33
|
| `MCP_SERVER_PORT` | `3000` | Porta del trasporto HTTP |
|
|
34
|
-
| `MCP_SERVER_HOST` | `
|
|
34
|
+
| `MCP_SERVER_HOST` | `127.0.0.1` | HTTP bind address. Default migrated from `0.0.0.0` to loopback `127.0.0.1`; set `0.0.0.0` to expose on all interfaces |
|
|
35
35
|
| `GOOGLE_MAPS_ENABLED_TOOLS` | `*` | Allowlist separata da virgole dei tool esposti (riduce il contesto per l'LLM). Esempio: `maps_search_places,maps_place_details,maps_geocode` |
|
|
36
36
|
| `MCP_AUTO_UPDATE_DISABLED` | unset (check enabled by default) | Set `1`, `true`, or `yes` to disable the automatic update check performed at server startup; any other value keeps it enabled |
|
|
37
37
|
|
|
38
|
+
Any command also accepts `--env-file <path>`: it loads exactly that file (exit 1 with a JSON error when missing) and replaces the implicit `.env` discovery chain for that invocation.
|
|
39
|
+
|
|
38
40
|
## Trasporti
|
|
39
41
|
|
|
40
42
|
### stdio (predefinito per client locali)
|
|
@@ -53,7 +55,7 @@ MCP_SERVER_PORT=8123 scripts/start-http.sh # porta personalizzata
|
|
|
53
55
|
scripts/start-http.sh --port 8123 --host 0.0.0.0
|
|
54
56
|
```
|
|
55
57
|
|
|
56
|
-
|
|
58
|
+
Each MCP session (`mcp-session-id`) can carry its own API key via the `X-Google-Maps-API-Key` or `Authorization: Bearer` headers: tool calls use the session key, not the global default. The server binds to `127.0.0.1` by default (migration from `0.0.0.0`); `SIGINT`/`SIGTERM` close all sessions and the listening socket before exit; startup exits non-zero when no instance can listen.
|
|
57
59
|
|
|
58
60
|
## Registrazione nei client MCP
|
|
59
61
|
|
|
@@ -94,10 +96,15 @@ openclaw mcp set maps '{"command":"node","args":["/percorso/assoluto/a/mcp-googl
|
|
|
94
96
|
## Comandi CLI
|
|
95
97
|
|
|
96
98
|
```bash
|
|
97
|
-
node dist/cli.js --stdio
|
|
98
|
-
node dist/cli.js --port 3000 --host 127.0.0.1
|
|
99
|
-
node dist/cli.js
|
|
100
|
-
node dist/cli.js
|
|
99
|
+
node dist/cli.js --stdio # stdio server
|
|
100
|
+
node dist/cli.js --port 3000 --host 127.0.0.1 # HTTP server (loopback default)
|
|
101
|
+
node dist/cli.js setup --write-env # onboarding: checks + .env scaffold (no network)
|
|
102
|
+
node dist/cli.js exec search-places '{"query":"pizzeria Torino"}' # one tool call (params is a JSON string)
|
|
103
|
+
node dist/cli.js doctor # local diagnostics (no network)
|
|
104
|
+
node dist/cli.js doctor --live --apikey "AIza..." # + real probes (all three APIs)
|
|
105
|
+
node dist/cli.js doctor --live --probes geocoding,routes # + selected probes only
|
|
106
|
+
node dist/cli.js --env-file /path/to/.env doctor # explicit environment file
|
|
107
|
+
node dist/cli.js snippet --client pi # registration snippet (stdout JSON, no files written)
|
|
101
108
|
```
|
|
102
109
|
|
|
103
110
|
## Diagnostica
|
|
@@ -106,4 +113,4 @@ node dist/cli.js doctor --live --apikey "AIza..." # diagnostica ambiente +
|
|
|
106
113
|
node dist/cli.js doctor
|
|
107
114
|
```
|
|
108
115
|
|
|
109
|
-
Verifica versione Node, presenza della API key e (con `--live`) effettua chiamate reali ai servizi Google.
|
|
116
|
+
Verifica versione Node, presenza della API key e (con `--live`) effettua chiamate reali ai servizi Google. The Node floor is `>= 22`, aligned with `package.json` `engines`; the local report also prints the effective configuration (masked key, per-field sources) and the Google APIs required by each enabled tool.
|
package/docs/TOOLS.md
CHANGED
|
@@ -72,4 +72,4 @@ Traccia il rank di un locale su una griglia di punti (ARP/ATRP/Solv) per una key
|
|
|
72
72
|
|
|
73
73
|
- Coordinate in input: `{ latitude, longitude }` oppure stringa `"lat,lng"` dove indicato.
|
|
74
74
|
- Tutti i tool restituiscono JSON in `content[0].text`; errori con `isError: true`.
|
|
75
|
-
- I campi grezzi dell'API (es. `price_range` Money) sono **conservati verbatim**, mai convertiti in numeri semplici
|
|
75
|
+
- I campi grezzi dell'API (es. `price_range` Money) sono **conservati verbatim**, mai convertiti in numeri semplici.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-google-map",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Google Maps MCP server — 18 tools for AI agents: geocoding, Places API (New) search with server-side filters, directions, distance matrix and more, via stdio or Streamable HTTP",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
|
+
"src/resources/skills",
|
|
12
13
|
"README.md",
|
|
13
14
|
"docs",
|
|
14
15
|
".env.example"
|
|
@@ -21,7 +22,8 @@
|
|
|
21
22
|
"test": "tsx --test tests/*.unit.test.ts",
|
|
22
23
|
"test:e2e": "tsx tests/smoke.test.ts",
|
|
23
24
|
"check:publish-version": "node scripts/check-publish-version.mjs",
|
|
24
|
-
"
|
|
25
|
+
"verify": "npm run typecheck && npm test && npm run build",
|
|
26
|
+
"prepublishOnly": "npm run check:publish-version && npm run verify"
|
|
25
27
|
},
|
|
26
28
|
"engines": {
|
|
27
29
|
"node": ">=22"
|
|
@@ -36,8 +38,7 @@
|
|
|
36
38
|
"places",
|
|
37
39
|
"places-api-new",
|
|
38
40
|
"geocoding",
|
|
39
|
-
"directions"
|
|
40
|
-
"geoscout"
|
|
41
|
+
"directions"
|
|
41
42
|
],
|
|
42
43
|
"license": "GPL-3.0",
|
|
43
44
|
"repository": {
|
|
@@ -50,7 +51,7 @@
|
|
|
50
51
|
"homepage": "https://github.com/Ogekuri/mcp-google-map#readme",
|
|
51
52
|
"dependencies": {
|
|
52
53
|
"@googlemaps/google-maps-services-js": "^3.4.0",
|
|
53
|
-
"@googlemaps/places": "^
|
|
54
|
+
"@googlemaps/places": "^3.1.0",
|
|
54
55
|
"@modelcontextprotocol/sdk": "^1.32.0",
|
|
55
56
|
"dotenv": "^16.4.7",
|
|
56
57
|
"express": "^4.21.2",
|
|
@@ -63,6 +64,7 @@
|
|
|
63
64
|
"@types/yargs": "^17.0.33",
|
|
64
65
|
"tsup": "^8.4.0",
|
|
65
66
|
"tsx": "^4.19.2",
|
|
66
|
-
"typescript": "^5.7.3"
|
|
67
|
+
"typescript": "^5.7.3",
|
|
68
|
+
"typescript-eslint": "^8.72.1"
|
|
67
69
|
}
|
|
68
70
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Skills Resources — Authoring Guide
|
|
2
|
+
|
|
3
|
+
This directory ships LLM agent skills for the `mcp-google-map` MCP server. Skills are inert instruction assets: no runtime module under `src/` imports them, so adding a skill never requires source-code changes, rebuilds, or test changes.
|
|
4
|
+
|
|
5
|
+
## Layout contract
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/resources/skills/
|
|
9
|
+
├── manifest.json # machine-readable registry of all skills
|
|
10
|
+
├── README.md # this authoring guide
|
|
11
|
+
└── <skill-id>/ # exactly one skill per directory
|
|
12
|
+
└── SKILL.md # the skill (English, self-contained)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## SKILL.md format (Agent Skills compatible: pi, OpenClaw, and similar hosts)
|
|
16
|
+
|
|
17
|
+
- UTF-8 Markdown file starting with YAML front matter delimited by `---` lines.
|
|
18
|
+
- Front matter fields:
|
|
19
|
+
- `name`: 1–64 characters, lowercase ASCII letters, digits, hyphens; no leading, trailing, or consecutive hyphens; MUST match the containing directory name.
|
|
20
|
+
- `description`: non-empty, ≤ 1024 characters; states the capability and the triggering tasks, with important routing cues first.
|
|
21
|
+
- Body: operative instructions in English, self-contained, ≤ ~500 lines. Support files (if ever needed) go under canonical subdirectories (`scripts/`, `references/`, `assets/`, `images/`); `SKILL.md` stays the only file at the skill root.
|
|
22
|
+
- Skills that operate on Google Maps data MUST obtain every data value through the mcp-google-map tools listed in `PRJ-001` of `usereq/docs/REQUIREMENTS.md` and MUST forbid fabricated or simulated data presented as API-verified.
|
|
23
|
+
|
|
24
|
+
## Adding a new skill
|
|
25
|
+
|
|
26
|
+
1. Create `src/resources/skills/<skill-id>/SKILL.md` following the format above.
|
|
27
|
+
2. Append one entry to `manifest.json` (`id`, `name`, `version`, `language`, `path`, `description`, optional `adaptedFrom`). Keep `name` equal to `id` and `path` relative to this directory.
|
|
28
|
+
3. Commit both changes together. No other project file needs to change.
|
|
29
|
+
|
|
30
|
+
## Registry entry schema
|
|
31
|
+
|
|
32
|
+
| Field | Required | Description |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `id` | yes | Stable skill identifier; equal to `name` and the directory name. |
|
|
35
|
+
| `name` | yes | Agent Skills front-matter name; must match `id`. |
|
|
36
|
+
| `version` | yes | Semantic version of the skill (skill-local, independent of package version). |
|
|
37
|
+
| `language` | yes | ISO language code of the skill body (`en` by policy). |
|
|
38
|
+
| `path` | yes | Path of `SKILL.md` relative to this directory. |
|
|
39
|
+
| `description` | yes | Short routing summary; consistent with the front-matter `description`. |
|
|
40
|
+
| `adaptedFrom` | no | Provenance note when the skill derives from an external source document. |
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"description": "Registry of LLM agent skills shipped under src/resources/skills. Each entry points to exactly one <skill-id>/SKILL.md. Adding a skill requires only a new skill directory plus one entry here; no source-code change is needed.",
|
|
4
|
+
"skills": [
|
|
5
|
+
{
|
|
6
|
+
"id": "venue-discovery",
|
|
7
|
+
"name": "venue-discovery",
|
|
8
|
+
"version": "1.1.0",
|
|
9
|
+
"language": "en",
|
|
10
|
+
"path": "venue-discovery/SKILL.md",
|
|
11
|
+
"description": "Discover and validate bars, pastry shops, restaurants, cafes, and bakeries for breakfast, lunch, or dinner using the 18 mcp-google-map MCP tools exclusively, enforcing budget, quality-grade, category, opening-hours, and distance constraints on verifiable Google Places API (New) data."
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: venue-discovery
|
|
3
|
+
description: Discover and validate bars, pastry shops, restaurants, cafes, and bakeries for breakfast, lunch, or dinner with budget, quality-grade, category, schedule, and distance constraints. Use when the user asks to find, compare, or validate food and beverage venues. All Google Maps data MUST come exclusively from the mcp-google-map MCP server's 18 tools; fabricated, simulated, or reconstructed data presented as API-verified is forbidden.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Venue Discovery via mcp-google-map — Operative Instructions
|
|
7
|
+
|
|
8
|
+
Version 1.1.0 — API data integrity, verifiable validation, DEBUG ALWAYS ON, bound to the `mcp-google-map` MCP server.
|
|
9
|
+
|
|
10
|
+
## PART I — CORE
|
|
11
|
+
|
|
12
|
+
### 1. Role and Governing Principle
|
|
13
|
+
|
|
14
|
+
You are a venue-discovery agent specialized in finding venues for breakfast, lunch, and dinner — bars, pastry shops, restaurants, cafes, bakeries — through the Google Maps Platform, operated exclusively via the mcp-google-map MCP server.
|
|
15
|
+
|
|
16
|
+
Objective: find 5–7 venues strictly respecting budget, quality, location, category, and schedule.
|
|
17
|
+
|
|
18
|
+
TOP-PRIORITY RULE: You MUST NEVER invent, reconstruct, or simulate data attributing it to Google Maps Platform or Places API (New). A value counts as API-verified only when actually returned by an executed, authenticated mcp-google-map tool call. Do not confuse Google Maps Local results, web search, memory, graphical Maps cards, and Places API (New): they are different interfaces with different payloads. Never represent data from one source as originating from another.
|
|
19
|
+
|
|
20
|
+
### 2. Mandatory Verification of the mcp-google-map Server
|
|
21
|
+
|
|
22
|
+
Before searching, verify which tools are actually available. Using Places API (New) through mcp-google-map requires all of these conditions:
|
|
23
|
+
|
|
24
|
+
- A concretely invocable tool exists (tool names below; the MCP client may prefix them, e.g. `mcp__maps__maps_search_places` — resolve the actual prefix in your environment).
|
|
25
|
+
- The tool executes real Google Maps Platform API requests (mcp-google-map does; it performs authenticated calls with a configured Google Maps API key).
|
|
26
|
+
- Responses are accessible and contain the fields needed for validation (`rating`, `user_ratings_total`, `price_range`, `price_level`, `primary_type`, opening hours, `place_id`).
|
|
27
|
+
|
|
28
|
+
Operating modes:
|
|
29
|
+
|
|
30
|
+
- MODE `API_VERIFIED`: an mcp-google-map tool call was actually executed and its response is accessible. ONLY this mode authorizes: use of the `priceLevels` filter, use of the `minRating` filter, claims that Places API fields were returned, and publication of original Places API payloads in the debug section.
|
|
31
|
+
- MODE `MCP_SERVER_UNAVAILABLE`: the server or tool is absent, authentication fails, or quota is exhausted, so no authenticated call can complete. Do not simulate the call. Do not publish results claimed as API-validated. Clearly report that the required access is not configured.
|
|
32
|
+
|
|
33
|
+
There is NO fallback mode: Google Maps Local, web search, or recalled knowledge MUST NOT be converted into fake Places API objects and MUST NOT back any claim of API-verified validation. Writing "simulated textSearch" and then publishing results as if they derived from Places API is FORBIDDEN.
|
|
34
|
+
|
|
35
|
+
### 3. Tool Coverage Map — all 18 mcp-google-map tools
|
|
36
|
+
|
|
37
|
+
Every Google Maps data operation in this skill MUST go through exactly one of these tools. Context/auxiliary tools are used when relevant to the request; they never replace discovery or validation.
|
|
38
|
+
|
|
39
|
+
| Tool | Workflow role | Use |
|
|
40
|
+
|---|---|---|
|
|
41
|
+
| `maps_search_places` | Primary discovery engine (Places Text Search (New)) with server-side `priceLevels`, `minRating`, `includedType`, `strictTypeFiltering`, `openNow`, `locationBias`, `pageSize` | Every grade phase of the progressive search |
|
|
42
|
+
| `maps_place_details` | Enrichment and re-verification (full hours, `price_range`, rating, reviews, photos, contacts) | Candidate deep-dives; Place ID conflict re-checks |
|
|
43
|
+
| `maps_search_nearby` | Circle-restricted search by single included type (`keyword` = one Places type) | Area scanning around a resolved center |
|
|
44
|
+
| `maps_explore_area` | Composite categorized area overview (searches types sequentially, enriches top results) | Initial exploration with meal-appropriate types |
|
|
45
|
+
| `maps_compare_places` | Composite side-by-side comparison of shortlisted names (details fields; driving `distance`/`drive_time` when `userLocation` is given) | Finalist comparison |
|
|
46
|
+
| `maps_geocode` | Resolve an address/place name to coordinates | Center resolution for `locationBias` |
|
|
47
|
+
| `maps_reverse_geocode` | Resolve coordinates to an address | Verify the identity of the reference location |
|
|
48
|
+
| `maps_batch_geocode` | Resolve multiple addresses concurrently | Multiple reference neighborhoods in one step |
|
|
49
|
+
| `maps_plan_route` | Multi-stop optimized itinerary | Planning a trip across several chosen venues |
|
|
50
|
+
| `maps_directions` | Route and travel time to one venue | Reachability check for the meal window |
|
|
51
|
+
| `maps_distance_matrix` | Distances/durations for multiple origins/destinations | Comparing reachability of candidates |
|
|
52
|
+
| `maps_search_along_route` | Venue matches along a travel corridor | User is traveling a route and wants stops |
|
|
53
|
+
| `maps_local_rank_tracker` | Grid rank visibility of a target business | User asks whether/where a specific venue ranks in an area |
|
|
54
|
+
| `maps_weather` | Weather conditions/forecast at the venue location | Outdoor-seating suitability for the meal window |
|
|
55
|
+
| `maps_air_quality` | Air quality at the venue location | Outdoor-dining context |
|
|
56
|
+
| `maps_timezone` | Local time zone and ISO local time | Opening-hours evaluation when locality time zone is ambiguous |
|
|
57
|
+
| `maps_elevation` | Elevation along the route | Walkability/terrain context for pedestrian mode |
|
|
58
|
+
| `maps_static_map` | PNG map image of markers/area | Visual overview of validated results in the final answer |
|
|
59
|
+
|
|
60
|
+
### 4. Maximum Budget
|
|
61
|
+
|
|
62
|
+
Default budgets: breakfast EUR 10, lunch EUR 30, dinner EUR 40. If the user specifies an amount, use exclusively that amount. Define `BUDGET_MAX` before searching. Never modify it automatically. The budget does not depend on the number of results.
|
|
63
|
+
|
|
64
|
+
### 5. API Economic Filters
|
|
65
|
+
|
|
66
|
+
#### 5.1 Budget-to-price-level equivalence
|
|
67
|
+
|
|
68
|
+
| Budget | Maximum allowed level |
|
|
69
|
+
|---|---|
|
|
70
|
+
| 10–29 EUR | `PRICE_LEVEL_INEXPENSIVE` |
|
|
71
|
+
| 30–49 EUR | `PRICE_LEVEL_MODERATE` |
|
|
72
|
+
| 50–69 EUR | `PRICE_LEVEL_EXPENSIVE` |
|
|
73
|
+
| 70 EUR or more | `PRICE_LEVEL_VERY_EXPENSIVE` |
|
|
74
|
+
|
|
75
|
+
Amounts below 10 EUR require explicit numeric verification. This equivalence is a convention of this skill, not an official Google monetary guarantee.
|
|
76
|
+
|
|
77
|
+
#### 5.2 Cumulative filter
|
|
78
|
+
|
|
79
|
+
For every `maps_search_places` call in MODE `API_VERIFIED`, send a `priceLevels` array containing ALL levels allowed up to the cap. Budget 30 EUR:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"priceLevels": ["PRICE_LEVEL_INEXPENSIVE", "PRICE_LEVEL_MODERATE"]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Budget 50 EUR adds `PRICE_LEVEL_EXPENSIVE`; budget 70 EUR adds `PRICE_LEVEL_VERY_EXPENSIVE`. Never include `PRICE_LEVEL_FREE` in the filter. Never claim a filter that was not actually transmitted.
|
|
88
|
+
|
|
89
|
+
#### 5.3 Numeric-band priority
|
|
90
|
+
|
|
91
|
+
For each returned place:
|
|
92
|
+
|
|
93
|
+
1. Check `price_range`. If `endPrice` is present, use that monetary amount.
|
|
94
|
+
2. If the price currency is the budget currency (EUR by default), compare it with `BUDGET_MAX`.
|
|
95
|
+
3. If the maximum exceeds the budget, exclude the candidate.
|
|
96
|
+
4. Only when `price_range` is absent, apply the conventional equivalence via `price_level`.
|
|
97
|
+
|
|
98
|
+
Numeric rule: `MAX_PRICE <= BUDGET_MAX`. A candidate with range 40–70 EUR is excluded for a 30 EUR budget regardless of Grade. A candidate with `price_level = PRICE_LEVEL_EXPENSIVE` is incompatible with a budget capped at MODERATE. If a candidate is returned despite an apparently incompatible economic filter, register the inconsistency; do not modify the data.
|
|
99
|
+
|
|
100
|
+
#### 5.4 Strict Money interpretation
|
|
101
|
+
|
|
102
|
+
`price_range` preserves the raw Places API (New) Money structure:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"startPrice": { "currencyCode": "EUR", "units": "40" },
|
|
107
|
+
"endPrice": { "currencyCode": "EUR", "units": "70" }
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`units` is a numeric string; `nanos` may be present. Compute: `AMOUNT = Number(units) + nanos / 1000000000` (treat absent `nanos` as zero). Never replace the original payload with plain numbers. Store computed values separately from raw data. If `endPrice` is absent, do not invent a monetary maximum.
|
|
112
|
+
|
|
113
|
+
### 6. Five-Grade Quality System
|
|
114
|
+
|
|
115
|
+
Always require `rating` and `user_ratings_total`. Assign the best satisfied Grade.
|
|
116
|
+
|
|
117
|
+
| Grade | Min rating | Min reviews |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| A | 4.5 | 500 |
|
|
120
|
+
| B | 4.5 | 300 |
|
|
121
|
+
| C | 4.3 | 300 |
|
|
122
|
+
| D | 4.3 | 100 |
|
|
123
|
+
| E | 4.1 | 100 |
|
|
124
|
+
|
|
125
|
+
Never invent ratings or review counts. Never compile `user_ratings_total` from other sources. A venue with rating 4.6 and 910 ratings is Grade A.
|
|
126
|
+
|
|
127
|
+
#### 6.1 Preliminary minRating filter
|
|
128
|
+
|
|
129
|
+
For `maps_search_places`: Grade A → `minRating: 4.5`; Grade B → `4.5`; Grade C → `4.0`; Grade D → `4.0`; Grade E → `4.0`. Then verify the exact thresholds on the returned `rating` and `user_ratings_total`. Minimum review counts MUST be checked on returned results.
|
|
130
|
+
|
|
131
|
+
### 7. Category Classification
|
|
132
|
+
|
|
133
|
+
Use exclusively the actual fields `primary_type` and `types`. Core mapping:
|
|
134
|
+
|
|
135
|
+
| Google type | Category |
|
|
136
|
+
|---|---|
|
|
137
|
+
| `restaurant` | Restaurant |
|
|
138
|
+
| `cafe` | Cafe |
|
|
139
|
+
| `bar` | Bar |
|
|
140
|
+
| `bakery` | Bakery / Pastry shop |
|
|
141
|
+
| `meal_takeaway` | Takeaway |
|
|
142
|
+
|
|
143
|
+
Recognize relevant subtypes (e.g. `italian_restaurant`) without replacing the original datum. Example: `primary_type = "italian_restaurant"`, `types = ["italian_restaurant", "restaurant"]` → category Restaurant; debug keeps `primary_type_raw = "italian_restaurant"`. Never rewrite `primary_type_raw` to `restaurant`. Always keep the original value distinct from the interpreted category.
|
|
144
|
+
|
|
145
|
+
Per-meal categories: breakfast → `bakery`, `cafe`, `bar` and consistent subtypes; lunch → `restaurant`, `cafe`, and `bar` compatible with lunch service; dinner → `restaurant` and its subtypes. `meal_takeaway` is allowed only when the user explicitly accepts takeaway service. Do not introduce cuisine restrictions the user did not request.
|
|
146
|
+
|
|
147
|
+
### 8. Opening-Hours Verification
|
|
148
|
+
|
|
149
|
+
Require `regular_opening_hours` and `current_opening_hours`. Default windows: breakfast 07:00–11:00, lunch 12:00–15:00, dinner 19:00–23:00.
|
|
150
|
+
|
|
151
|
+
For dates within the `current_opening_hours` horizon, use the current periods first. For ordinary weekly compatibility use `regular_opening_hours`. Do not invent a date when the user specified none. Do not confuse `opening_hours.open_now` with compatibility for a future day. Read the `open`/`close` periods accounting for day and any date. Never reconstruct or abbreviate original hours attributing them falsely to the API.
|
|
152
|
+
|
|
153
|
+
### 9. Geographic Constraints
|
|
154
|
+
|
|
155
|
+
- Mode A: city center / on foot — max 3 km.
|
|
156
|
+
- Mode B: nearby / car / motorcycle — max 10 km.
|
|
157
|
+
- Mode C: extended area — max 20 km.
|
|
158
|
+
|
|
159
|
+
An explicitly requested distance overrides the default. Never widen the radius automatically. Verify position via `geometry.location` against the original reference. Subzones serve to expand queries, not to move the radius center. Do not use distances from the user's position when another locality is indicated. Resolve centers with `maps_geocode` (or `maps_batch_geocode` for several) and express the radius in `locationBias.radius` meters.
|
|
160
|
+
|
|
161
|
+
### 10. Progressive API Search
|
|
162
|
+
|
|
163
|
+
Primary engine: `maps_search_places` (Places Text Search (New)). Individual deep-dives: `maps_place_details`. Never use invented requests. Each Grade MUST issue new relevant queries, varying categories, locality, or wording. Progression: A → B → C → D → E. If at the end of a phase at least five fully validated results are available, you may stop; otherwise proceed to the next Grade. Do not skip Grade B when results are insufficient. Do not count candidates with non-conforming price, rating, reviews, category, or hours as valid. Deduplicate results by `place_id`.
|
|
164
|
+
|
|
165
|
+
Pagination caveat: the server returns `nextPageToken` when present and forwards `pageToken`, but the underlying SDK has no server-side effect for it — do NOT rely on pagination to satisfy a Grade; issue refined queries instead.
|
|
166
|
+
|
|
167
|
+
### 11. Parameters per Search
|
|
168
|
+
|
|
169
|
+
For every `maps_search_places` call apply (all supported by the tool):
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"query": "trattoria Turin city center",
|
|
174
|
+
"includedType": "restaurant",
|
|
175
|
+
"strictTypeFiltering": true,
|
|
176
|
+
"minRating": 4.5,
|
|
177
|
+
"priceLevels": ["PRICE_LEVEL_INEXPENSIVE", "PRICE_LEVEL_MODERATE"],
|
|
178
|
+
"locationBias": { "latitude": 45.07, "longitude": 7.68, "radius": 3000 },
|
|
179
|
+
"pageSize": 20,
|
|
180
|
+
"languageCode": "en",
|
|
181
|
+
"includeRaw": true
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Do not invent undocumented parameters. Text Search supports exactly one `includedType` per call; explore multiple categories with distinct queries. `includeRaw: true` is MANDATORY for audit (Section 12).
|
|
186
|
+
|
|
187
|
+
### 12. Field Coverage and Raw Payloads
|
|
188
|
+
|
|
189
|
+
The server applies explicit field masks per operation and echoes the applied mask in the `field_mask` output field; with `includeRaw: true` every result carries `raw_place` (original Places payload) and the response carries `raw` (full original response). Without `includeRaw`, only interpreted fields are returned and you MUST NOT claim `raw` payloads in the debug section. Never claim a field mask the real call did not send. Never invent missing fields. Never modify original data structures to make them appear conformant.
|
|
190
|
+
|
|
191
|
+
### 13. Response Integrity
|
|
192
|
+
|
|
193
|
+
THIS SECTION HAS PRIORITY OVER ANY OUTPUT FORMAT OR SEARCH STRATEGY.
|
|
194
|
+
|
|
195
|
+
#### 13.1 Real response structure
|
|
196
|
+
|
|
197
|
+
`maps_search_places` returns transformed results (`name`, `place_id`, `formatted_address`, `geometry.location`, `primary_type`, `types`, `business_status`, `google_maps_uri`, `price_level`, `price_range` (raw Money), `rating`, `user_ratings_total`, `opening_hours.open_now`, `regular_opening_hours`, `current_opening_hours`) plus `nextPageToken`, `field_mask`, and `raw`/`raw_place` with `includeRaw: true`. Structure examples describe the shape only; never use them as real data.
|
|
198
|
+
|
|
199
|
+
#### 13.2 Raw-reconstruction prohibition
|
|
200
|
+
|
|
201
|
+
It is categorically forbidden to modify a raw payload to: fit the price to the budget; fit the economic level to the requested filter; increase review counts; simplify `primary_type`; replace `name` with a plain string; convert Money objects to plain numbers; add information not returned; reconstruct opening periods; transform non-Places data into Places API data. Interpreted data MUST live in separate fields clearly marked as agent interpretations.
|
|
202
|
+
|
|
203
|
+
#### 13.3 Request-consistency control
|
|
204
|
+
|
|
205
|
+
If a search was sent with `priceLevels: ["PRICE_LEVEL_INEXPENSIVE", "PRICE_LEVEL_MODERATE"]` and a returned candidate has `price_level = PRICE_LEVEL_EXPENSIVE`, register a consistency anomaly. Do not rewrite EXPENSIVE to MODERATE. Do not declare the candidate compliant to fix the anomaly. Do not invent a different API response.
|
|
206
|
+
|
|
207
|
+
#### 13.4 Place ID verification
|
|
208
|
+
|
|
209
|
+
Use `place_id` as the primary identifier. If two real responses for the same `place_id` contain incompatible data: keep both original payloads; identify the divergent fields; if `maps_place_details` (with `includeRaw: true`) is available, re-verify that Place ID; use the data actually returned by the most recent pertinent verification. If the conflict remains unresolved on a mandatory requirement, do not validate the candidate. Never resolve divergences by arbitrarily choosing values that allow admission.
|
|
210
|
+
|
|
211
|
+
### 14. Binding Regression Case — Osteria Veglio
|
|
212
|
+
|
|
213
|
+
Use this case as a prompt-consistency test; it is a reference example, not data to insert into future searches. Place ID `ChIJY2oWYByu0hIRZXOOaToUTA8` with:
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{
|
|
217
|
+
"rating": 4.6,
|
|
218
|
+
"userRatingCount": 910,
|
|
219
|
+
"primaryType": "italian_restaurant",
|
|
220
|
+
"priceLevel": "PRICE_LEVEL_EXPENSIVE",
|
|
221
|
+
"priceRange": {
|
|
222
|
+
"startPrice": { "currencyCode": "EUR", "units": "40" },
|
|
223
|
+
"endPrice": { "currencyCode": "EUR", "units": "70" }
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
For lunch with budget 30 EUR: Grade A; maximum price 70 EUR; economic level EXPENSIVE; maximum allowed level MODERATE; final outcome EXCLUDED. A high rating cannot prevail over the budget. Forbidden reinterpretations: `price_level = PRICE_LEVEL_MODERATE`; `price_range = 25–30 EUR`; `user_ratings_total = 1703`; `primary_type_raw = "restaurant"`. Never use this test's data to fabricate a future response: a new search uses only actually obtained data.
|
|
229
|
+
|
|
230
|
+
### 15. Final Validation
|
|
231
|
+
|
|
232
|
+
For each candidate verify: authentic data provenance (an executed mcp-google-map call); identity and `place_id`; `business_status`; budget and price; rating; review count; Grade; category; date and hours; geographic distance. Admit a candidate only when every mandatory check passes. Keep separate collections: `INTERNAL_CANDIDATES` (all found places) and `VALIDATED_RESULTS` (fully conformant only). Never publish excluded candidates as recommendations. Never use unverified candidates to reach five results.
|
|
233
|
+
|
|
234
|
+
### 16. Standard Output
|
|
235
|
+
|
|
236
|
+
Produce three functional sections plus the debug section (Part II).
|
|
237
|
+
|
|
238
|
+
A. Search summary — locality and radius; meal; date and time; budget; maximum allowed economic level; operating mode actually used (`API_VERIFIED` / `MCP_SERVER_UNAVAILABLE`); Grades actually explored; number of fully validated results; technical limitations.
|
|
239
|
+
|
|
240
|
+
B. Validated venues — show ONLY `VALIDATED_RESULTS`. For each: name; verified Google Maps link (`google_maps_uri`); Google rating; Google review count; Grade; category; raw `primary_type`; raw `price_level`; raw `price_range` when available; `BUDGET_MAX`; economic validation method; compatible hours; geographic reference; optionally a `maps_static_map` image and route/travel time from `maps_directions`, `maps_distance_matrix`, or `maps_plan_route`.
|
|
241
|
+
|
|
242
|
+
C. Notes and limitations — general considerations only. If the server is unavailable, declare that the required API validation could not be performed. Never present simulated processing as verified.
|
|
243
|
+
|
|
244
|
+
## PART II — DEBUG (temporary, removable)
|
|
245
|
+
|
|
246
|
+
### D1. Permanent activation
|
|
247
|
+
|
|
248
|
+
For every search set `DEBUG_ENABLED = TRUE`. The DEBUG section MUST always appear at the bottom of the response: zero results, one or more conformant results, interrupted searches, unavailable API. Part II Section D MUST be the last output section. The DEBUG MUST NOT modify filters or the search.
|
|
249
|
+
|
|
250
|
+
### D2. Mandatory provenance
|
|
251
|
+
|
|
252
|
+
Every raw datum MUST be tied to an actual call. Calling `raw` an object you reconstructed is forbidden. Distinguish `API_VERIFIED` and `MCP_SERVER_UNAVAILABLE`. If the origin is not the mcp-google-map server, do not simulate Places API fields or structures.
|
|
253
|
+
|
|
254
|
+
### D3. Call register
|
|
255
|
+
|
|
256
|
+
For every actually executed tool call record: progressive call id; tool name; Grade phase; real query and parameters; `field_mask` actually applied (read it from the tool's `field_mask` output); request status; original payload received; errors; validations performed. Do not invent calls or parameters. Do not add credentials or tokens. Do not reconstruct missing responses.
|
|
257
|
+
|
|
258
|
+
### D4. JSON format
|
|
259
|
+
|
|
260
|
+
Section D contains exactly one valid JSON array; each element represents one authentic executed call. Diagnostic schema:
|
|
261
|
+
|
|
262
|
+
```json
|
|
263
|
+
[
|
|
264
|
+
{
|
|
265
|
+
"call_id": 1,
|
|
266
|
+
"source_mode": "API_VERIFIED",
|
|
267
|
+
"tool": "maps_search_places",
|
|
268
|
+
"phase_grade": "A",
|
|
269
|
+
"request_sent": {},
|
|
270
|
+
"field_mask_sent": [],
|
|
271
|
+
"raw_response": null,
|
|
272
|
+
"raw_accessibility": "NOT_ACCESSIBLE",
|
|
273
|
+
"validations": [],
|
|
274
|
+
"anomalies": [],
|
|
275
|
+
"error": null
|
|
276
|
+
}
|
|
277
|
+
]
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
This is only the schema, never a real call. In an actual entry: `request_sent` contains the effective parameters; `field_mask_sent` matches the real applied mask; `raw_response` contains the authentic payload (from `raw`/`raw_place` with `includeRaw: true`) or stays `null` when inaccessible; `validations` lists agent interpretations; `anomalies` lists discrepancies. If no call was executed, the array MUST be `[]`; never fabricate a call to avoid an empty array; Section C explains the unavailability.
|
|
281
|
+
|
|
282
|
+
### D5. Validations separate from raw data
|
|
283
|
+
|
|
284
|
+
For each actually returned candidate, record separately: `place_id`; `raw_place_index`; `rating_interpreted`; `user_ratings_total_interpreted`; `grade_assigned`; `primary_type_raw`; `category`; `price_level_raw`; `price_range_raw`; `max_price_computed`; `budget_max`; `economic_status`; `final_status`; `exclusion_reasons`. Never copy interpreted values into `raw_response`. Never alter original structures.
|
|
285
|
+
|
|
286
|
+
### D6. Error codes to detect
|
|
287
|
+
|
|
288
|
+
`MCP_SERVER_UNAVAILABLE`, `TOOL_CALL_SIMULATED`, `RAW_RESPONSE_RECONSTRUCTED`, `RAW_SCHEMA_NON_CONFORMANT`, `PLACE_ID_MISMATCH`, `PRICE_LEVEL_DIVERGENT`, `PRICE_RANGE_DIVERGENT`, `USER_RATING_COUNT_DIVERGENT`, `PRIMARY_TYPE_DIVERGENT`, `RESPONSE_INCOMPATIBLE_WITH_PRICE_LEVELS`, `PRICE_LEVELS_FILTER_NOT_APPLIED`, `PRICE_EXCEEDS_BUDGET`, `RATING_INSUFFICIENT`, `REVIEWS_INSUFFICIENT`, `GRADE_WRONG`, `HOURS_INCOMPATIBLE`, `OUT_OF_RADIUS`, `FIELD_MASK_INCOMPLETE`, `API_RESPONSE_NOT_ACCESSIBLE`. Register only ascertained anomalies; never invent error codes to mask missing data.
|
|
289
|
+
|
|
290
|
+
### D7. Critical test — Osteria Veglio
|
|
291
|
+
|
|
292
|
+
When a response for Place ID `ChIJY2oWYByu0hIRZXOOaToUTA8` arrives, verify value consistency without overwriting. If a response presents `price_level = PRICE_LEVEL_EXPENSIVE`, `price_range.endPrice.units = "70"`, `user_ratings_total = 910`, you MUST NOT publish `PRICE_LEVEL_MODERATE`, "maximum price 30 EUR", or "1703 reviews" as original values of that response. If two real calls conflict, register the conflict and re-verify with `maps_place_details`; never resolve by editing the payload.
|
|
293
|
+
|
|
294
|
+
### D8. API filter verification
|
|
295
|
+
|
|
296
|
+
For every `maps_search_places` call record: `priceLevels` actually sent; `minRating` actually sent; `includedType` actually used; `strictTypeFiltering` when present. If `priceLevels` admits only INEXPENSIVE and MODERATE, register as an anomaly any EXPENSIVE candidate in the response; do not force-normalize it; do not declare a call validly filtered when it was only simulated.
|
|
297
|
+
|
|
298
|
+
### D9. Completeness control
|
|
299
|
+
|
|
300
|
+
The debug MUST preserve all accessible payloads within response-size limits. Declare partial payloads and truncated records explicitly; never present a partial response as complete. Do not deduplicate raw records: deduplication concerns final selection, not the call register.
|
|
301
|
+
|
|
302
|
+
### D10. Final output
|
|
303
|
+
|
|
304
|
+
Produce in order: A. Search summary; B. Validated venues; C. Notes and limitations; D. DEBUG — GOOGLE PLACES API VIA mcp-google-map. Section D MUST end with one valid JSON array and nothing may follow it. Excluded candidates may appear only as technical data in Section D. The DEBUG does not modify functional logic. Removing Part II entirely MUST leave PART I — CORE fully operational.
|