@cablate/mcp-google-map 0.0.63 → 0.0.64
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/.codex-plugin/plugin.json +37 -0
- package/README.md +17 -8
- package/README.zh-TW.md +17 -8
- package/package.json +3 -1
- package/plugin.json +21 -0
- package/skills/google-maps/SKILL.md +0 -2
- package/skills/google-maps/SKILL.skill +0 -0
- package/skills/project-docs/SKILL.md +0 -66
- package/skills/project-docs/references/architecture.md +0 -137
- package/skills/project-docs/references/decisions.md +0 -149
- package/skills/project-docs/references/geo-domain-knowledge.md +0 -286
- package/skills/project-docs/references/google-maps-api-guide.md +0 -139
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-google-map",
|
|
3
|
+
"version": "0.0.64",
|
|
4
|
+
"description": "Use Google Maps-backed place search, routing, geocoding, weather, air quality, and geographic analysis through a standalone CLI.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "CabLate",
|
|
7
|
+
"url": "https://github.com/cablate"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/cablate/mcp-google-map",
|
|
10
|
+
"repository": "https://github.com/cablate/mcp-google-map",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"google-maps",
|
|
14
|
+
"places",
|
|
15
|
+
"routing",
|
|
16
|
+
"geocoding",
|
|
17
|
+
"travel",
|
|
18
|
+
"agent-skill"
|
|
19
|
+
],
|
|
20
|
+
"skills": "./skills/",
|
|
21
|
+
"interface": {
|
|
22
|
+
"displayName": "Google Maps CLI",
|
|
23
|
+
"shortDescription": "Geospatial research and planning through a standalone CLI.",
|
|
24
|
+
"longDescription": "Guide an AI agent to use the @cablate/mcp-google-map exec CLI for place discovery, routing, geocoding, travel planning, local SEO, weather, air quality, and other geographic workflows. No MCP connection is required.",
|
|
25
|
+
"developerName": "CabLate",
|
|
26
|
+
"category": "Productivity",
|
|
27
|
+
"capabilities": [
|
|
28
|
+
"Read"
|
|
29
|
+
],
|
|
30
|
+
"websiteURL": "https://github.com/cablate/mcp-google-map",
|
|
31
|
+
"defaultPrompt": [
|
|
32
|
+
"Find and compare places for my trip.",
|
|
33
|
+
"Plan an efficient route between these stops.",
|
|
34
|
+
"Research what is near this location."
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
}
|
package/README.md
CHANGED
|
@@ -89,6 +89,17 @@ All tools are annotated with `readOnlyHint: true` and `destructiveHint: false`
|
|
|
89
89
|
|
|
90
90
|
## Installation
|
|
91
91
|
|
|
92
|
+
### Codex Plugin (Agent Skill, no MCP required)
|
|
93
|
+
|
|
94
|
+
Install the CabLate marketplace, then install the Skill-only plugin:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
codex plugin marketplace add cablate/mcp-google-map --ref main
|
|
98
|
+
codex plugin add mcp-google-map@cablate
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Set `GOOGLE_MAPS_API_KEY` in the environment available to Codex, make sure Node.js 18+ and `npx` are installed, then start a new conversation. The plugin teaches the agent to run `npx -y @cablate/mcp-google-map exec ...` directly. It does not register or start an MCP server; the MCP setup below remains an independent option.
|
|
102
|
+
|
|
92
103
|
### Method 1: stdio (Recommended for most clients)
|
|
93
104
|
|
|
94
105
|
Works with Claude Desktop, Cursor, VS Code, and any MCP client that supports stdio:
|
|
@@ -290,20 +301,18 @@ src/
|
|
|
290
301
|
tests/
|
|
291
302
|
└── smoke.test.ts # Smoke + E2E test suite
|
|
292
303
|
skills/
|
|
293
|
-
|
|
304
|
+
└── google-maps/ # Public Agent Skill — standalone CLI workflows
|
|
294
305
|
│ ├── SKILL.md # Tool map, recipes, invocation
|
|
295
306
|
│ ├── SKILL.skill # Importable archive of this Skill
|
|
296
307
|
│ └── references/
|
|
297
308
|
│ ├── tools-api.md # Tool parameters + scenario recipes
|
|
298
309
|
│ ├── travel-planning.md # Travel planning methodology
|
|
299
310
|
│ └── local-seo.md # Local SEO / Google Business Profile ranking analysis
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
├── geo-domain-knowledge.md # GIS fundamentals, Japan context
|
|
306
|
-
└── decisions.md # 10 ADRs (design decisions + rationale)
|
|
311
|
+
.agents/
|
|
312
|
+
├── plugins/marketplace.json # CabLate marketplace catalog
|
|
313
|
+
└── skills/project-docs/ # Maintainer-only development Skill
|
|
314
|
+
.codex-plugin/plugin.json # Codex compatibility manifest
|
|
315
|
+
plugin.json # Portable Agent Plugin manifest
|
|
307
316
|
```
|
|
308
317
|
|
|
309
318
|
## Tech Stack
|
package/README.zh-TW.md
CHANGED
|
@@ -89,6 +89,17 @@ npx @cablate/mcp-google-map --port 3000 --apikey "YOUR_API_KEY"
|
|
|
89
89
|
|
|
90
90
|
## 安裝
|
|
91
91
|
|
|
92
|
+
### Codex Plugin(Agent Skill,不需要 MCP)
|
|
93
|
+
|
|
94
|
+
先加入 CabLate marketplace,再安裝只包含 Skill 的 plugin:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
codex plugin marketplace add cablate/mcp-google-map --ref main
|
|
98
|
+
codex plugin add mcp-google-map@cablate
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
請在 Codex 可讀取的環境中設定 `GOOGLE_MAPS_API_KEY`,並確認已安裝 Node.js 18+ 與 `npx`,然後開啟新對話。Plugin 會教代理直接執行 `npx -y @cablate/mcp-google-map exec ...`;它不會註冊或啟動 MCP server。下方的 MCP 設定仍是另一種獨立使用方式。
|
|
102
|
+
|
|
92
103
|
### 方法一:stdio(大多數客戶端推薦)
|
|
93
104
|
|
|
94
105
|
適用於 Claude Desktop、Cursor、VS Code 及任何支援 stdio 的 MCP 客戶端:
|
|
@@ -287,20 +298,18 @@ src/
|
|
|
287
298
|
tests/
|
|
288
299
|
└── smoke.test.ts # Smoke + E2E 測試套件
|
|
289
300
|
skills/
|
|
290
|
-
|
|
301
|
+
└── google-maps/ # 公開 Agent Skill — 獨立 CLI 工作流程
|
|
291
302
|
│ ├── SKILL.md # 工具對照表、場景食譜、呼叫方式
|
|
292
303
|
│ ├── SKILL.skill # 可匯入的 Skill 封裝檔
|
|
293
304
|
│ └── references/
|
|
294
305
|
│ ├── tools-api.md # 工具參數 + 場景食譜
|
|
295
306
|
│ ├── travel-planning.md # 旅行規劃方法論
|
|
296
307
|
│ └── local-seo.md # Local SEO / Google 商家排名分析
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
├── geo-domain-knowledge.md # GIS 基礎、日本場景
|
|
303
|
-
└── decisions.md # 10 個 ADR(設計決策 + 理由)
|
|
308
|
+
.agents/
|
|
309
|
+
├── plugins/marketplace.json # CabLate marketplace 目錄
|
|
310
|
+
└── skills/project-docs/ # 僅供維護者使用的開發 Skill
|
|
311
|
+
.codex-plugin/plugin.json # Codex 相容 manifest
|
|
312
|
+
plugin.json # 可攜式 Agent Plugin manifest
|
|
304
313
|
```
|
|
305
314
|
|
|
306
315
|
## 技術棧
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cablate/mcp-google-map",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.64",
|
|
4
4
|
"mcpName": "io.github.cablate/google-map",
|
|
5
5
|
"description": "18 Google Maps tools for AI agents — geocode, search, directions, weather, air quality, local rank tracking, map images via MCP server or standalone CLI",
|
|
6
6
|
"type": "module",
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
"dist",
|
|
13
13
|
"dist/**/*.map",
|
|
14
14
|
"README.md",
|
|
15
|
+
"plugin.json",
|
|
16
|
+
".codex-plugin",
|
|
15
17
|
"skills",
|
|
16
18
|
"examples"
|
|
17
19
|
],
|
package/plugin.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
|
+
"name": "mcp-google-map",
|
|
4
|
+
"version": "0.0.64",
|
|
5
|
+
"description": "Use Google Maps-backed place search, routing, geocoding, weather, air quality, and geographic analysis through a standalone CLI.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "CabLate",
|
|
8
|
+
"url": "https://github.com/cablate"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/cablate/mcp-google-map",
|
|
11
|
+
"repository": "https://github.com/cablate/mcp-google-map",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"google-maps",
|
|
15
|
+
"places",
|
|
16
|
+
"routing",
|
|
17
|
+
"geocoding",
|
|
18
|
+
"travel",
|
|
19
|
+
"agent-skill"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -111,5 +111,3 @@ npx -y @cablate/mcp-google-map exec <tool> '<json_params>'
|
|
|
111
111
|
| `references/travel-planning.md` | Travel planning methodology — 6-layer model, Search Along Route, anti-patterns | When planning multi-day trips — **read before Recipe 1** |
|
|
112
112
|
| `references/local-seo.md` | Local SEO / Google Business Profile ranking analysis — competitor audit, keyword landscape, gap analysis | When analyzing business rankings, comparing competitors, or scouting locations |
|
|
113
113
|
| `references/content-attribution.md` | Google Maps content attribution, source links, AI disclosure, and storage limits | Before presenting reviews, photos, or AI summaries from Places |
|
|
114
|
-
|
|
115
|
-
> For **project development** knowledge (architecture, API guide, GIS domain, design decisions), see `skills/project-docs/SKILL.md`.
|
|
Binary file
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: mcp-google-map-project
|
|
3
|
-
description: Project knowledge for developing and maintaining @cablate/mcp-google-map. Architecture, Google Maps API guide, GIS domain knowledge, and design decisions. Read this skill to onboard onto the project or make informed development decisions.
|
|
4
|
-
version: 0.0.1
|
|
5
|
-
compatibility:
|
|
6
|
-
- claude-code
|
|
7
|
-
- cursor
|
|
8
|
-
- vscode-copilot
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# mcp-google-map — Project Knowledge
|
|
12
|
-
|
|
13
|
-
## Overview
|
|
14
|
-
|
|
15
|
-
This skill contains everything needed to develop, maintain, and extend the `@cablate/mcp-google-map` MCP server. Reading these files gives you full context on architecture, API specifics, domain knowledge, and the reasoning behind design decisions.
|
|
16
|
-
|
|
17
|
-
For the **agent skill** (how to USE the tools), see `skills/google-maps/SKILL.md`.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Quick Orientation
|
|
22
|
-
|
|
23
|
-
| Aspect | Summary |
|
|
24
|
-
|--------|---------|
|
|
25
|
-
| **What** | MCP server providing Google Maps tools for AI agents |
|
|
26
|
-
| **Stack** | TypeScript, Node.js, Express, MCP SDK, Zod |
|
|
27
|
-
| **Tools** | 18 tools (14 atomic + 4 composite) |
|
|
28
|
-
| **Transports** | stdio, Streamable HTTP, standalone exec CLI |
|
|
29
|
-
| **APIs** | Places API (New), Directions, Geocoding, Elevation, Timezone, Weather, Air Quality, Static Maps, Search Along Route |
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Reference Files
|
|
34
|
-
|
|
35
|
-
| File | Content | When to read |
|
|
36
|
-
|------|---------|--------------|
|
|
37
|
-
| `references/architecture.md` | System architecture, 3-layer design, transport modes, tool registration flow, 9-file checklist, code map | **Start here** when onboarding. Also read when adding new tools. |
|
|
38
|
-
| `references/google-maps-api-guide.md` | All Google Maps API endpoints used, pricing, coverage limits, rate limits, common gotchas, Places New vs Legacy | When debugging API errors, evaluating new APIs, or checking costs |
|
|
39
|
-
| `references/geo-domain-knowledge.md` | GIS fundamentals — coordinates, distance, geocoding, place types, spatial search, map projection, Japan-specific knowledge | When making tool design decisions that involve geographic concepts |
|
|
40
|
-
| `references/decisions.md` | 10 Architecture Decision Records (ADR) with context and rationale | When asking "why was X built this way?" or considering changes to existing design |
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## How to Add a New Tool
|
|
45
|
-
|
|
46
|
-
See `references/architecture.md` § "9-File Tool Change Checklist" for the complete procedure. Summary:
|
|
47
|
-
|
|
48
|
-
1. Create `src/tools/maps/<toolName>.ts` (NAME, DESCRIPTION, SCHEMA, ACTION)
|
|
49
|
-
2. Register in `src/config.ts`
|
|
50
|
-
3. Add exec case in `src/cli.ts`
|
|
51
|
-
4. Add to `tests/smoke.test.ts` (expectedTools + API call test)
|
|
52
|
-
5. Update `README.md` (count + table + exec list + project structure)
|
|
53
|
-
6. Update `skills/google-maps/SKILL.md` (Tool Map)
|
|
54
|
-
7. Update `skills/google-maps/references/tools-api.md` (params + chaining)
|
|
55
|
-
8. Check `server.json` and `package.json` descriptions
|
|
56
|
-
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
## When to Update This Skill
|
|
60
|
-
|
|
61
|
-
| Trigger | What to update |
|
|
62
|
-
|---------|----------------|
|
|
63
|
-
| Architecture change | `references/architecture.md` |
|
|
64
|
-
| New Google Maps API integrated | `references/google-maps-api-guide.md` |
|
|
65
|
-
| New design decision made | `references/decisions.md` (add ADR) |
|
|
66
|
-
| New GIS concept relevant to tools | `references/geo-domain-knowledge.md` |
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
# Architecture Reference
|
|
2
|
-
|
|
3
|
-
## System Architecture Overview
|
|
4
|
-
|
|
5
|
-
Three-layer architecture with a shared entry point:
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
CLI / HTTP / stdio
|
|
9
|
-
|
|
|
10
|
-
BaseMcpServer <- MCP protocol layer (tool registration, transport)
|
|
11
|
-
|
|
|
12
|
-
Tool ACTION() <- thin dispatch, calls PlacesSearcher
|
|
13
|
-
|
|
|
14
|
-
PlacesSearcher <- service facade (composition, filtering, response shaping)
|
|
15
|
-
/|\
|
|
16
|
-
GoogleMapsTools RoutesService NewPlacesService
|
|
17
|
-
(geocode/tz/elev) (Routes API REST) (Places API New)
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
| Layer | Files | Responsibility |
|
|
21
|
-
|---|---|---|
|
|
22
|
-
| Entry | `src/cli.ts` | Parse CLI args, select transport mode, instantiate server |
|
|
23
|
-
| Protocol | `src/core/BaseMcpServer.ts` | Register tools, handle MCP sessions, route HTTP/stdio |
|
|
24
|
-
| Tool | `src/tools/maps/*.ts` | Declare NAME, DESCRIPTION, SCHEMA, ACTION |
|
|
25
|
-
| Config | `src/config.ts` | Assemble ToolConfig[], attach MAPS_TOOL_ANNOTATIONS |
|
|
26
|
-
| Facade | `src/services/PlacesSearcher.ts` | Orchestrate multi-step / composite tools |
|
|
27
|
-
| API client (routes) | `src/services/RoutesService.ts` | Routes API REST client (directions, distance matrix, waypoint optimization) |
|
|
28
|
-
| API client (legacy) | `src/services/toolclass.ts` | Wrap `@googlemaps/google-maps-services-js` SDK (geocode, timezone, elevation) |
|
|
29
|
-
| API client (places) | `src/services/NewPlacesService.ts` | Wrap `@googlemaps/places` gRPC client |
|
|
30
|
-
| Auth | `src/utils/apiKeyManager.ts` | API key priority resolution |
|
|
31
|
-
| Context | `src/utils/requestContext.ts` | Per-request AsyncLocalStorage propagation |
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
## Transport Modes
|
|
36
|
-
|
|
37
|
-
| Mode | Entry | How to activate | Notes |
|
|
38
|
-
|---|---|---|---|
|
|
39
|
-
| **HTTP (Streamable)** | `cli.ts` → `BaseMcpServer.startHttpServer()` | default, or `--port` | Listens on `/mcp` (POST/GET/DELETE); sessions tracked by UUID header `mcp-session-id` |
|
|
40
|
-
| **stdio** | `cli.ts` → `BaseMcpServer.startStdio()` | `--stdio` flag | Used by Claude Desktop, Cursor; stdout reserved for JSON-RPC, all logs go to stderr |
|
|
41
|
-
| **exec CLI** | `cli.ts` → `execTool()` | `mcp-google-map exec <tool> '<json>'` | No MCP protocol; directly calls `PlacesSearcher` method and prints JSON to stdout; used for scripting/piping |
|
|
42
|
-
|
|
43
|
-
### HTTP Session Lifecycle
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
POST /mcp (no session-id, isInitializeRequest)
|
|
47
|
-
-> create StreamableHTTPServerTransport
|
|
48
|
-
-> create new McpServer, connect transport
|
|
49
|
-
-> store in sessions[uuid]
|
|
50
|
-
|
|
51
|
-
POST /mcp (mcp-session-id header)
|
|
52
|
-
-> reuse existing session context
|
|
53
|
-
-> update apiKey if header present
|
|
54
|
-
|
|
55
|
-
DELETE /mcp (mcp-session-id header)
|
|
56
|
-
-> terminate session, clean up transport
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
---
|
|
60
|
-
|
|
61
|
-
## Tool Registration Flow
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
src/tools/maps/weather.ts exports Weather.{NAME, DESCRIPTION, SCHEMA, ACTION}
|
|
65
|
-
|
|
|
66
|
-
src/config.ts builds ToolConfig[] array, attaches MAPS_TOOL_ANNOTATIONS
|
|
67
|
-
|
|
|
68
|
-
src/cli.ts passes config.tools[] to new BaseMcpServer(name, tools)
|
|
69
|
-
|
|
|
70
|
-
BaseMcpServer.createMcpServer() calls server.registerTool(name, {description, inputSchema, annotations}, action)
|
|
71
|
-
|
|
|
72
|
-
@modelcontextprotocol/sdk exposes tool to MCP client
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
`MAPS_TOOL_ANNOTATIONS` applied to all tools:
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
{ readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## API Key Management
|
|
84
|
-
|
|
85
|
-
Priority order (highest to lowest):
|
|
86
|
-
|
|
87
|
-
| Priority | Source | Header / Variable |
|
|
88
|
-
|---|---|---|
|
|
89
|
-
| 1 | HTTP request header | `X-Google-Maps-API-Key` |
|
|
90
|
-
| 2 | HTTP Authorization header | `Authorization: Bearer <key>` |
|
|
91
|
-
| 3 | Session-specific key | stored per `mcp-session-id` |
|
|
92
|
-
| 4 | CLI argument | `--apikey` / `-k` |
|
|
93
|
-
| 5 | Environment variable | `GOOGLE_MAPS_API_KEY` |
|
|
94
|
-
| 6 | `.env` file | loaded by `dotenv` at startup from `cwd` or package dir |
|
|
95
|
-
|
|
96
|
-
**Flow in HTTP mode**: `ApiKeyManager.getApiKey(req)` resolves key → stored in `SessionContext.apiKey` → propagated via `runWithContext()` (AsyncLocalStorage) → tool action reads from context or `process.env`.
|
|
97
|
-
|
|
98
|
-
**Flow in exec mode**: `--apikey` arg → directly passed to `new PlacesSearcher(apiKey)` constructor.
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## Adding a New Tool — 9-File Checklist
|
|
103
|
-
|
|
104
|
-
From `CLAUDE.md`:
|
|
105
|
-
|
|
106
|
-
| # | File | What to update |
|
|
107
|
-
|---|---|---|
|
|
108
|
-
| 1 | `src/tools/maps/<toolName>.ts` | Define NAME, DESCRIPTION, SCHEMA, ACTION |
|
|
109
|
-
| 2 | `src/config.ts` | Add to `tools[]` array with annotations |
|
|
110
|
-
| 3 | `src/cli.ts` | Add to `EXEC_TOOLS` const + `switch` case in `execTool()` |
|
|
111
|
-
| 4 | `tests/smoke.test.ts` | Add to `expectedTools` array + update tool count assertions |
|
|
112
|
-
| 5 | `README.md` | Update tool count (header, comparison table, Server Info, exec mode) + Available Tools table + Project Structure |
|
|
113
|
-
| 6 | `skills/google-maps/SKILL.md` | Add row to Tool Map table |
|
|
114
|
-
| 7 | `skills/google-maps/references/tools-api.md` | Add parameter docs + chaining patterns |
|
|
115
|
-
| 8 | `server.json` | Update description if it mentions tool count |
|
|
116
|
-
| 9 | `package.json` | Update description if it mentions tool count |
|
|
117
|
-
|
|
118
|
-
Missing any file causes doc/behavior mismatch. Verify all before opening a PR.
|
|
119
|
-
|
|
120
|
-
---
|
|
121
|
-
|
|
122
|
-
## Code Map
|
|
123
|
-
|
|
124
|
-
| File | Purpose |
|
|
125
|
-
|---|---|
|
|
126
|
-
| `src/cli.ts` | CLI entry point — parses args, selects transport, dispatches exec mode |
|
|
127
|
-
| `src/config.ts` | Assembles ToolConfig[] array from all tool modules |
|
|
128
|
-
| `src/core/BaseMcpServer.ts` | MCP server core — tool registration, HTTP session management, stdio transport |
|
|
129
|
-
| `src/index.ts` | Package entry — exports Logger and re-exports public API |
|
|
130
|
-
| `src/services/PlacesSearcher.ts` | Service facade — orchestrates multi-step composite tools (planRoute, exploreArea, comparePlaces, searchAlongRoute) |
|
|
131
|
-
| `src/services/RoutesService.ts` | Routes API REST client — computeRoutes (directions), computeRouteMatrix (distance matrix), waypoint optimization |
|
|
132
|
-
| `src/services/toolclass.ts` | Google Maps SDK wrapper — geocode, elevation, timezone, weather, airQuality, staticMap, searchAlongRoute |
|
|
133
|
-
| `src/services/NewPlacesService.ts` | Places API (New) client — searchNearby, searchText, getPlaceDetails via gRPC |
|
|
134
|
-
| `src/tools/maps/*.ts` | Individual tool definitions (17 files) — each exports NAME, DESCRIPTION, SCHEMA, ACTION |
|
|
135
|
-
| `src/utils/apiKeyManager.ts` | Singleton — resolves API key priority from headers / session / env |
|
|
136
|
-
| `src/utils/requestContext.ts` | AsyncLocalStorage — propagates API key within a single request lifecycle |
|
|
137
|
-
| `tests/smoke.test.ts` | Integration smoke tests — validates tool list, basic API calls |
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
# Architecture Decision Records — mcp-google-map
|
|
2
|
-
|
|
3
|
-
> Format: Decision / Context / Rationale
|
|
4
|
-
> Sources: dev-roadmap-spec.md, CLAUDE.md, project history
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
## ADR-001: Unified `maps_` Prefix for All Tool Names
|
|
9
|
-
|
|
10
|
-
**Decision**: All tools are named with the `maps_` prefix (e.g., `maps_geocode`, `maps_search_nearby`). This was applied as a breaking change when the namespace was standardized.
|
|
11
|
-
|
|
12
|
-
**Context**: Early tool names were inconsistent — some had prefixes, some did not. As the tool count grew and the server was listed on MCP registries, namespace collisions with other MCP servers became a concern. Claude's tool selection also benefits from a clear namespace signal.
|
|
13
|
-
|
|
14
|
-
**Rationale**:
|
|
15
|
-
- Consistent namespace prevents collision when multiple MCP servers are active simultaneously.
|
|
16
|
-
- The `maps_` prefix gives Claude a strong disambiguation signal — it knows these tools are geospatial without reading descriptions.
|
|
17
|
-
- Breaking change was accepted early (pre-stable) to avoid accumulating technical debt. All 9 files in the Tool Change Checklist must be updated together on any rename.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## ADR-002: `compare_places` Retained as a Composite Tool
|
|
22
|
-
|
|
23
|
-
**Decision**: `maps_compare_places` is a single tool that internally fetches details for multiple places and returns a structured comparison. It is not decomposed into atomic `place_details` calls that the AI chains together.
|
|
24
|
-
|
|
25
|
-
**Context**: An alternative design would have the AI call `maps_place_details` N times and synthesize the comparison itself. During testing, this produced inconsistent output quality and required users to explicitly orchestrate the chain.
|
|
26
|
-
|
|
27
|
-
**Rationale**:
|
|
28
|
-
- Users ask "compare these restaurants" and expect a comparison table, not raw data to synthesize.
|
|
29
|
-
- Composite tools reduce chaining overhead and produce deterministic, structured output.
|
|
30
|
-
- The Geo-Reasoning Benchmark (GRB) validates this: Composite Efficiency Score (CES) rewards using 1 call instead of N calls. `compare_places` is the reference case for this metric.
|
|
31
|
-
- User preference confirmed: users do not want to manually chain atomic calls for comparison tasks.
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
## ADR-003: `maps_weather` and `maps_air_quality` as Separate Tools
|
|
36
|
-
|
|
37
|
-
**Decision**: Weather and air quality are exposed as two independent tools, not combined into a single `maps_environment` tool.
|
|
38
|
-
|
|
39
|
-
**Context**: A natural grouping might combine weather and air quality into one "environmental conditions" call. Both return ambient data about a location.
|
|
40
|
-
|
|
41
|
-
**Rationale**:
|
|
42
|
-
- **Different APIs**: Weather uses one endpoint; Air Quality uses `POST https://airquality.googleapis.com/v1/currentConditions:lookup` — a completely separate Google service requiring separate API enablement.
|
|
43
|
-
- **Different geographic coverage**: Weather API does not support Japan. Air Quality API fully supports Japan (including AEROS local index). Combining them would require complex conditional logic and mislead users about availability.
|
|
44
|
-
- **Different data structures and use cases**: Weather is for planning (will it rain?). Air quality is for health decisions (should I wear a mask? can elderly parents go outside?). The 7-demographic health recommendation field in air quality has no analogue in weather.
|
|
45
|
-
- **Independent billing**: Separate pricing makes cost attribution cleaner.
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## ADR-004: `maps_isochrone` Not Built
|
|
50
|
-
|
|
51
|
-
**Decision**: Isochrone generation (travel-time polygons) is excluded from the roadmap, marked as "Skip for now."
|
|
52
|
-
|
|
53
|
-
**Context**: Isochrones are a commonly requested GIS feature — "show me everywhere I can reach in 30 minutes." They are valuable for real estate analysis, event planning, and accessibility research.
|
|
54
|
-
|
|
55
|
-
**Rationale**:
|
|
56
|
-
- **Google has no native isochrone API.** All alternative implementations have disqualifying problems:
|
|
57
|
-
- Mapbox Isochrone API: mature, but introduces a second vendor (Mapbox key) alongside Google — breaks the single-provider positioning.
|
|
58
|
-
- OpenRouteService: free but rate-limited and stability uncertain for production use.
|
|
59
|
-
- Distance Matrix grid approximation: 24+ API calls per isochrone at ~$0.12/request; prohibitively expensive and low-accuracy.
|
|
60
|
-
- **Core value is visual**: An isochrone polygon is only meaningful when rendered on a map. Without `maps_static_map` to display it, returning raw GeoJSON coordinates is not useful to AI or users. The feature was deprioritized until static map rendering was in place.
|
|
61
|
-
- **Revisit path**: If built later, the best approach is Distance Matrix 8-direction probing + `maps_static_map` to render an approximated polygon. Estimated effort: 8 hours.
|
|
62
|
-
|
|
63
|
-
---
|
|
64
|
-
|
|
65
|
-
## ADR-005: `maps_validate_address` Not Built
|
|
66
|
-
|
|
67
|
-
**Decision**: Address validation (checking if a postal address is deliverable) is excluded from the tool set.
|
|
68
|
-
|
|
69
|
-
**Context**: Google's Address Validation API provides USPS CASS-certified validation, deliverability flags, and address correction. It could theoretically be useful for any tool that takes address inputs.
|
|
70
|
-
|
|
71
|
-
**Rationale**:
|
|
72
|
-
- **Cost**: $17 per 1,000 requests — 3.4× the cost of standard geocoding. This is prohibitive for conversational AI use where users make casual address queries.
|
|
73
|
-
- **Wrong use case**: Address validation is designed for backend pipelines (e-commerce checkout, CRM deduplication, bulk mailing). It requires structured postal input and returns structured postal corrections — not a natural fit for natural-language AI conversations.
|
|
74
|
-
- **Coverage gap**: Only 38 countries supported; excludes most of Asia and Africa. A tool that silently fails for Tokyo or Mumbai addresses would create confusing UX.
|
|
75
|
-
- **Existing alternative**: `maps_geocode` already handles 60% of "is this address valid?" scenarios by returning whether a geocode succeeded and providing the `formatted_address` canonical form.
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## ADR-006: Spatial Context / Session Memory Not Built
|
|
80
|
-
|
|
81
|
-
**Decision**: There is no persistent spatial context or session memory layer in the MCP server. The server does not remember previously queried locations or build a "current location" state across calls.
|
|
82
|
-
|
|
83
|
-
**Context**: A proposed feature was to maintain implicit state — if a user asks "find coffee shops" after previously mentioning "I'm in Shinjuku," the server would remember Shinjuku and use it as the implicit location for the next search.
|
|
84
|
-
|
|
85
|
-
**Rationale**:
|
|
86
|
-
- **Claude's conversation history already solves this.** Claude reads its own prior messages and can extract previously mentioned locations. A server-side memory layer would duplicate capability that already exists in the LLM.
|
|
87
|
-
- **Composite tools reduce chaining need.** Tools like `maps_explore_area` and `maps_plan_route` accept multi-intent inputs that would otherwise require chaining with location state.
|
|
88
|
-
- **Implementation risks outweigh benefits**:
|
|
89
|
-
- Implicit state leakage: state from one user's session could bleed into another in concurrent scenarios.
|
|
90
|
-
- Debugging opacity: errors become harder to trace when the server has hidden state.
|
|
91
|
-
- stdio transport has no session concept — each stdio connection is stateless by design.
|
|
92
|
-
- **User value assessed at 3/10.** In testing, users could not perceive a meaningful difference. The friction of unexpected state (wrong implicit location) outweighed the convenience.
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
## ADR-007: stdio as Primary Transport
|
|
97
|
-
|
|
98
|
-
**Decision**: The MCP server uses stdio (standard input/output) as its primary transport mechanism. HTTP/SSE is secondary.
|
|
99
|
-
|
|
100
|
-
**Context**: MCP servers can expose transport via stdio (subprocess model) or HTTP+SSE (network server model). Both are valid per the MCP specification.
|
|
101
|
-
|
|
102
|
-
**Rationale**:
|
|
103
|
-
- **MCP Registry requirement**: The official MCP registry and most client integrations (Claude Desktop, Claude Code, Cursor) prefer or require stdio-based servers for local installation.
|
|
104
|
-
- **Security model**: stdio servers run as a subprocess of the client, inheriting the client's trust context. No network port exposure, no authentication complexity.
|
|
105
|
-
- **Deployment simplicity**: `npx mcp-google-map` works out of the box without configuring ports, firewalls, or SSL.
|
|
106
|
-
- **Statelessness aligns with stdio**: Each stdio connection represents one session. This reinforces ADR-006 (no spatial context) — the transport model naturally discourages stateful designs.
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## ADR-008: Search Along Route Uses Direct REST Calls
|
|
111
|
-
|
|
112
|
-
**Decision**: The "search along route" capability calls the Google Maps REST API directly rather than using the official `@googlemaps/google-maps-services-js` client library.
|
|
113
|
-
|
|
114
|
-
**Context**: Most tools in this project use the official client library for consistency and type safety. The route-based search requires fetching a polyline and then querying points along it — a pattern not natively supported by the client library.
|
|
115
|
-
|
|
116
|
-
**Rationale**:
|
|
117
|
-
- **Client library may not expose the required parameters or patterns** for buffered route searches. The REST API is always the source of truth; the client library is a convenience wrapper.
|
|
118
|
-
- **Direct REST calls are straightforward**: for GET requests with query parameters, `axios` or `fetch` is sufficient and keeps the implementation explicit.
|
|
119
|
-
- **Type safety can be maintained** by defining TypeScript interfaces for the REST response shapes — same outcome as using the library, without library constraints.
|
|
120
|
-
- This is an exception to the general project preference for the client library, justified by the specific technical requirement.
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## ADR-009: MCP Prompt Templates Removed
|
|
125
|
-
|
|
126
|
-
**Decision**: MCP Prompt Templates (slash commands like `/travel-planner`) were evaluated and ultimately not shipped as a feature.
|
|
127
|
-
|
|
128
|
-
**Context**: The roadmap spec (P1-1) proposed implementing MCP's `prompts` primitive to expose slash commands in clients like Claude Desktop. The intended value was giving non-technical users a one-click entry into geo agent mode.
|
|
129
|
-
|
|
130
|
-
**Rationale**:
|
|
131
|
-
- **Client support is low and inconsistent.** As of evaluation, most MCP clients either do not render prompt templates as slash commands or render them inconsistently. The feature would benefit a small fraction of users.
|
|
132
|
-
- **SKILL.md already covers the use case** for Claude Code users — the skill system provides rich scenario guidance, chaining patterns, and example recipes that go beyond what prompt templates support.
|
|
133
|
-
- **Maintenance cost**: Prompt template content would need to stay in sync with tool capabilities, adding to the already-significant 9-file update checklist (CLAUDE.md ADR).
|
|
134
|
-
- **Revisit condition**: If MCP client support for prompts reaches broad adoption (Claude Desktop, VS Code extension, Cursor all render them consistently), this should be reconsidered. The 6-hour implementation estimate is low.
|
|
135
|
-
|
|
136
|
-
---
|
|
137
|
-
|
|
138
|
-
## ADR-010: Travel Planning Uses "Tool-Driven Diffusion," Not AI Prior Knowledge
|
|
139
|
-
|
|
140
|
-
**Decision**: Travel planning workflows are designed so the AI discovers ground truth by calling tools, not by relying on training-data knowledge of specific places, hours, or transit schedules.
|
|
141
|
-
|
|
142
|
-
**Context**: An AI could answer "what time does Kinkaku-ji open?" from training data. It could suggest a Tokyo itinerary without any tool calls based on memorized "best of Tokyo" patterns. This is faster but fragile.
|
|
143
|
-
|
|
144
|
-
**Rationale**:
|
|
145
|
-
- **Training data goes stale.** Business hours change, places close, new venues open. A tool call to `maps_place_details` returns current data; training knowledge reflects a past snapshot.
|
|
146
|
-
- **Specificity requires data.** A user asking for restaurants near their hotel requires the actual hotel coordinates, not generic neighborhood knowledge. The tool call chain (geocode hotel → search nearby → get details) produces a personalized result that training data cannot replicate.
|
|
147
|
-
- **Verifiability and trust.** When the AI cites data from a tool response (e.g., "Fushimi Inari opens at 6 AM according to Google Maps"), users can verify the source. When it speaks from training data, there is no audit trail.
|
|
148
|
-
- **The SKILL.md geo-domain knowledge** (temple hours, transit rules, energy curves) is intentionally at the *pattern* level — it tells the AI *how* to plan, not *what* specific facts are. The facts come from tools. This separation is the core design principle.
|
|
149
|
-
- Practical implementation: always geocode place names (don't assume coordinates), always fetch operating hours from `maps_place_details` (don't assume 9–5), always calculate transit time with `maps_directions` (don't estimate from distance).
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
# Geo Domain Knowledge for AI Map Tool Operators
|
|
2
|
-
|
|
3
|
-
> Purpose: Give an AI agent without GIS background the domain knowledge needed to use map tools correctly and confidently.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 1. Coordinate Systems
|
|
8
|
-
|
|
9
|
-
**WGS84** is the universal standard. Every latitude/longitude pair you encounter in Google Maps APIs uses WGS84. No conversion needed.
|
|
10
|
-
|
|
11
|
-
**Order convention — lat comes first:**
|
|
12
|
-
- Correct: `(35.6762, 139.6503)` — Tokyo
|
|
13
|
-
- Wrong: `(139.6503, 35.6762)` — inverted, puts you in the ocean
|
|
14
|
-
- Google Maps API parameters are always `latitude`, `longitude` in that order.
|
|
15
|
-
|
|
16
|
-
**Precision and real-world accuracy:**
|
|
17
|
-
|
|
18
|
-
| Decimal places | Precision | Notes |
|
|
19
|
-
|----------------|-----------|-------|
|
|
20
|
-
| 0 (e.g., 35°) | ~111 km | Country-level |
|
|
21
|
-
| 1 (35.6°) | ~11 km | City-level |
|
|
22
|
-
| 2 (35.67°) | ~1.1 km | District-level |
|
|
23
|
-
| 3 (35.676°) | ~111 m | Street-level |
|
|
24
|
-
| 4 (35.6762°) | ~11 m | Building-level |
|
|
25
|
-
| 5 (35.67620°) | ~1.1 m | Door-level |
|
|
26
|
-
| 6+ | <1 m | Survey-grade, rarely needed |
|
|
27
|
-
|
|
28
|
-
For navigation and place lookup, 4–5 decimal places is sufficient. Do not truncate coordinates returned by the API — pass them as-is to downstream tools.
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## 2. Distance Concepts
|
|
33
|
-
|
|
34
|
-
**Latitude degree is nearly constant worldwide:**
|
|
35
|
-
- 1° latitude ≈ 111 km everywhere
|
|
36
|
-
|
|
37
|
-
**Longitude degree varies with latitude:**
|
|
38
|
-
- At equator (0°): 1° longitude ≈ 111 km
|
|
39
|
-
- At 35°N (Tokyo/Seoul/Beijing): 1° longitude ≈ 91 km
|
|
40
|
-
- At 45°N (Paris/Milan): 1° longitude ≈ 78 km
|
|
41
|
-
- At 60°N (Oslo/Helsinki): 1° longitude ≈ 55 km
|
|
42
|
-
|
|
43
|
-
**Quick mental math:** At Tokyo's latitude, a 0.01° difference is roughly 1 km.
|
|
44
|
-
|
|
45
|
-
**Speed references for time estimation:**
|
|
46
|
-
|
|
47
|
-
| Mode | Typical speed | Notes |
|
|
48
|
-
|------|--------------|-------|
|
|
49
|
-
| Walking | ~5 km/h | 1 km = ~12 min |
|
|
50
|
-
| Cycling | ~15 km/h | varies by terrain |
|
|
51
|
-
| Urban driving | ~30–40 km/h | traffic included |
|
|
52
|
-
| Highway driving | ~80–100 km/h | intercity |
|
|
53
|
-
| Transit (urban) | ~20–30 km/h door-to-door | includes wait time |
|
|
54
|
-
| Shinkansen | ~250–300 km/h | between major cities |
|
|
55
|
-
|
|
56
|
-
These are rule-of-thumb values. Always use `maps_directions` or `maps_distance_matrix` for real travel time — actual conditions (traffic, transit schedules) differ significantly.
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## 3. Geocoding Concepts
|
|
61
|
-
|
|
62
|
-
**Forward geocoding**: address/name → lat/lng
|
|
63
|
-
- Input: "Shibuya Station, Tokyo"
|
|
64
|
-
- Output: `{ lat: 35.6580, lng: 139.7016, place_id: "ChIJ...", formatted_address: "..." }`
|
|
65
|
-
|
|
66
|
-
**Reverse geocoding**: lat/lng → address
|
|
67
|
-
- Input: `(35.6580, 139.7016)`
|
|
68
|
-
- Output: formatted address + place types for that location
|
|
69
|
-
- Use case: "What is at these coordinates?"
|
|
70
|
-
|
|
71
|
-
**place_id** — the stable identifier for a place in Google's database:
|
|
72
|
-
- Format: `ChIJN1t_tDeuEmsRUsoyG83frY4` (opaque string)
|
|
73
|
-
- Stable across time (unlike coordinates, which can shift if a business moves)
|
|
74
|
-
- Preferred input for `maps_place_details` — faster and more precise than re-searching by name
|
|
75
|
-
- Always cache `place_id` when you receive it; reuse in subsequent calls
|
|
76
|
-
|
|
77
|
-
**formatted_address vs raw input:**
|
|
78
|
-
- `formatted_address` is Google's canonical form: `"2 Chome-21-1 Asakusa, Taito City, Tokyo 111-0032, Japan"`
|
|
79
|
-
- Use it for display and for chaining into other tools that accept address strings
|
|
80
|
-
- Do not invent or modify addresses — only pass what Google returned
|
|
81
|
-
|
|
82
|
-
---
|
|
83
|
-
|
|
84
|
-
## 4. Place Types
|
|
85
|
-
|
|
86
|
-
Google's place type system is hierarchical. A place can have multiple types (e.g., a convenience store is both `convenience_store` and `store`).
|
|
87
|
-
|
|
88
|
-
**Common type categories:**
|
|
89
|
-
|
|
90
|
-
| Category | Examples |
|
|
91
|
-
|----------|---------|
|
|
92
|
-
| Food & drink | `restaurant`, `cafe`, `bar`, `bakery`, `meal_takeaway`, `food` |
|
|
93
|
-
| Lodging | `lodging`, `hotel`, `hostel`, `guest_house` |
|
|
94
|
-
| Transport | `train_station`, `subway_station`, `bus_station`, `airport`, `transit_station` |
|
|
95
|
-
| Culture | `museum`, `art_gallery`, `library`, `church`, `temple`, `shrine` |
|
|
96
|
-
| Nature | `park`, `natural_feature`, `campground`, `amusement_park` |
|
|
97
|
-
| Health | `hospital`, `pharmacy`, `doctor`, `dentist` |
|
|
98
|
-
| Shopping | `shopping_mall`, `supermarket`, `convenience_store`, `clothing_store` |
|
|
99
|
-
| Finance | `bank`, `atm` |
|
|
100
|
-
| Education | `school`, `university` |
|
|
101
|
-
| Government | `local_government_office`, `post_office`, `police` |
|
|
102
|
-
|
|
103
|
-
**How to pick the right type for search:**
|
|
104
|
-
- Be specific for precision: `ramen_restaurant` > `restaurant` when you know what you want
|
|
105
|
-
- Use broader types for exploration: `food` catches everything edible
|
|
106
|
-
- Some types are not searchable (too broad) — prefer specific leaf-level types
|
|
107
|
-
- Compound queries work: pass `keyword="ramen"` with `type="restaurant"` for best results
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## 5. Routing and Navigation
|
|
112
|
-
|
|
113
|
-
**Travel modes:**
|
|
114
|
-
|
|
115
|
-
| Mode | Parameter | Notes |
|
|
116
|
-
|------|-----------|-------|
|
|
117
|
-
| Driving | `DRIVE` | Default, uses current traffic |
|
|
118
|
-
| Walking | `WALK` | No highways, includes pedestrian paths |
|
|
119
|
-
| Cycling | `BICYCLE` | Not available in all regions |
|
|
120
|
-
| Transit | `TRANSIT` | Requires `departure_time` for accurate results |
|
|
121
|
-
|
|
122
|
-
**Key rule for transit**: Always provide `departure_time` (Unix timestamp). Without it, Google may use default schedules that don't reflect actual service patterns. For planning tools, use a future timestamp on a weekday.
|
|
123
|
-
|
|
124
|
-
**Overview polyline:**
|
|
125
|
-
- A compressed string encoding the entire route path (e.g., `_p~iF~ps|U_ulLnnqC_mqNvxq`@`)
|
|
126
|
-
- Encoded in Google's Polyline Algorithm (each character represents coordinate delta)
|
|
127
|
-
- Use it when you need to pass the route to `maps_static_map` for visualization
|
|
128
|
-
- Do not try to decode it manually — pass it as-is to display tools
|
|
129
|
-
|
|
130
|
-
**Waypoints and stops:**
|
|
131
|
-
- Routes can include intermediate waypoints
|
|
132
|
-
- Optimize waypoint order with `optimize=true` for multi-stop itineraries
|
|
133
|
-
- For Tokyo sightseeing: always think about natural geographic flow (e.g., north→south or circular) to minimize backtracking
|
|
134
|
-
|
|
135
|
-
---
|
|
136
|
-
|
|
137
|
-
## 6. Map Projections
|
|
138
|
-
|
|
139
|
-
**Mercator projection** is what Google Maps (and virtually all web maps) uses.
|
|
140
|
-
|
|
141
|
-
Key distortion property: **area is not preserved, shape is**. The further from the equator, the larger things appear relative to their true size.
|
|
142
|
-
|
|
143
|
-
| Location | Apparent size on map vs reality |
|
|
144
|
-
|----------|--------------------------------|
|
|
145
|
-
| Africa vs Greenland | Africa is 14x larger in reality, but they look similar on Mercator |
|
|
146
|
-
| Japan (~35°N) | Moderate distortion, cities appear roughly accurate |
|
|
147
|
-
| Scandinavia (~60°N) | Significantly overstated on map |
|
|
148
|
-
|
|
149
|
-
**Why this matters for `maps_static_map`:**
|
|
150
|
-
- At the same zoom level, a 600x400 tile covers more actual ground at higher latitudes
|
|
151
|
-
- Zoom 12 in Tokyo covers ~10 km across; zoom 12 in Tokyo's northern suburbs covers slightly more
|
|
152
|
-
- Zoom guidelines for `maps_static_map`:
|
|
153
|
-
|
|
154
|
-
| Zoom | Coverage |
|
|
155
|
-
|------|---------|
|
|
156
|
-
| 1 | World |
|
|
157
|
-
| 5 | Continent/large country |
|
|
158
|
-
| 10 | City |
|
|
159
|
-
| 12 | District |
|
|
160
|
-
| 14 | Neighborhood |
|
|
161
|
-
| 16 | Streets |
|
|
162
|
-
| 18 | Building-level |
|
|
163
|
-
| 20 | Room-level (where available) |
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
## 7. Spatial Search Types
|
|
168
|
-
|
|
169
|
-
**Circular search (radius-based):**
|
|
170
|
-
- Definition: find places within N meters of a center point
|
|
171
|
-
- API: `maps_search_nearby` with `radius` parameter
|
|
172
|
-
- Best for: "coffee shops near me," "ATM within 500m"
|
|
173
|
-
- Limitation: covers uniform area regardless of walkability — a 500m radius includes both sides of a river
|
|
174
|
-
|
|
175
|
-
**Search along route:**
|
|
176
|
-
- Definition: find places near any point on a route path
|
|
177
|
-
- Requires: route polyline from `maps_directions`
|
|
178
|
-
- Best for: "rest stops between Tokyo and Osaka," "gas stations on the way"
|
|
179
|
-
- Implementation: buffer the polyline, search at interval waypoints
|
|
180
|
-
|
|
181
|
-
**Bounding box search:**
|
|
182
|
-
- Definition: find everything within a lat/lng rectangle
|
|
183
|
-
- Best for: "all museums in Kyoto" (known geographic area)
|
|
184
|
-
- Less precise than radius — corners are farther from center than edge midpoints
|
|
185
|
-
|
|
186
|
-
**Choosing the right approach:**
|
|
187
|
-
|
|
188
|
-
| Scenario | Use |
|
|
189
|
-
|----------|-----|
|
|
190
|
-
| Near a specific point | Circular (radius) |
|
|
191
|
-
| Along a travel path | Route-based |
|
|
192
|
-
| Within a city/district | Bounding box or large radius from city center |
|
|
193
|
-
| "Best of" in an area | Keyword search + type filter |
|
|
194
|
-
|
|
195
|
-
---
|
|
196
|
-
|
|
197
|
-
## 8. Travel Planning Domain Knowledge
|
|
198
|
-
|
|
199
|
-
**Time-of-day sensitivity:**
|
|
200
|
-
- Early morning (6–9 AM): temples/shrines are quieter, markets open
|
|
201
|
-
- Midday (11 AM–2 PM): lunch crowds at restaurants; museums uncrowded
|
|
202
|
-
- Late afternoon (3–5 PM): good for viewpoints and gardens (golden hour light)
|
|
203
|
-
- Evening (5–8 PM): best for dining, night markets, illuminated landmarks
|
|
204
|
-
- Night (8 PM+): limited temple access, izakayas peak, Tokyo Skytree views
|
|
205
|
-
|
|
206
|
-
**Arc routing principle:**
|
|
207
|
-
- Design routes that move in one general direction, then return — avoid ping-pong backtracking
|
|
208
|
-
- Example: Asakusa → Ueno → Akihabara (east→center→east) is efficient; Shinjuku → Asakusa → Shinjuku is not
|
|
209
|
-
|
|
210
|
-
**Energy curve (fatigue model):**
|
|
211
|
-
- Morning: high energy → schedule physically demanding activities (hills, many stairs)
|
|
212
|
-
- Midday: lunch + rest → schedule museum interiors, air-conditioned venues
|
|
213
|
-
- Afternoon: moderate energy → walking tours, shopping
|
|
214
|
-
- Evening: low energy → seated dining, short walks only
|
|
215
|
-
|
|
216
|
-
**Meal timing:**
|
|
217
|
-
- Breakfast: 7–9 AM
|
|
218
|
-
- Lunch: 11:30 AM–1:30 PM (plan to arrive before 12 to avoid queues)
|
|
219
|
-
- Dinner: 6–8 PM (popular spots fill by 6:30)
|
|
220
|
-
- Always build 15–20 min buffer for transit between meals and activities
|
|
221
|
-
|
|
222
|
-
**Group size adjustments:**
|
|
223
|
-
- Solo/couple: access anywhere, no reservation usually needed
|
|
224
|
-
- Group (4–8): book restaurants ahead, check venue capacity
|
|
225
|
-
- Large group (8+): many historic sites have capacity limits (e.g., Fushimi Inari paths are narrow)
|
|
226
|
-
|
|
227
|
-
---
|
|
228
|
-
|
|
229
|
-
## 9. Japan-Specific Knowledge
|
|
230
|
-
|
|
231
|
-
### Kyoto Area Structure
|
|
232
|
-
|
|
233
|
-
Kyoto's main sightseeing zones:
|
|
234
|
-
|
|
235
|
-
| Zone | Key sites | Character |
|
|
236
|
-
|------|----------|-----------|
|
|
237
|
-
| Arashiyama (west) | Bamboo Grove, Tenryu-ji | Nature, bamboo, riverside |
|
|
238
|
-
| Higashiyama (east) | Kiyomizu-dera, Gion, Ninen-zaka | Traditional streets, temples |
|
|
239
|
-
| Fushimi (south) | Fushimi Inari | Torii gates, accessible by JR |
|
|
240
|
-
| Downtown (center) | Nijo Castle, Nishiki Market | Mix of modern and historical |
|
|
241
|
-
| Nishijin (north-center) | Kinkaku-ji, Ryoan-ji | Famous temples, crowded |
|
|
242
|
-
|
|
243
|
-
**Rule**: Arashiyama and Higashiyama are on opposite sides of the city (~1 hr by bus). Do not combine them in a half-day plan.
|
|
244
|
-
|
|
245
|
-
### Train Network
|
|
246
|
-
|
|
247
|
-
| Network | Type | Use case |
|
|
248
|
-
|---------|------|---------|
|
|
249
|
-
| Shinkansen (bullet train) | Inter-city | Tokyo↔Kyoto (2h15m), Tokyo↔Osaka (2h30m) |
|
|
250
|
-
| JR lines | Regional/urban | JR Pass compatible, connects major stations |
|
|
251
|
-
| Hankyu/Keihan/Kintetsu | Private railways | Osaka↔Kyoto alternatives, often cheaper |
|
|
252
|
-
| Tokyo Metro / Toei | Urban subway | Dense Tokyo inner-city coverage |
|
|
253
|
-
| Kyoto Bus | Urban bus | Essential for Kyoto (no subway to Arashiyama/Fushimi) |
|
|
254
|
-
|
|
255
|
-
**Practical notes:**
|
|
256
|
-
- IC cards (Suica, Pasmo, ICOCA) work on almost all trains and buses in Japan — recommend for all visitors
|
|
257
|
-
- JR Pass only covers JR-operated lines, not private railways or subways
|
|
258
|
-
- In Kyoto, bus day pass (¥700) is cost-effective for 3+ bus rides
|
|
259
|
-
|
|
260
|
-
### Temple and Shrine Access Times
|
|
261
|
-
|
|
262
|
-
| Category | Typical hours | Notes |
|
|
263
|
-
|----------|--------------|-------|
|
|
264
|
-
| Major temples (paid) | 8:30 AM – 5:00 PM | Last entry 30 min before close |
|
|
265
|
-
| Fushimi Inari | 24 hours | Lower section always open |
|
|
266
|
-
| Buddhist temple grounds | 6:00 AM – dusk | Gates/halls may have separate hours |
|
|
267
|
-
| Shrine precincts | Usually always open | Inner buildings have set hours |
|
|
268
|
-
|
|
269
|
-
**Key rule**: Always plan temple visits for morning to avoid afternoon crowds and ensure all halls are open. Schedule Fushimi Inari early morning (6–8 AM) to avoid tour groups.
|
|
270
|
-
|
|
271
|
-
### Japanese Address System
|
|
272
|
-
|
|
273
|
-
Addresses in Japan follow a reverse order from Western convention:
|
|
274
|
-
- Prefecture → City → Ward → Chome (district) → Block → Building
|
|
275
|
-
- Example: `東京都渋谷区道玄坂1丁目2-3` = Tokyo-to, Shibuya-ku, Dogenzaka 1-chome, block 2, building 3
|
|
276
|
-
- Always geocode Japanese addresses using `maps_geocode` — do not attempt to calculate coordinates from address text.
|
|
277
|
-
|
|
278
|
-
### Useful Distance References (Japan)
|
|
279
|
-
|
|
280
|
-
| Route | Distance | Transport | Time |
|
|
281
|
-
|-------|----------|-----------|------|
|
|
282
|
-
| Tokyo → Kyoto | 450 km | Nozomi Shinkansen | 2h15m |
|
|
283
|
-
| Tokyo → Osaka | 520 km | Nozomi Shinkansen | 2h30m |
|
|
284
|
-
| Kyoto → Nara | 35 km | JR Nara Line | 45m |
|
|
285
|
-
| Kyoto → Osaka | 75 km | JR/Hankyu | 15–28m |
|
|
286
|
-
| Shinjuku → Asakusa (Tokyo) | 10 km | Metro | 30m |
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
# Google Maps API Guide
|
|
2
|
-
|
|
3
|
-
## APIs in Use
|
|
4
|
-
|
|
5
|
-
| API | Endpoint | Tool(s) | GCP Service to Enable |
|
|
6
|
-
|---|---|---|---|
|
|
7
|
-
| Geocoding API | via `@googlemaps/google-maps-services-js` SDK | `maps_geocode`, `maps_reverse_geocode`, `maps_batch_geocode` | Geocoding API |
|
|
8
|
-
| Routes API (computeRoutes) | `https://routes.googleapis.com/directions/v2:computeRoutes` (REST fetch) | `maps_directions`, `maps_plan_route` (legs + waypoint optimization), `maps_search_along_route` (polyline) | Routes API |
|
|
9
|
-
| Routes API (computeRouteMatrix) | `https://routes.googleapis.com/distanceMatrix/v2:computeRouteMatrix` (REST fetch) | `maps_distance_matrix` | Routes API |
|
|
10
|
-
| Elevation API | via SDK | `maps_elevation` | Elevation API |
|
|
11
|
-
| Time Zone API | via SDK | `maps_timezone` | Time Zone API |
|
|
12
|
-
| Places API (New) — Nearby Search | `https://places.googleapis.com/v1/places:searchNearby` (gRPC via `@googlemaps/places`) | `maps_search_nearby` | Places API (New) |
|
|
13
|
-
| Places API (New) — Text Search | `https://places.googleapis.com/v1/places:searchText` (gRPC + REST) | `maps_search_places`, `maps_compare_places`, `maps_explore_area`, `maps_search_along_route` (step 2) | Places API (New) |
|
|
14
|
-
| Places API (New) — Place Details | `https://places.googleapis.com/v1/places/{placeId}` (gRPC) | `maps_place_details` | Places API (New) |
|
|
15
|
-
| Weather API | `https://weather.googleapis.com/v1/currentConditions:lookup` | `maps_weather` (type=current) | Google Weather API |
|
|
16
|
-
| Weather API — Daily Forecast | `https://weather.googleapis.com/v1/forecast/days:lookup` | `maps_weather` (type=forecast_daily, max 10 days) | Google Weather API |
|
|
17
|
-
| Weather API — Hourly Forecast | `https://weather.googleapis.com/v1/forecast/hours:lookup` | `maps_weather` (type=forecast_hourly, max 240 hours) | Google Weather API |
|
|
18
|
-
| Air Quality API | `https://airquality.googleapis.com/v1/currentConditions:lookup` | `maps_air_quality` | Air Quality API |
|
|
19
|
-
| Maps Static API | `https://maps.googleapis.com/maps/api/staticmap` | `maps_static_map` | Maps Static API |
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## API Coverage Limitations
|
|
24
|
-
|
|
25
|
-
### Weather API
|
|
26
|
-
|
|
27
|
-
- **Not supported**: China, Japan, South Korea, Cuba, Iran, North Korea, Syria
|
|
28
|
-
- Best coverage: North America, Europe, Oceania
|
|
29
|
-
- Error message when unsupported: `"not supported for this location"` — the code catches this and returns a user-readable message including the list of unsupported regions
|
|
30
|
-
- Forecast limits: daily max 10 days, hourly max 240 hours (enforced with `Math.min/Math.max`)
|
|
31
|
-
|
|
32
|
-
### Air Quality API
|
|
33
|
-
|
|
34
|
-
- Global coverage (no known hard exclusions)
|
|
35
|
-
- Returns multiple indexes: universal AQI + local country-specific index where available
|
|
36
|
-
- `extraComputations` options: `HEALTH_RECOMMENDATIONS`, `POLLUTANT_CONCENTRATION`
|
|
37
|
-
|
|
38
|
-
### Places API (New)
|
|
39
|
-
|
|
40
|
-
- `maxResultCount` hard cap: 20 (enforced in `NewPlacesService`)
|
|
41
|
-
- `searchNearby` uses `includedTypes` (type-based), not free-text keyword
|
|
42
|
-
- Photos: returns `photo.name` (resource reference), not a direct image URL
|
|
43
|
-
|
|
44
|
-
### Directions API
|
|
45
|
-
|
|
46
|
-
- `transit` mode requires `departure_time` for accurate transit schedule results (without it Google may return estimated or no results)
|
|
47
|
-
- `plan_route` optimization uses `driving` mode for distance matrix even when the final leg mode is `transit`, to avoid matrix returning null entries
|
|
48
|
-
|
|
49
|
-
### Static Maps API
|
|
50
|
-
|
|
51
|
-
- URL length limit: 16,384 characters (enforced before fetch)
|
|
52
|
-
- Returns binary PNG, converted to base64 by the server for MCP response
|
|
53
|
-
- `maptype` options: `roadmap`, `satellite`, `terrain`, `hybrid`
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## Common Pitfalls
|
|
58
|
-
|
|
59
|
-
| Scenario | Problem | Fix |
|
|
60
|
-
|---|---|---|
|
|
61
|
-
| `transit` directions with no `departure_time` | Google may return `ZERO_RESULTS` or incorrect duration | Always pass `departure_time` (Unix timestamp or `"now"`) when using transit mode |
|
|
62
|
-
| `plan-route` with `formatted_address` from geocode | Directions API may return `ZERO_RESULTS` on complex formatted addresses | `plan-route` passes the original user-provided stop name to Directions, not `formatted_address` from geocode step |
|
|
63
|
-
| `searchNearby` with free-text keyword | `includedTypes` expects a Place type string (e.g. `"restaurant"`), not a general query | Use `search_places` for free-text; use `search_nearby` for type-constrained radius search |
|
|
64
|
-
| Weather for Japan/China | Returns HTTP error with "not supported for this location" | Catch and re-throw with explicit unsupported country list (already implemented) |
|
|
65
|
-
| Air Quality `includePollutants: false` | Default is `true` for `includeHealthRecommendations`, `false` for pollutants | Be explicit — omitting `includePollutants` defaults to `false` |
|
|
66
|
-
| Static map URL over 16,384 chars | Google rejects the request | Reduce number of markers or path waypoints |
|
|
67
|
-
| Place Details with Places API (New) | Resource name format is `places/<id>` not raw `placeId` | `NewPlacesService.getPlaceDetails()` prepends `places/` automatically |
|
|
68
|
-
| Batch geocode concurrency | Default concurrency is 20, max enforced at 50 | Use `--concurrency` flag in CLI batch-geocode command; tool-mode uses `Promise.all` |
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
## Rate Limits and Batch Strategy
|
|
73
|
-
|
|
74
|
-
| API | QPS Limit (default) | Notes |
|
|
75
|
-
|---|---|---|
|
|
76
|
-
| Geocoding API | 50 QPS | `maps_batch_geocode` uses `Promise.all` in tool mode; CLI uses semaphore with configurable concurrency (default 20, max 50) |
|
|
77
|
-
| Places API (New) | 100 QPS | Result count capped at 20 per request |
|
|
78
|
-
| Directions API | 50 QPS | `plan_route` makes N-1 serial Directions calls after parallel geocoding |
|
|
79
|
-
| Distance Matrix API | 100 elements/request, 100 QPS | `plan_route` optimization: N×N matrix for ≤ ~10 stops is safe |
|
|
80
|
-
| Weather / Air Quality | Per project quota | No internal retry logic; HTTP 429 surfaces as `"API quota exceeded"` message |
|
|
81
|
-
| Static Maps API | 500 QPS | Single image fetch; no batch |
|
|
82
|
-
|
|
83
|
-
**HTTP 403** → API key invalid or the required GCP API not enabled.
|
|
84
|
-
**HTTP 429 / `OVER_QUERY_LIMIT`** → Quota exceeded; wait and retry or upgrade billing plan.
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## Search Along Route
|
|
89
|
-
|
|
90
|
-
`maps_search_along_route` is a two-step composite:
|
|
91
|
-
|
|
92
|
-
**Step 1** — Get route polyline via Directions API:
|
|
93
|
-
```
|
|
94
|
-
GoogleMapsTools.getDirections(origin, destination, mode)
|
|
95
|
-
-> routes[0].overview_polyline.points (encoded polyline)
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
**Step 2** — Places Text Search with `searchAlongRouteParameters`:
|
|
99
|
-
```
|
|
100
|
-
POST https://places.googleapis.com/v1/places:searchText
|
|
101
|
-
Headers:
|
|
102
|
-
X-Goog-Api-Key: <key>
|
|
103
|
-
X-Goog-FieldMask: places.displayName,places.id,places.formattedAddress,
|
|
104
|
-
places.location,places.rating,places.userRatingCount,
|
|
105
|
-
places.currentOpeningHours.openNow
|
|
106
|
-
Body:
|
|
107
|
-
{
|
|
108
|
-
"textQuery": "<query>",
|
|
109
|
-
"searchAlongRouteParameters": {
|
|
110
|
-
"polyline": { "encodedPolyline": "<encoded>" }
|
|
111
|
-
},
|
|
112
|
-
"maxResultCount": <1-20>
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
**Limitations**:
|
|
117
|
-
- Requires Places API (New) to be enabled
|
|
118
|
-
- `maxResults` capped at 20
|
|
119
|
-
- Uses REST fetch (not gRPC SDK) because `searchAlongRouteParameters` is not yet exposed in the Node.js gRPC client
|
|
120
|
-
- Mode defaults to `walking` if not specified
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
## Places API New vs Legacy
|
|
125
|
-
|
|
126
|
-
| Aspect | Places API (New) | Places API (Legacy) |
|
|
127
|
-
|---|---|---|
|
|
128
|
-
| GCP service name | "Places API (New)" | "Places API" |
|
|
129
|
-
| Node.js library | `@googlemaps/places` | `@googlemaps/google-maps-services-js` |
|
|
130
|
-
| Protocol | gRPC (+ REST for searchText) | HTTPS REST |
|
|
131
|
-
| Auth | `apiKey` in constructor / `X-Goog-Api-Key` header | `key` query param |
|
|
132
|
-
| Field selection | `X-Goog-FieldMask` header | `fields` param |
|
|
133
|
-
| Resource naming | `places/<id>` | raw `placeId` string |
|
|
134
|
-
| Tools using it | `maps_search_nearby`, `maps_search_places`, `maps_place_details`, `maps_explore_area`, `maps_compare_places`, `maps_search_along_route` (step 2) | geocode, reverseGeocode, directions, distanceMatrix, elevation, timezone |
|
|
135
|
-
| Max results | 20 per request | varies by endpoint |
|
|
136
|
-
| Photos | Returns `photo.name` resource path | Returns `photo_reference` string |
|
|
137
|
-
| Error codes | gRPC status codes (7=PERMISSION_DENIED, 8=RESOURCE_EXHAUSTED) | HTTP status codes |
|
|
138
|
-
|
|
139
|
-
**Note**: `maps_search_along_route` uses the Routes API for step 1 (polyline extraction) and Places API (New) REST for step 2 (search). Both APIs must be enabled for this tool to function.
|