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/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  Logger,
3
3
  NewPlacesService,
4
4
  PlacesSearcher
5
- } from "./chunk-K27FX5QH.js";
5
+ } from "./chunk-NAUIQEK4.js";
6
6
  export {
7
7
  Logger,
8
8
  NewPlacesService,
@@ -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 GeoScout; unica API di ricerca locali usata dal server |
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
- La chiave può essere fornita in tre modi (priorità decrescente):
20
+ The API key can be supplied as follows (decreasing per-request priority on the HTTP transport):
21
21
 
22
- 1. flag CLI `--apikey "AIza..."`
23
- 2. header HTTP `X-Goog-Api-Key` (o `x-api-key`) sul trasporto HTTP — **per richiesta**, utile in multi-sessione
24
- 3. variabile d'ambiente `GOOGLE_MAPS_API_KEY` (o riga in `.env`)
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` | `0.0.0.0` | Interfaccia di bind HTTP (usare `127.0.0.1` per esposizione solo locale) |
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
- Ogni sessione MCP (`mcp-session-id`) può ricevere una API key propria via header `X-Goog-Api-Key`: le chiamate dei tool usano la chiave della sessione, non quella globale.
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 # server stdio
98
- node dist/cli.js --port 3000 --host 127.0.0.1 # server HTTP
99
- node dist/cli.js exec search-places --query "pizzeria Torino" # chiama un tool da terminale
100
- node dist/cli.js doctor --live --apikey "AIza..." # diagnostica ambiente + chiamate reali
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 — vedi [GEOSCOUT.md](GEOSCOUT.md).
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.4.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
- "prepublishOnly": "npm run check:publish-version && npm run typecheck && npm test && npm run build"
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": "^2.1.0",
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.