mcp-google-map 0.9.0 → 0.13.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/README.md +7 -3
- package/dist/{chunk-OAML6T2D.js → chunk-VCFXCLJF.js} +4 -4
- package/dist/chunk-VCFXCLJF.js.map +1 -0
- package/dist/cli.d.ts +11 -2
- package/dist/cli.js +399 -194
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/resources/skills/README.md +8 -3
- package/src/resources/skills/eatspot-discovery/DEBUG.md +71 -0
- package/src/resources/skills/eatspot-discovery/SKILL.md +6 -64
- package/src/resources/skills/manifest.json +3 -2
- package/dist/chunk-OAML6T2D.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
Logger,
|
|
4
4
|
PlacesSearcher
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-VCFXCLJF.js";
|
|
6
6
|
|
|
7
7
|
// src/cli.ts
|
|
8
8
|
import { config as dotenvConfig2 } from "dotenv";
|
|
@@ -13,75 +13,6 @@ import { hideBin } from "yargs/helpers";
|
|
|
13
13
|
// src/utils/configResolver.ts
|
|
14
14
|
import { config as dotenvConfig } from "dotenv";
|
|
15
15
|
import { existsSync } from "fs";
|
|
16
|
-
|
|
17
|
-
// src/utils/autoUpdate.ts
|
|
18
|
-
var AUTO_UPDATE_DISABLED_ENV = "MCP_AUTO_UPDATE_DISABLED";
|
|
19
|
-
var DEFAULT_PACKAGE_NAME = "mcp-google-map";
|
|
20
|
-
var DEFAULT_REGISTRY_BASE_URL = "https://registry.npmjs.org";
|
|
21
|
-
var DEFAULT_UPDATE_CHECK_TIMEOUT_MS = 2e3;
|
|
22
|
-
async function probeLatestVersion(deps = {}) {
|
|
23
|
-
const env = deps.env ?? process.env;
|
|
24
|
-
if (isAutoUpdateDisabled(env)) {
|
|
25
|
-
return { status: "disabled" };
|
|
26
|
-
}
|
|
27
|
-
const currentVersion = deps.currentVersion;
|
|
28
|
-
if (!currentVersion) {
|
|
29
|
-
return { status: "unknown-version" };
|
|
30
|
-
}
|
|
31
|
-
const packageName = deps.packageName ?? DEFAULT_PACKAGE_NAME;
|
|
32
|
-
const registryBaseUrl = deps.registryBaseUrl ?? DEFAULT_REGISTRY_BASE_URL;
|
|
33
|
-
const timeoutMs = deps.timeoutMs ?? DEFAULT_UPDATE_CHECK_TIMEOUT_MS;
|
|
34
|
-
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
35
|
-
try {
|
|
36
|
-
const response = await fetchImpl(`${registryBaseUrl}/${packageName}/latest`, {
|
|
37
|
-
headers: { accept: "application/json" },
|
|
38
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
39
|
-
});
|
|
40
|
-
if (!response.ok) {
|
|
41
|
-
return {
|
|
42
|
-
status: "error",
|
|
43
|
-
message: `registry responded with HTTP ${response.status}.`
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
const payload = await response.json();
|
|
47
|
-
if (typeof payload?.version !== "string") {
|
|
48
|
-
return {
|
|
49
|
-
status: "error",
|
|
50
|
-
message: "registry response has no version field."
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
if (!isNewerVersion(payload.version, currentVersion)) {
|
|
54
|
-
return { status: "current", currentVersion };
|
|
55
|
-
}
|
|
56
|
-
return { status: "newer", currentVersion, latestVersion: payload.version };
|
|
57
|
-
} catch (error) {
|
|
58
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
59
|
-
return { status: "error", message };
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function isAutoUpdateDisabled(env = process.env) {
|
|
63
|
-
const raw = env[AUTO_UPDATE_DISABLED_ENV];
|
|
64
|
-
return typeof raw === "string" && /^(1|true|yes)$/i.test(raw.trim());
|
|
65
|
-
}
|
|
66
|
-
function isNewerVersion(candidate, current) {
|
|
67
|
-
const toSegments = (version) => version.trim().split(".").map((segment) => /^\d+$/.test(segment) ? Number(segment) : Number.NaN);
|
|
68
|
-
const candidateSegments = toSegments(candidate);
|
|
69
|
-
const currentSegments = toSegments(current);
|
|
70
|
-
if (candidateSegments.some((segment) => !Number.isInteger(segment)) || currentSegments.some((segment) => !Number.isInteger(segment))) {
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
const length = Math.max(candidateSegments.length, currentSegments.length);
|
|
74
|
-
for (let index = 0; index < length; index += 1) {
|
|
75
|
-
const candidatePart = candidateSegments[index] ?? 0;
|
|
76
|
-
const currentPart = currentSegments[index] ?? 0;
|
|
77
|
-
if (candidatePart !== currentPart) {
|
|
78
|
-
return candidatePart > currentPart;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// src/utils/configResolver.ts
|
|
85
16
|
var NODE_ENGINE_FLOOR = 22;
|
|
86
17
|
var DEFAULT_HTTP_HOST = "127.0.0.1";
|
|
87
18
|
var DEFAULT_HTTP_PORT = 3e3;
|
|
@@ -116,7 +47,7 @@ function resolveRuntimeConfig(env = process.env, overrides = {}) {
|
|
|
116
47
|
portSource,
|
|
117
48
|
enabledToolsRaw,
|
|
118
49
|
enabledToolsSource: enabledToolsRaw ? "environment" : "default",
|
|
119
|
-
autoUpdateDisabled:
|
|
50
|
+
autoUpdateDisabled: overrides.autoUpdateDisabled === true,
|
|
120
51
|
envFile: overrides.envFile
|
|
121
52
|
};
|
|
122
53
|
}
|
|
@@ -178,10 +109,92 @@ import { z } from "zod";
|
|
|
178
109
|
|
|
179
110
|
// src/utils/requestContext.ts
|
|
180
111
|
import { AsyncLocalStorage } from "async_hooks";
|
|
112
|
+
|
|
113
|
+
// src/utils/apiKeyManager.ts
|
|
114
|
+
var ApiKeyManager = class _ApiKeyManager {
|
|
115
|
+
constructor() {
|
|
116
|
+
this.defaultApiKey = void 0;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* @brief Returns the process-wide singleton instance.
|
|
120
|
+
* @details Lazily constructs the manager; the default key starts unset and
|
|
121
|
+
* MUST be injected by the server-start path before serving requests.
|
|
122
|
+
* Complexity O(1).
|
|
123
|
+
* @return {ApiKeyManager} The singleton instance.
|
|
124
|
+
*/
|
|
125
|
+
static getInstance() {
|
|
126
|
+
if (!_ApiKeyManager.instance) {
|
|
127
|
+
_ApiKeyManager.instance = new _ApiKeyManager();
|
|
128
|
+
}
|
|
129
|
+
return _ApiKeyManager.instance;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* @brief Injects the startup default API key.
|
|
133
|
+
* @details Called by the server-start command with the key resolved from
|
|
134
|
+
* the persisted settings (REQ-142); undefined clears the default so
|
|
135
|
+
* requests without header/session keys resolve no key (REQ-018, DES-006).
|
|
136
|
+
* Pure in-memory mutation; no environment writes.
|
|
137
|
+
* @param key {string | undefined} Default key from the persisted settings; undefined clears it.
|
|
138
|
+
* @return {void}
|
|
139
|
+
* @satisfies DES-006, REQ-142
|
|
140
|
+
*/
|
|
141
|
+
setDefaultApiKey(key) {
|
|
142
|
+
this.defaultApiKey = key;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* @brief Resolves the effective API key for one request.
|
|
146
|
+
* @details Priority: `X-Google-Maps-API-Key` header, then `Authorization:
|
|
147
|
+
* Bearer` token, then the session key, then the injected default key
|
|
148
|
+
* (DES-005, REQ-016, REQ-017, REQ-018). Complexity O(1).
|
|
149
|
+
* @param req {Request | undefined} Incoming HTTP request; undefined skips header resolution.
|
|
150
|
+
* @param sessionApiKey {string | undefined} Session-scoped key; consulted before the default.
|
|
151
|
+
* @return {string | undefined} Effective key; undefined when nothing resolves.
|
|
152
|
+
* @satisfies DES-005, REQ-016, REQ-017, REQ-018
|
|
153
|
+
*/
|
|
154
|
+
getApiKey(req, sessionApiKey) {
|
|
155
|
+
if (req) {
|
|
156
|
+
const headerApiKey = req.headers["x-google-maps-api-key"];
|
|
157
|
+
if (headerApiKey) {
|
|
158
|
+
return headerApiKey;
|
|
159
|
+
}
|
|
160
|
+
const authHeader = req.headers["authorization"];
|
|
161
|
+
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
162
|
+
return authHeader.substring(7);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (sessionApiKey) {
|
|
166
|
+
return sessionApiKey;
|
|
167
|
+
}
|
|
168
|
+
return this.defaultApiKey;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* @brief Reports whether any API key is resolvable for a request.
|
|
172
|
+
* @details Delegates to `getApiKey` truthiness. Complexity O(1).
|
|
173
|
+
* @param req {Request | undefined} Incoming HTTP request.
|
|
174
|
+
* @param sessionApiKey {string | undefined} Session-scoped key.
|
|
175
|
+
* @return {boolean} True when a key resolves.
|
|
176
|
+
*/
|
|
177
|
+
hasApiKey(req, sessionApiKey) {
|
|
178
|
+
return !!this.getApiKey(req, sessionApiKey);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* @brief Validates the API key format.
|
|
182
|
+
* @details Accepts 20-50 characters of `[A-Za-z0-9_-]` (REQ-020). Pure;
|
|
183
|
+
* complexity O(n) in key length.
|
|
184
|
+
* @param key {string} Candidate key.
|
|
185
|
+
* @return {boolean} True when the format is valid.
|
|
186
|
+
* @satisfies REQ-020
|
|
187
|
+
*/
|
|
188
|
+
isValidApiKeyFormat(key) {
|
|
189
|
+
return /^[A-Za-z0-9_-]{20,50}$/.test(key);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// src/utils/requestContext.ts
|
|
181
194
|
var requestContextStorage = new AsyncLocalStorage();
|
|
182
195
|
function getCurrentApiKey() {
|
|
183
196
|
const context = requestContextStorage.getStore();
|
|
184
|
-
return context?.apiKey ||
|
|
197
|
+
return context?.apiKey || ApiKeyManager.getInstance().getApiKey();
|
|
185
198
|
}
|
|
186
199
|
function runWithContext(context, fn) {
|
|
187
200
|
return requestContextStorage.run(context, fn);
|
|
@@ -1210,62 +1223,6 @@ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
|
1210
1223
|
import express from "express";
|
|
1211
1224
|
import { randomUUID } from "crypto";
|
|
1212
1225
|
import { z as z19 } from "zod";
|
|
1213
|
-
|
|
1214
|
-
// src/utils/apiKeyManager.ts
|
|
1215
|
-
var ApiKeyManager = class _ApiKeyManager {
|
|
1216
|
-
constructor() {
|
|
1217
|
-
this.defaultApiKey = process.env.GOOGLE_MAPS_API_KEY;
|
|
1218
|
-
}
|
|
1219
|
-
static getInstance() {
|
|
1220
|
-
if (!_ApiKeyManager.instance) {
|
|
1221
|
-
_ApiKeyManager.instance = new _ApiKeyManager();
|
|
1222
|
-
}
|
|
1223
|
-
return _ApiKeyManager.instance;
|
|
1224
|
-
}
|
|
1225
|
-
/**
|
|
1226
|
-
* Set the default API key (from command line or environment)
|
|
1227
|
-
*/
|
|
1228
|
-
setDefaultApiKey(key) {
|
|
1229
|
-
this.defaultApiKey = key;
|
|
1230
|
-
process.env.GOOGLE_MAPS_API_KEY = key;
|
|
1231
|
-
}
|
|
1232
|
-
/**
|
|
1233
|
-
* Get API key with priority:
|
|
1234
|
-
* 1. HTTP Header (X-Google-Maps-API-Key or Authorization: Bearer)
|
|
1235
|
-
* 2. Session-specific API key
|
|
1236
|
-
* 3. Default API key (command line or environment)
|
|
1237
|
-
*/
|
|
1238
|
-
getApiKey(req, sessionApiKey) {
|
|
1239
|
-
if (req) {
|
|
1240
|
-
const headerApiKey = req.headers["x-google-maps-api-key"];
|
|
1241
|
-
if (headerApiKey) {
|
|
1242
|
-
return headerApiKey;
|
|
1243
|
-
}
|
|
1244
|
-
const authHeader = req.headers["authorization"];
|
|
1245
|
-
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
1246
|
-
return authHeader.substring(7);
|
|
1247
|
-
}
|
|
1248
|
-
}
|
|
1249
|
-
if (sessionApiKey) {
|
|
1250
|
-
return sessionApiKey;
|
|
1251
|
-
}
|
|
1252
|
-
return this.defaultApiKey;
|
|
1253
|
-
}
|
|
1254
|
-
/**
|
|
1255
|
-
* Check if any API key is available
|
|
1256
|
-
*/
|
|
1257
|
-
hasApiKey(req, sessionApiKey) {
|
|
1258
|
-
return !!this.getApiKey(req, sessionApiKey);
|
|
1259
|
-
}
|
|
1260
|
-
/**
|
|
1261
|
-
* Validate API key format (basic validation)
|
|
1262
|
-
*/
|
|
1263
|
-
isValidApiKeyFormat(key) {
|
|
1264
|
-
return /^[A-Za-z0-9_-]{20,50}$/.test(key);
|
|
1265
|
-
}
|
|
1266
|
-
};
|
|
1267
|
-
|
|
1268
|
-
// src/core/BaseMcpServer.ts
|
|
1269
1226
|
var VERSION = "0.0.1";
|
|
1270
1227
|
var BaseMcpServer = class {
|
|
1271
1228
|
constructor(name, tools) {
|
|
@@ -1443,7 +1400,7 @@ var BaseMcpServer = class {
|
|
|
1443
1400
|
|
|
1444
1401
|
// src/cli.ts
|
|
1445
1402
|
import { fileURLToPath } from "url";
|
|
1446
|
-
import { dirname as
|
|
1403
|
+
import { dirname as dirname3 } from "path";
|
|
1447
1404
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync4 } from "fs";
|
|
1448
1405
|
import { createInterface } from "readline";
|
|
1449
1406
|
|
|
@@ -1453,12 +1410,80 @@ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync a
|
|
|
1453
1410
|
import { homedir } from "os";
|
|
1454
1411
|
import { dirname, join as join2 } from "path";
|
|
1455
1412
|
|
|
1413
|
+
// src/utils/autoUpdate.ts
|
|
1414
|
+
var AUTO_UPDATE_DISABLED_ENV = "MCP_AUTO_UPDATE_DISABLED";
|
|
1415
|
+
var DEFAULT_PACKAGE_NAME = "mcp-google-map";
|
|
1416
|
+
var DEFAULT_REGISTRY_BASE_URL = "https://registry.npmjs.org";
|
|
1417
|
+
var DEFAULT_UPDATE_CHECK_TIMEOUT_MS = 2e3;
|
|
1418
|
+
async function probeLatestVersion(deps = {}) {
|
|
1419
|
+
const env = deps.env;
|
|
1420
|
+
if (env !== void 0 && isAutoUpdateDisabled(env)) {
|
|
1421
|
+
return { status: "disabled" };
|
|
1422
|
+
}
|
|
1423
|
+
const currentVersion = deps.currentVersion;
|
|
1424
|
+
if (!currentVersion) {
|
|
1425
|
+
return { status: "unknown-version" };
|
|
1426
|
+
}
|
|
1427
|
+
const packageName = deps.packageName ?? DEFAULT_PACKAGE_NAME;
|
|
1428
|
+
const registryBaseUrl = deps.registryBaseUrl ?? DEFAULT_REGISTRY_BASE_URL;
|
|
1429
|
+
const timeoutMs = deps.timeoutMs ?? DEFAULT_UPDATE_CHECK_TIMEOUT_MS;
|
|
1430
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
1431
|
+
try {
|
|
1432
|
+
const response = await fetchImpl(`${registryBaseUrl}/${packageName}/latest`, {
|
|
1433
|
+
headers: { accept: "application/json" },
|
|
1434
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
1435
|
+
});
|
|
1436
|
+
if (!response.ok) {
|
|
1437
|
+
return {
|
|
1438
|
+
status: "error",
|
|
1439
|
+
message: `registry responded with HTTP ${response.status}.`
|
|
1440
|
+
};
|
|
1441
|
+
}
|
|
1442
|
+
const payload = await response.json();
|
|
1443
|
+
if (typeof payload?.version !== "string") {
|
|
1444
|
+
return {
|
|
1445
|
+
status: "error",
|
|
1446
|
+
message: "registry response has no version field."
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
if (!isNewerVersion(payload.version, currentVersion)) {
|
|
1450
|
+
return { status: "current", currentVersion };
|
|
1451
|
+
}
|
|
1452
|
+
return { status: "newer", currentVersion, latestVersion: payload.version };
|
|
1453
|
+
} catch (error) {
|
|
1454
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1455
|
+
return { status: "error", message };
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
function isAutoUpdateDisabled(env = process.env) {
|
|
1459
|
+
const raw = env[AUTO_UPDATE_DISABLED_ENV];
|
|
1460
|
+
return typeof raw === "string" && /^(1|true|yes)$/i.test(raw.trim());
|
|
1461
|
+
}
|
|
1462
|
+
function isNewerVersion(candidate, current) {
|
|
1463
|
+
const toSegments = (version) => version.trim().split(".").map((segment) => /^\d+$/.test(segment) ? Number(segment) : Number.NaN);
|
|
1464
|
+
const candidateSegments = toSegments(candidate);
|
|
1465
|
+
const currentSegments = toSegments(current);
|
|
1466
|
+
if (candidateSegments.some((segment) => !Number.isInteger(segment)) || currentSegments.some((segment) => !Number.isInteger(segment))) {
|
|
1467
|
+
return false;
|
|
1468
|
+
}
|
|
1469
|
+
const length = Math.max(candidateSegments.length, currentSegments.length);
|
|
1470
|
+
for (let index = 0; index < length; index += 1) {
|
|
1471
|
+
const candidatePart = candidateSegments[index] ?? 0;
|
|
1472
|
+
const currentPart = currentSegments[index] ?? 0;
|
|
1473
|
+
if (candidatePart !== currentPart) {
|
|
1474
|
+
return candidatePart > currentPart;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
return false;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1456
1480
|
// src/utils/cliSettings.ts
|
|
1457
1481
|
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
|
|
1458
1482
|
import { join, resolve } from "path";
|
|
1459
1483
|
var SETTINGS_PROGRAM_NAME = "mcp-google-map";
|
|
1460
1484
|
var CLI_SETTINGS_RELATIVE = [".config", SETTINGS_PROGRAM_NAME, "config.json"];
|
|
1461
1485
|
var MCP_SERVER_NAME = "mcp-google-map";
|
|
1486
|
+
var INSTALL_API_KEY_PLACEHOLDER = "__RUN_mcp-google-map_api-key_TO_CONFIGURE_YOUR_API_KEY__";
|
|
1462
1487
|
function resolveCliSettingsPath(home) {
|
|
1463
1488
|
const root = home ?? (process.env.HOME ?? process.cwd());
|
|
1464
1489
|
return resolve(root, ...CLI_SETTINGS_RELATIVE);
|
|
@@ -1473,23 +1498,40 @@ function uniqueStrings(value) {
|
|
|
1473
1498
|
}
|
|
1474
1499
|
return result;
|
|
1475
1500
|
}
|
|
1501
|
+
function isUnsetApiKey(value) {
|
|
1502
|
+
return value === void 0 || value === null || value.trim().length === 0 || value === INSTALL_API_KEY_PLACEHOLDER;
|
|
1503
|
+
}
|
|
1476
1504
|
function loadCliSettings(home) {
|
|
1477
1505
|
try {
|
|
1478
1506
|
const raw = JSON.parse(readFileSync(resolveCliSettingsPath(home), "utf-8"));
|
|
1479
1507
|
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
1480
|
-
return { enabled: [] };
|
|
1508
|
+
return { enabled: [], apiKey: "", autoUpdate: true };
|
|
1481
1509
|
}
|
|
1482
|
-
|
|
1510
|
+
const record = raw;
|
|
1511
|
+
return {
|
|
1512
|
+
enabled: uniqueStrings(record.enabled),
|
|
1513
|
+
apiKey: typeof record.apiKey === "string" ? record.apiKey : "",
|
|
1514
|
+
autoUpdate: typeof record.autoUpdate === "boolean" ? record.autoUpdate : true
|
|
1515
|
+
};
|
|
1483
1516
|
} catch {
|
|
1484
|
-
return { enabled: [] };
|
|
1517
|
+
return { enabled: [], apiKey: "", autoUpdate: true };
|
|
1485
1518
|
}
|
|
1486
1519
|
}
|
|
1520
|
+
function loadConfiguredApiKey(home) {
|
|
1521
|
+
const apiKey = loadCliSettings(home).apiKey;
|
|
1522
|
+
return isUnsetApiKey(apiKey) ? void 0 : apiKey;
|
|
1523
|
+
}
|
|
1487
1524
|
function saveCliSettings(settings, home) {
|
|
1488
1525
|
const path = resolveCliSettingsPath(home);
|
|
1489
1526
|
const temporary = `${path}.tmp`;
|
|
1527
|
+
const payload = {
|
|
1528
|
+
enabled: uniqueStrings(settings.enabled),
|
|
1529
|
+
apiKey: typeof settings.apiKey === "string" ? settings.apiKey : "",
|
|
1530
|
+
autoUpdate: settings.autoUpdate === true
|
|
1531
|
+
};
|
|
1490
1532
|
try {
|
|
1491
1533
|
mkdirSync(join(path, ".."), { recursive: true });
|
|
1492
|
-
writeFileSync(temporary, JSON.stringify(
|
|
1534
|
+
writeFileSync(temporary, JSON.stringify(payload, null, 2) + "\n", "utf-8");
|
|
1493
1535
|
renameSync(temporary, path);
|
|
1494
1536
|
} catch (error) {
|
|
1495
1537
|
throw new Error(`settings write failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -1772,7 +1814,22 @@ async function runVersionCommand(options, deps = {}) {
|
|
|
1772
1814
|
`);
|
|
1773
1815
|
return 0;
|
|
1774
1816
|
}
|
|
1817
|
+
function isUpgradeNecessary(status) {
|
|
1818
|
+
return status !== "current";
|
|
1819
|
+
}
|
|
1775
1820
|
async function runUpgradeCommand(options, deps = {}) {
|
|
1821
|
+
const precheck = await probeLatestVersion({
|
|
1822
|
+
...deps.idleCheck,
|
|
1823
|
+
currentVersion: options.currentVersion
|
|
1824
|
+
});
|
|
1825
|
+
if (!isUpgradeNecessary(precheck.status)) {
|
|
1826
|
+
const stdout2 = deps.stdout ?? process.stdout;
|
|
1827
|
+
stdout2.write(
|
|
1828
|
+
`${DEFAULT_PACKAGE_NAME} ${options.currentVersion} is already the latest available version.
|
|
1829
|
+
`
|
|
1830
|
+
);
|
|
1831
|
+
return 0;
|
|
1832
|
+
}
|
|
1776
1833
|
const upgraded = runPackageManagerCommand(PACKAGE_UPGRADE_COMMAND, deps);
|
|
1777
1834
|
if (upgraded !== 0) {
|
|
1778
1835
|
return upgraded;
|
|
@@ -1920,6 +1977,7 @@ function renderClientSnippet(options = {}) {
|
|
|
1920
1977
|
|
|
1921
1978
|
// src/utils/cliTargets.ts
|
|
1922
1979
|
import {
|
|
1980
|
+
appendFileSync,
|
|
1923
1981
|
cpSync,
|
|
1924
1982
|
existsSync as existsSync2,
|
|
1925
1983
|
mkdirSync as mkdirSync3,
|
|
@@ -2114,30 +2172,46 @@ function listFilesRecursive(root) {
|
|
|
2114
2172
|
walk(root);
|
|
2115
2173
|
return files;
|
|
2116
2174
|
}
|
|
2117
|
-
|
|
2175
|
+
var SKILL_DOCUMENT_FILE = "SKILL.md";
|
|
2176
|
+
function syncSkillTree(source, destination, layout = {}) {
|
|
2118
2177
|
mkdirSync3(destination, { recursive: true });
|
|
2119
|
-
cpSync(source, destination, {
|
|
2120
|
-
|
|
2178
|
+
cpSync(source, destination, {
|
|
2179
|
+
recursive: true,
|
|
2180
|
+
force: true,
|
|
2181
|
+
filter: (entry) => layout.debugPath === void 0 || relative(source, entry).split("\\").join("/") !== layout.debugPath
|
|
2182
|
+
});
|
|
2183
|
+
const expected = new Set(listFilesRecursive(source).filter((rel) => rel !== layout.debugPath));
|
|
2121
2184
|
const existing = listFilesRecursive(destination);
|
|
2122
2185
|
existing.sort((a, b) => b.length - a.length);
|
|
2123
2186
|
for (const rel of existing) {
|
|
2124
2187
|
if (expected.has(rel)) continue;
|
|
2125
2188
|
rmSync(join3(destination, rel), { recursive: true, force: true });
|
|
2126
2189
|
}
|
|
2190
|
+
if (layout.includeDebug === true && layout.debugPath !== void 0) {
|
|
2191
|
+
appendFileSync(
|
|
2192
|
+
join3(destination, ...SKILL_DOCUMENT_FILE.split("/")),
|
|
2193
|
+
readFileSync3(join3(source, ...layout.debugPath.split("/")))
|
|
2194
|
+
);
|
|
2195
|
+
}
|
|
2127
2196
|
}
|
|
2128
2197
|
function removeSkillDir(skillDir) {
|
|
2129
2198
|
rmSync(skillDir, { recursive: true, force: true });
|
|
2130
2199
|
}
|
|
2131
|
-
function compareSkillTree(source, destination) {
|
|
2132
|
-
const packaged = listFilesRecursive(source);
|
|
2200
|
+
function compareSkillTree(source, destination, layout = {}) {
|
|
2201
|
+
const packaged = listFilesRecursive(source).filter((rel) => rel !== layout.debugPath);
|
|
2133
2202
|
if (packaged.length === 0) return "MISSING";
|
|
2134
2203
|
if (!existsSync2(destination)) return "MISSING";
|
|
2135
2204
|
for (const rel of packaged) {
|
|
2136
2205
|
const target = join3(destination, ...rel.split("/"));
|
|
2137
2206
|
if (!existsSync2(target)) return "MISSING";
|
|
2138
|
-
|
|
2139
|
-
|
|
2207
|
+
const packagedText = readFileSync3(join3(source, ...rel.split("/"))).toString("utf-8");
|
|
2208
|
+
const installedText = readFileSync3(target).toString("utf-8");
|
|
2209
|
+
if (installedText === packagedText) continue;
|
|
2210
|
+
if (rel === SKILL_DOCUMENT_FILE && layout.debugPath !== void 0) {
|
|
2211
|
+
const overlayText = readFileSync3(join3(source, ...layout.debugPath.split("/"))).toString("utf-8");
|
|
2212
|
+
if (installedText === packagedText + overlayText) continue;
|
|
2140
2213
|
}
|
|
2214
|
+
return "STALE";
|
|
2141
2215
|
}
|
|
2142
2216
|
return "OK";
|
|
2143
2217
|
}
|
|
@@ -2167,13 +2241,9 @@ function applyServerRegistration(target, serverName, entry, home) {
|
|
|
2167
2241
|
|
|
2168
2242
|
// src/utils/cliInstaller.ts
|
|
2169
2243
|
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
|
|
2170
|
-
import { join as join4, resolve as resolve3 } from "path";
|
|
2171
|
-
function buildServerRegistration(
|
|
2172
|
-
|
|
2173
|
-
if (apiKey !== void 0 && apiKey.length > 0) {
|
|
2174
|
-
env.GOOGLE_MAPS_API_KEY = apiKey;
|
|
2175
|
-
}
|
|
2176
|
-
return { command: "npx", args: ["-y", MCP_SERVER_NAME, "start", "--stdio"], env };
|
|
2244
|
+
import { dirname as dirname2, join as join4, resolve as resolve3 } from "path";
|
|
2245
|
+
function buildServerRegistration() {
|
|
2246
|
+
return { command: "npx", args: ["-y", MCP_SERVER_NAME, "start", "--stdio"] };
|
|
2177
2247
|
}
|
|
2178
2248
|
function resolveSkillsResourcesRoot(packageRoot) {
|
|
2179
2249
|
const candidate = resolve3(packageRoot, "src", "resources", "skills");
|
|
@@ -2202,21 +2272,36 @@ function loadSkillsManifest(resourcesRoot) {
|
|
|
2202
2272
|
if (typeof skill.id !== "string" || typeof skill.path !== "string") {
|
|
2203
2273
|
throw new Error(`skills manifest entry is missing id or path: ${manifestPath}`);
|
|
2204
2274
|
}
|
|
2205
|
-
|
|
2206
|
-
|
|
2275
|
+
const skillFile = join4(resourcesRoot, skill.path);
|
|
2276
|
+
if (!existsSync3(skillFile)) {
|
|
2277
|
+
throw new Error(`manifest skill file not found: ${skillFile}`);
|
|
2278
|
+
}
|
|
2279
|
+
if (skill.debug !== void 0 && (typeof skill.debug !== "string" || skill.debug.trim() === "")) {
|
|
2280
|
+
throw new Error(`manifest skill debug path is invalid: ${manifestPath}`);
|
|
2281
|
+
}
|
|
2282
|
+
const debugPath = typeof skill.debug === "string" ? skill.debug : void 0;
|
|
2283
|
+
if (debugPath !== void 0 && !existsSync3(join4(dirname2(resolve3(skillFile)), debugPath))) {
|
|
2284
|
+
throw new Error(`manifest skill debug file not found: ${join4(dirname2(resolve3(skillFile)), debugPath)}`);
|
|
2207
2285
|
}
|
|
2208
2286
|
return {
|
|
2209
2287
|
id: skill.id,
|
|
2210
2288
|
name: skill.name ?? skill.id,
|
|
2211
2289
|
version: skill.version ?? "",
|
|
2212
2290
|
path: skill.path,
|
|
2213
|
-
description: skill.description ?? ""
|
|
2291
|
+
description: skill.description ?? "",
|
|
2292
|
+
...debugPath === void 0 ? {} : { debugPath }
|
|
2214
2293
|
};
|
|
2215
2294
|
});
|
|
2216
2295
|
}
|
|
2296
|
+
function resolveSkillContentLayout(skill, includeDebug) {
|
|
2297
|
+
return {
|
|
2298
|
+
...skill.debugPath === void 0 ? {} : { debugPath: skill.debugPath },
|
|
2299
|
+
includeDebug: includeDebug && skill.debugPath !== void 0
|
|
2300
|
+
};
|
|
2301
|
+
}
|
|
2217
2302
|
function installEnabledCliResources(options) {
|
|
2218
2303
|
const manifest = loadSkillsManifest(options.resourcesRoot);
|
|
2219
|
-
const entry = buildServerRegistration(
|
|
2304
|
+
const entry = buildServerRegistration();
|
|
2220
2305
|
const result = { summaries: [], errors: [] };
|
|
2221
2306
|
for (const cli of loadCliSettings(options.home).enabled) {
|
|
2222
2307
|
const target = CLI_TARGETS[cli];
|
|
@@ -2228,7 +2313,11 @@ function installEnabledCliResources(options) {
|
|
|
2228
2313
|
applyServerRegistration(target, MCP_SERVER_NAME, entry, options.home);
|
|
2229
2314
|
let skills = 0;
|
|
2230
2315
|
for (const skill of manifest) {
|
|
2231
|
-
syncSkillTree(
|
|
2316
|
+
syncSkillTree(
|
|
2317
|
+
join4(options.resourcesRoot, skill.id),
|
|
2318
|
+
join4(target.skillsDir(options.home), skill.id),
|
|
2319
|
+
resolveSkillContentLayout(skill, options.includeDebugSkills === true)
|
|
2320
|
+
);
|
|
2232
2321
|
skills += 1;
|
|
2233
2322
|
}
|
|
2234
2323
|
result.summaries.push({ cli: target.id, server: 1, skills });
|
|
@@ -2350,7 +2439,9 @@ function buildInstallRows(home, resourcesRoot) {
|
|
|
2350
2439
|
skill.id,
|
|
2351
2440
|
target.id,
|
|
2352
2441
|
"yes",
|
|
2353
|
-
compareSkillTree(join5(resourcesRoot, skill.id), join5(target.skillsDir(home), skill.id)
|
|
2442
|
+
compareSkillTree(join5(resourcesRoot, skill.id), join5(target.skillsDir(home), skill.id), {
|
|
2443
|
+
...skill.debugPath === void 0 ? {} : { debugPath: skill.debugPath }
|
|
2444
|
+
})
|
|
2354
2445
|
]);
|
|
2355
2446
|
}
|
|
2356
2447
|
}
|
|
@@ -2368,7 +2459,7 @@ function buildCliShowReport(options) {
|
|
|
2368
2459
|
|
|
2369
2460
|
// src/cli.ts
|
|
2370
2461
|
var __filename = fileURLToPath(import.meta.url);
|
|
2371
|
-
var __dirname =
|
|
2462
|
+
var __dirname = dirname3(__filename);
|
|
2372
2463
|
function extractEnvFileOption(argv) {
|
|
2373
2464
|
for (let i = 0; i < argv.length; i++) {
|
|
2374
2465
|
const arg = argv[i];
|
|
@@ -2397,9 +2488,7 @@ async function startServer(port, apiKey, host) {
|
|
|
2397
2488
|
if (port) {
|
|
2398
2489
|
process.env.MCP_SERVER_PORT = port.toString();
|
|
2399
2490
|
}
|
|
2400
|
-
|
|
2401
|
-
process.env.GOOGLE_MAPS_API_KEY = apiKey;
|
|
2402
|
-
}
|
|
2491
|
+
ApiKeyManager.getInstance().setDefaultApiKey(apiKey);
|
|
2403
2492
|
if (host) {
|
|
2404
2493
|
process.env.MCP_SERVER_HOST = host;
|
|
2405
2494
|
}
|
|
@@ -2874,6 +2963,80 @@ function runEnableDisableCliCommand(name, enable, options = {}) {
|
|
|
2874
2963
|
);
|
|
2875
2964
|
return 0;
|
|
2876
2965
|
}
|
|
2966
|
+
function runApiKeyCommand(key, options) {
|
|
2967
|
+
const streams = options.streams ?? { stdout: process.stdout, stderr: process.stderr };
|
|
2968
|
+
const trimmed = (key ?? "").trim();
|
|
2969
|
+
if (!ApiKeyManager.getInstance().isValidApiKeyFormat(trimmed)) {
|
|
2970
|
+
streams.stderr.write(
|
|
2971
|
+
"api-key: invalid Google Maps API key. Expected 20-50 characters of letters, digits, hyphens, or underscores.\nUsage: mcp-google-map api-key <your-api-key>\n"
|
|
2972
|
+
);
|
|
2973
|
+
return 1;
|
|
2974
|
+
}
|
|
2975
|
+
try {
|
|
2976
|
+
const settings = loadCliSettings(options.home);
|
|
2977
|
+
settings.apiKey = trimmed;
|
|
2978
|
+
saveCliSettings(settings, options.home);
|
|
2979
|
+
} catch (error) {
|
|
2980
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2981
|
+
streams.stderr.write(`api-key: failed to persist the API key: ${message}
|
|
2982
|
+
`);
|
|
2983
|
+
return 1;
|
|
2984
|
+
}
|
|
2985
|
+
streams.stdout.write(`API key configured (${maskSecret(trimmed)}).
|
|
2986
|
+
`);
|
|
2987
|
+
let install;
|
|
2988
|
+
try {
|
|
2989
|
+
install = installEnabledCliResources({ home: options.home, resourcesRoot: options.resourcesRoot });
|
|
2990
|
+
} catch (error) {
|
|
2991
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2992
|
+
streams.stderr.write(`api-key: install failed: ${message}
|
|
2993
|
+
`);
|
|
2994
|
+
return 1;
|
|
2995
|
+
}
|
|
2996
|
+
if (install.summaries.length === 0 && install.errors.length === 0) {
|
|
2997
|
+
streams.stdout.write("No CLI agent enabled. Run 'mcp-google-map enable <cli name>' first.\n");
|
|
2998
|
+
return 0;
|
|
2999
|
+
}
|
|
3000
|
+
for (const summary of install.summaries) {
|
|
3001
|
+
streams.stdout.write(
|
|
3002
|
+
`${summary.cli}: MCP connector installed (server entries: ${summary.server}, skills: ${summary.skills}).
|
|
3003
|
+
`
|
|
3004
|
+
);
|
|
3005
|
+
}
|
|
3006
|
+
for (const error of install.errors) {
|
|
3007
|
+
streams.stdout.write(`${error}
|
|
3008
|
+
`);
|
|
3009
|
+
}
|
|
3010
|
+
return install.errors.length > 0 ? 1 : 0;
|
|
3011
|
+
}
|
|
3012
|
+
function runAutoUpdateCommand(rawState, options = {}) {
|
|
3013
|
+
const streams = options.streams ?? { stdout: process.stdout, stderr: process.stderr };
|
|
3014
|
+
const normalized = (rawState ?? "").trim().toLowerCase();
|
|
3015
|
+
let enabled;
|
|
3016
|
+
if (normalized === "enable" || normalized === "1") {
|
|
3017
|
+
enabled = true;
|
|
3018
|
+
} else if (normalized === "disable" || normalized === "0") {
|
|
3019
|
+
enabled = false;
|
|
3020
|
+
} else {
|
|
3021
|
+
streams.stderr.write(
|
|
3022
|
+
`auto-update: invalid value "${rawState ?? ""}". Accepted values: enable, disable, 1, 0.
|
|
3023
|
+
`
|
|
3024
|
+
);
|
|
3025
|
+
return 1;
|
|
3026
|
+
}
|
|
3027
|
+
try {
|
|
3028
|
+
const settings = loadCliSettings(options.home);
|
|
3029
|
+
settings.autoUpdate = enabled;
|
|
3030
|
+
saveCliSettings(settings, options.home);
|
|
3031
|
+
} catch (error) {
|
|
3032
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3033
|
+
streams.stderr.write(`auto-update: failed to persist the setting: ${message}
|
|
3034
|
+
`);
|
|
3035
|
+
return 1;
|
|
3036
|
+
}
|
|
3037
|
+
streams.stdout.write(enabled ? "Auto-update check enabled.\n" : "Auto-update check disabled.\n");
|
|
3038
|
+
return 0;
|
|
3039
|
+
}
|
|
2877
3040
|
function runInstallUninstallCommand(operation, options) {
|
|
2878
3041
|
const streams = options.streams ?? { stdout: process.stdout, stderr: process.stderr };
|
|
2879
3042
|
if (loadCliSettings(options.home).enabled.length === 0) {
|
|
@@ -2893,7 +3056,11 @@ function runInstallUninstallCommand(operation, options) {
|
|
|
2893
3056
|
}
|
|
2894
3057
|
let result;
|
|
2895
3058
|
try {
|
|
2896
|
-
result = operation === "install" ? installEnabledCliResources({
|
|
3059
|
+
result = operation === "install" ? installEnabledCliResources({
|
|
3060
|
+
home: options.home,
|
|
3061
|
+
resourcesRoot: options.resourcesRoot,
|
|
3062
|
+
includeDebugSkills: options.includeDebugSkills === true
|
|
3063
|
+
}) : uninstallEnabledCliResources({ home: options.home, resourcesRoot: options.resourcesRoot });
|
|
2897
3064
|
} catch (error) {
|
|
2898
3065
|
streams.stderr.write(
|
|
2899
3066
|
JSON.stringify({ success: false, errors: [error instanceof Error ? error.message : String(error)] }, null, 2) + "\n"
|
|
@@ -2948,41 +3115,49 @@ if (isRunDirectly || isMainModule) {
|
|
|
2948
3115
|
type: "string",
|
|
2949
3116
|
description: "Hostname to bind the server to (default 127.0.0.1 loopback; 0.0.0.0 for all interfaces)",
|
|
2950
3117
|
default: process.env.MCP_SERVER_HOST || "127.0.0.1"
|
|
2951
|
-
}).option("apikey", {
|
|
2952
|
-
alias: "k",
|
|
2953
|
-
type: "string",
|
|
2954
|
-
description: "Google Maps API key",
|
|
2955
|
-
default: process.env.GOOGLE_MAPS_API_KEY
|
|
2956
3118
|
}).option("stdio", {
|
|
2957
3119
|
type: "boolean",
|
|
2958
3120
|
description: "Use stdio transport instead of HTTP",
|
|
2959
3121
|
default: false
|
|
2960
3122
|
}).example([
|
|
2961
3123
|
["$0 start", "Start HTTP server with default settings"],
|
|
2962
|
-
['$0 start --port 3000 --apikey "your_api_key"', "Start HTTP with custom port and API key"],
|
|
2963
3124
|
["$0 start --host 0.0.0.0 --port 3000", "Start HTTP accessible from all interfaces"],
|
|
2964
3125
|
["$0 start --stdio", "Start in stdio mode (for MCP clients)"],
|
|
2965
3126
|
["$0 run --stdio", "Alias: run the server in stdio mode"]
|
|
2966
3127
|
]);
|
|
2967
3128
|
const runServerCommand = async (argv) => {
|
|
2968
|
-
|
|
2969
|
-
|
|
3129
|
+
const effectiveApiKey = loadConfiguredApiKey();
|
|
3130
|
+
ApiKeyManager.getInstance().setDefaultApiKey(effectiveApiKey);
|
|
3131
|
+
if (loadCliSettings().autoUpdate) {
|
|
3132
|
+
void checkVersionIdle({ currentVersion: packageVersion }).catch(() => void 0);
|
|
2970
3133
|
}
|
|
2971
|
-
void checkVersionIdle({ currentVersion: packageVersion }).catch(() => void 0);
|
|
2972
3134
|
const tools = filterTools(config_default[0].tools);
|
|
2973
3135
|
if (argv.stdio) {
|
|
3136
|
+
if (effectiveApiKey === void 0) {
|
|
3137
|
+
process.stderr.write(
|
|
3138
|
+
JSON.stringify(
|
|
3139
|
+
{
|
|
3140
|
+
error: "Google Maps API key is not configured. Run 'mcp-google-map api-key <your-api-key>' to configure it."
|
|
3141
|
+
},
|
|
3142
|
+
null,
|
|
3143
|
+
2
|
|
3144
|
+
) + "\n"
|
|
3145
|
+
);
|
|
3146
|
+
process.exitCode = 1;
|
|
3147
|
+
return;
|
|
3148
|
+
}
|
|
2974
3149
|
const server = new BaseMcpServer(config_default[0].name, tools);
|
|
2975
3150
|
await server.startStdio();
|
|
2976
3151
|
} else {
|
|
2977
3152
|
Logger.log("\u{1F5FA}\uFE0F Google Maps MCP Server");
|
|
2978
3153
|
Logger.log(" A Model Context Protocol server for Google Maps services");
|
|
2979
3154
|
Logger.log("");
|
|
2980
|
-
if (
|
|
3155
|
+
if (effectiveApiKey === void 0) {
|
|
2981
3156
|
Logger.log("\u26A0\uFE0F Google Maps API Key not found!");
|
|
2982
|
-
Logger.log("
|
|
3157
|
+
Logger.log(" Run 'mcp-google-map api-key <your-api-key>' to configure it.");
|
|
2983
3158
|
Logger.log("");
|
|
2984
3159
|
}
|
|
2985
|
-
startServer(argv.port,
|
|
3160
|
+
startServer(argv.port, effectiveApiKey, argv.host).then((outcome) => {
|
|
2986
3161
|
if (outcome.started === 0) {
|
|
2987
3162
|
process.exit(1);
|
|
2988
3163
|
}
|
|
@@ -3138,23 +3313,59 @@ Usage: mcp-google-map <command> [options]
|
|
|
3138
3313
|
home: argv.home
|
|
3139
3314
|
});
|
|
3140
3315
|
}
|
|
3316
|
+
).command(
|
|
3317
|
+
"auto-update <state>",
|
|
3318
|
+
"Enable or disable the automatic update check in the persisted configuration",
|
|
3319
|
+
(yargs2) => yargs2.positional("state", {
|
|
3320
|
+
type: "string",
|
|
3321
|
+
describe: "New state: enable or disable (1 and 0 accepted)"
|
|
3322
|
+
}).option("home", {
|
|
3323
|
+
type: "string",
|
|
3324
|
+
description: "Home-directory override for the settings file (default: user home)"
|
|
3325
|
+
}).example([[
|
|
3326
|
+
"$0 auto-update disable",
|
|
3327
|
+
"Disable the automatic update check in the persisted configuration"
|
|
3328
|
+
]]),
|
|
3329
|
+
(argv) => {
|
|
3330
|
+
process.exitCode = runAutoUpdateCommand(argv.state, {
|
|
3331
|
+
home: argv.home
|
|
3332
|
+
});
|
|
3333
|
+
}
|
|
3334
|
+
).command(
|
|
3335
|
+
"api-key <key>",
|
|
3336
|
+
"Save the Google Maps API key in the user settings and refresh every enabled CLI registration",
|
|
3337
|
+
(yargs2) => yargs2.positional("key", {
|
|
3338
|
+
type: "string",
|
|
3339
|
+
describe: "Google Maps API key (20-50 characters: letters, digits, hyphens, underscores)"
|
|
3340
|
+
}).option("home", {
|
|
3341
|
+
type: "string",
|
|
3342
|
+
description: "Home-directory override for CLI configuration paths (default: user home)"
|
|
3343
|
+
}).example([["$0 api-key AIzaSy...", "Save the key and reinstall every enabled CLI"]]),
|
|
3344
|
+
(argv) => {
|
|
3345
|
+
process.exitCode = runApiKeyCommand(argv.key, {
|
|
3346
|
+
home: argv.home,
|
|
3347
|
+
resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, ".."))
|
|
3348
|
+
});
|
|
3349
|
+
}
|
|
3141
3350
|
).command(
|
|
3142
3351
|
"install",
|
|
3143
3352
|
"Register the mcp-google-map stdio server and install packaged skills for every enabled CLI",
|
|
3144
3353
|
(yargs2) => yargs2.option("home", {
|
|
3145
3354
|
type: "string",
|
|
3146
3355
|
description: "Home-directory override for CLI configuration paths (default: user home)"
|
|
3147
|
-
}).option("
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3356
|
+
}).option("debug-skills", {
|
|
3357
|
+
type: "boolean",
|
|
3358
|
+
description: "Append each skill's packaged debug overlay to the installed SKILL.md",
|
|
3359
|
+
default: false
|
|
3360
|
+
}).example([
|
|
3361
|
+
["$0 install", "Register the server and skills in every enabled CLI"],
|
|
3362
|
+
["$0 install --debug-skills", "Also append the packaged debug overlay to every installed skill"]
|
|
3363
|
+
]),
|
|
3153
3364
|
(argv) => {
|
|
3154
3365
|
process.exitCode = runInstallUninstallCommand("install", {
|
|
3155
3366
|
home: argv.home,
|
|
3156
|
-
|
|
3157
|
-
|
|
3367
|
+
resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, "..")),
|
|
3368
|
+
includeDebugSkills: argv.debugSkills === true
|
|
3158
3369
|
});
|
|
3159
3370
|
}
|
|
3160
3371
|
).command(
|
|
@@ -3193,11 +3404,6 @@ Usage: mcp-google-map <command> [options]
|
|
|
3193
3404
|
}).positional("params", {
|
|
3194
3405
|
type: "string",
|
|
3195
3406
|
describe: "JSON parameters string"
|
|
3196
|
-
}).option("apikey", {
|
|
3197
|
-
alias: "k",
|
|
3198
|
-
type: "string",
|
|
3199
|
-
description: "Google Maps API key",
|
|
3200
|
-
default: process.env.GOOGLE_MAPS_API_KEY
|
|
3201
3407
|
}).example([
|
|
3202
3408
|
[`$0 exec geocode '{"address":"Tokyo Tower"}'`, "Geocode an address"],
|
|
3203
3409
|
[
|
|
@@ -3208,11 +3414,12 @@ Usage: mcp-google-map <command> [options]
|
|
|
3208
3414
|
]);
|
|
3209
3415
|
},
|
|
3210
3416
|
async (argv) => {
|
|
3211
|
-
|
|
3417
|
+
const apiKey = loadConfiguredApiKey();
|
|
3418
|
+
if (!apiKey) {
|
|
3212
3419
|
process.stderr.write(
|
|
3213
3420
|
JSON.stringify(
|
|
3214
3421
|
{
|
|
3215
|
-
error: "
|
|
3422
|
+
error: "Google Maps API key is not configured. Run 'mcp-google-map api-key <your-api-key>' to configure it."
|
|
3216
3423
|
},
|
|
3217
3424
|
null,
|
|
3218
3425
|
2
|
|
@@ -3223,7 +3430,7 @@ Usage: mcp-google-map <command> [options]
|
|
|
3223
3430
|
}
|
|
3224
3431
|
try {
|
|
3225
3432
|
const params = argv.params ? JSON.parse(argv.params) : {};
|
|
3226
|
-
process.exitCode = await runExecCommand(argv.tool, params,
|
|
3433
|
+
process.exitCode = await runExecCommand(argv.tool, params, apiKey);
|
|
3227
3434
|
} catch (error) {
|
|
3228
3435
|
process.stderr.write(JSON.stringify({ error: error.message }, null, 2) + "\n");
|
|
3229
3436
|
process.exitCode = 1;
|
|
@@ -3247,11 +3454,6 @@ Usage: mcp-google-map <command> [options]
|
|
|
3247
3454
|
type: "number",
|
|
3248
3455
|
describe: "Max parallel requests",
|
|
3249
3456
|
default: 20
|
|
3250
|
-
}).option("apikey", {
|
|
3251
|
-
alias: "k",
|
|
3252
|
-
type: "string",
|
|
3253
|
-
description: "Google Maps API key",
|
|
3254
|
-
default: process.env.GOOGLE_MAPS_API_KEY
|
|
3255
3457
|
}).example([
|
|
3256
3458
|
["$0 batch-geocode -i addresses.txt", "Geocode to stdout"],
|
|
3257
3459
|
["$0 batch-geocode -i addresses.txt -o results.json", "Geocode to file"],
|
|
@@ -3259,8 +3461,9 @@ Usage: mcp-google-map <command> [options]
|
|
|
3259
3461
|
]);
|
|
3260
3462
|
},
|
|
3261
3463
|
async (argv) => {
|
|
3262
|
-
|
|
3263
|
-
|
|
3464
|
+
const apiKey = loadConfiguredApiKey();
|
|
3465
|
+
if (!apiKey) {
|
|
3466
|
+
console.error("Error: Google Maps API key is not configured. Run 'mcp-google-map api-key <your-api-key>'.");
|
|
3264
3467
|
process.exit(1);
|
|
3265
3468
|
}
|
|
3266
3469
|
let lines;
|
|
@@ -3282,7 +3485,7 @@ Usage: mcp-google-map <command> [options]
|
|
|
3282
3485
|
console.error("Error: No addresses found in input.");
|
|
3283
3486
|
process.exit(1);
|
|
3284
3487
|
}
|
|
3285
|
-
const searcher = new PlacesSearcher(
|
|
3488
|
+
const searcher = new PlacesSearcher(apiKey);
|
|
3286
3489
|
const concurrency = Math.min(Math.max(argv.concurrency, 1), 50);
|
|
3287
3490
|
const results = [];
|
|
3288
3491
|
let completed = 0;
|
|
@@ -3365,6 +3568,8 @@ export {
|
|
|
3365
3568
|
extractEnvFileOption,
|
|
3366
3569
|
installShutdownHandlers,
|
|
3367
3570
|
parseDoctorProbes,
|
|
3571
|
+
runApiKeyCommand,
|
|
3572
|
+
runAutoUpdateCommand,
|
|
3368
3573
|
runDoctor,
|
|
3369
3574
|
runEnableDisableCliCommand,
|
|
3370
3575
|
runExecCommand,
|