mcp-google-map 0.10.0 → 0.14.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 +3 -1
- package/dist/{chunk-OAML6T2D.js → chunk-VCFXCLJF.js} +4 -4
- package/dist/chunk-VCFXCLJF.js.map +1 -0
- package/dist/cli.d.ts +6 -2
- package/dist/cli.js +336 -261
- 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,6 +1410,73 @@ 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";
|
|
@@ -1481,16 +1505,16 @@ function loadCliSettings(home) {
|
|
|
1481
1505
|
try {
|
|
1482
1506
|
const raw = JSON.parse(readFileSync(resolveCliSettingsPath(home), "utf-8"));
|
|
1483
1507
|
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
1484
|
-
return { enabled: [] };
|
|
1508
|
+
return { enabled: [], apiKey: "", autoUpdate: true };
|
|
1485
1509
|
}
|
|
1486
1510
|
const record = raw;
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
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
|
+
};
|
|
1492
1516
|
} catch {
|
|
1493
|
-
return { enabled: [] };
|
|
1517
|
+
return { enabled: [], apiKey: "", autoUpdate: true };
|
|
1494
1518
|
}
|
|
1495
1519
|
}
|
|
1496
1520
|
function loadConfiguredApiKey(home) {
|
|
@@ -1500,10 +1524,11 @@ function loadConfiguredApiKey(home) {
|
|
|
1500
1524
|
function saveCliSettings(settings, home) {
|
|
1501
1525
|
const path = resolveCliSettingsPath(home);
|
|
1502
1526
|
const temporary = `${path}.tmp`;
|
|
1503
|
-
const payload = {
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1527
|
+
const payload = {
|
|
1528
|
+
enabled: uniqueStrings(settings.enabled),
|
|
1529
|
+
apiKey: typeof settings.apiKey === "string" ? settings.apiKey : "",
|
|
1530
|
+
autoUpdate: settings.autoUpdate === true
|
|
1531
|
+
};
|
|
1507
1532
|
try {
|
|
1508
1533
|
mkdirSync(join(path, ".."), { recursive: true });
|
|
1509
1534
|
writeFileSync(temporary, JSON.stringify(payload, null, 2) + "\n", "utf-8");
|
|
@@ -1789,7 +1814,22 @@ async function runVersionCommand(options, deps = {}) {
|
|
|
1789
1814
|
`);
|
|
1790
1815
|
return 0;
|
|
1791
1816
|
}
|
|
1817
|
+
function isUpgradeNecessary(status) {
|
|
1818
|
+
return status !== "current";
|
|
1819
|
+
}
|
|
1792
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
|
+
}
|
|
1793
1833
|
const upgraded = runPackageManagerCommand(PACKAGE_UPGRADE_COMMAND, deps);
|
|
1794
1834
|
if (upgraded !== 0) {
|
|
1795
1835
|
return upgraded;
|
|
@@ -1937,6 +1977,7 @@ function renderClientSnippet(options = {}) {
|
|
|
1937
1977
|
|
|
1938
1978
|
// src/utils/cliTargets.ts
|
|
1939
1979
|
import {
|
|
1980
|
+
appendFileSync,
|
|
1940
1981
|
cpSync,
|
|
1941
1982
|
existsSync as existsSync2,
|
|
1942
1983
|
mkdirSync as mkdirSync3,
|
|
@@ -2131,30 +2172,46 @@ function listFilesRecursive(root) {
|
|
|
2131
2172
|
walk(root);
|
|
2132
2173
|
return files;
|
|
2133
2174
|
}
|
|
2134
|
-
|
|
2175
|
+
var SKILL_DOCUMENT_FILE = "SKILL.md";
|
|
2176
|
+
function syncSkillTree(source, destination, layout = {}) {
|
|
2135
2177
|
mkdirSync3(destination, { recursive: true });
|
|
2136
|
-
cpSync(source, destination, {
|
|
2137
|
-
|
|
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));
|
|
2138
2184
|
const existing = listFilesRecursive(destination);
|
|
2139
2185
|
existing.sort((a, b) => b.length - a.length);
|
|
2140
2186
|
for (const rel of existing) {
|
|
2141
2187
|
if (expected.has(rel)) continue;
|
|
2142
2188
|
rmSync(join3(destination, rel), { recursive: true, force: true });
|
|
2143
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
|
+
}
|
|
2144
2196
|
}
|
|
2145
2197
|
function removeSkillDir(skillDir) {
|
|
2146
2198
|
rmSync(skillDir, { recursive: true, force: true });
|
|
2147
2199
|
}
|
|
2148
|
-
function compareSkillTree(source, destination) {
|
|
2149
|
-
const packaged = listFilesRecursive(source);
|
|
2200
|
+
function compareSkillTree(source, destination, layout = {}) {
|
|
2201
|
+
const packaged = listFilesRecursive(source).filter((rel) => rel !== layout.debugPath);
|
|
2150
2202
|
if (packaged.length === 0) return "MISSING";
|
|
2151
2203
|
if (!existsSync2(destination)) return "MISSING";
|
|
2152
2204
|
for (const rel of packaged) {
|
|
2153
2205
|
const target = join3(destination, ...rel.split("/"));
|
|
2154
2206
|
if (!existsSync2(target)) return "MISSING";
|
|
2155
|
-
|
|
2156
|
-
|
|
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;
|
|
2157
2213
|
}
|
|
2214
|
+
return "STALE";
|
|
2158
2215
|
}
|
|
2159
2216
|
return "OK";
|
|
2160
2217
|
}
|
|
@@ -2184,22 +2241,9 @@ function applyServerRegistration(target, serverName, entry, home) {
|
|
|
2184
2241
|
|
|
2185
2242
|
// src/utils/cliInstaller.ts
|
|
2186
2243
|
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
|
|
2187
|
-
import { join as join4, resolve as resolve3 } from "path";
|
|
2188
|
-
function buildServerRegistration(
|
|
2189
|
-
|
|
2190
|
-
GOOGLE_MAPS_API_KEY: isUnsetApiKey(apiKey) ? INSTALL_API_KEY_PLACEHOLDER : apiKey
|
|
2191
|
-
};
|
|
2192
|
-
return { command: "npx", args: ["-y", MCP_SERVER_NAME, "start", "--stdio"], env };
|
|
2193
|
-
}
|
|
2194
|
-
function resolveInstallApiKey(options) {
|
|
2195
|
-
if (!isUnsetApiKey(options.flagKey)) {
|
|
2196
|
-
return options.flagKey;
|
|
2197
|
-
}
|
|
2198
|
-
const persisted = loadConfiguredApiKey(options.home);
|
|
2199
|
-
if (persisted !== void 0) {
|
|
2200
|
-
return persisted;
|
|
2201
|
-
}
|
|
2202
|
-
return isUnsetApiKey(options.envKey) ? void 0 : options.envKey;
|
|
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"] };
|
|
2203
2247
|
}
|
|
2204
2248
|
function resolveSkillsResourcesRoot(packageRoot) {
|
|
2205
2249
|
const candidate = resolve3(packageRoot, "src", "resources", "skills");
|
|
@@ -2228,21 +2272,36 @@ function loadSkillsManifest(resourcesRoot) {
|
|
|
2228
2272
|
if (typeof skill.id !== "string" || typeof skill.path !== "string") {
|
|
2229
2273
|
throw new Error(`skills manifest entry is missing id or path: ${manifestPath}`);
|
|
2230
2274
|
}
|
|
2231
|
-
|
|
2232
|
-
|
|
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)}`);
|
|
2233
2285
|
}
|
|
2234
2286
|
return {
|
|
2235
2287
|
id: skill.id,
|
|
2236
2288
|
name: skill.name ?? skill.id,
|
|
2237
2289
|
version: skill.version ?? "",
|
|
2238
2290
|
path: skill.path,
|
|
2239
|
-
description: skill.description ?? ""
|
|
2291
|
+
description: skill.description ?? "",
|
|
2292
|
+
...debugPath === void 0 ? {} : { debugPath }
|
|
2240
2293
|
};
|
|
2241
2294
|
});
|
|
2242
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
|
+
}
|
|
2243
2302
|
function installEnabledCliResources(options) {
|
|
2244
2303
|
const manifest = loadSkillsManifest(options.resourcesRoot);
|
|
2245
|
-
const entry = buildServerRegistration(
|
|
2304
|
+
const entry = buildServerRegistration();
|
|
2246
2305
|
const result = { summaries: [], errors: [] };
|
|
2247
2306
|
for (const cli of loadCliSettings(options.home).enabled) {
|
|
2248
2307
|
const target = CLI_TARGETS[cli];
|
|
@@ -2254,7 +2313,11 @@ function installEnabledCliResources(options) {
|
|
|
2254
2313
|
applyServerRegistration(target, MCP_SERVER_NAME, entry, options.home);
|
|
2255
2314
|
let skills = 0;
|
|
2256
2315
|
for (const skill of manifest) {
|
|
2257
|
-
syncSkillTree(
|
|
2316
|
+
syncSkillTree(
|
|
2317
|
+
join4(options.resourcesRoot, skill.id),
|
|
2318
|
+
join4(target.skillsDir(options.home), skill.id),
|
|
2319
|
+
resolveSkillContentLayout(skill, options.includeDebugSkills === true)
|
|
2320
|
+
);
|
|
2258
2321
|
skills += 1;
|
|
2259
2322
|
}
|
|
2260
2323
|
result.summaries.push({ cli: target.id, server: 1, skills });
|
|
@@ -2376,7 +2439,9 @@ function buildInstallRows(home, resourcesRoot) {
|
|
|
2376
2439
|
skill.id,
|
|
2377
2440
|
target.id,
|
|
2378
2441
|
"yes",
|
|
2379
|
-
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
|
+
})
|
|
2380
2445
|
]);
|
|
2381
2446
|
}
|
|
2382
2447
|
}
|
|
@@ -2394,7 +2459,7 @@ function buildCliShowReport(options) {
|
|
|
2394
2459
|
|
|
2395
2460
|
// src/cli.ts
|
|
2396
2461
|
var __filename = fileURLToPath(import.meta.url);
|
|
2397
|
-
var __dirname =
|
|
2462
|
+
var __dirname = dirname3(__filename);
|
|
2398
2463
|
function extractEnvFileOption(argv) {
|
|
2399
2464
|
for (let i = 0; i < argv.length; i++) {
|
|
2400
2465
|
const arg = argv[i];
|
|
@@ -2423,9 +2488,7 @@ async function startServer(port, apiKey, host) {
|
|
|
2423
2488
|
if (port) {
|
|
2424
2489
|
process.env.MCP_SERVER_PORT = port.toString();
|
|
2425
2490
|
}
|
|
2426
|
-
|
|
2427
|
-
process.env.GOOGLE_MAPS_API_KEY = apiKey;
|
|
2428
|
-
}
|
|
2491
|
+
ApiKeyManager.getInstance().setDefaultApiKey(apiKey);
|
|
2429
2492
|
if (host) {
|
|
2430
2493
|
process.env.MCP_SERVER_HOST = host;
|
|
2431
2494
|
}
|
|
@@ -2905,62 +2968,74 @@ function runApiKeyCommand(key, options) {
|
|
|
2905
2968
|
const trimmed = (key ?? "").trim();
|
|
2906
2969
|
if (!ApiKeyManager.getInstance().isValidApiKeyFormat(trimmed)) {
|
|
2907
2970
|
streams.stderr.write(
|
|
2908
|
-
|
|
2909
|
-
{
|
|
2910
|
-
success: false,
|
|
2911
|
-
error: "Invalid Google Maps API key. Expected 20-50 characters of letters, digits, hyphens, or underscores. Usage: mcp-google-map api-key <your-api-key>"
|
|
2912
|
-
},
|
|
2913
|
-
null,
|
|
2914
|
-
2
|
|
2915
|
-
) + "\n"
|
|
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"
|
|
2916
2972
|
);
|
|
2917
2973
|
return 1;
|
|
2918
2974
|
}
|
|
2919
|
-
let settingsPath;
|
|
2920
2975
|
try {
|
|
2921
2976
|
const settings = loadCliSettings(options.home);
|
|
2922
2977
|
settings.apiKey = trimmed;
|
|
2923
|
-
|
|
2978
|
+
saveCliSettings(settings, options.home);
|
|
2924
2979
|
} catch (error) {
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2980
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2981
|
+
streams.stderr.write(`api-key: failed to persist the API key: ${message}
|
|
2982
|
+
`);
|
|
2928
2983
|
return 1;
|
|
2929
2984
|
}
|
|
2985
|
+
streams.stdout.write(`API key configured (${maskSecret(trimmed)}).
|
|
2986
|
+
`);
|
|
2930
2987
|
let install;
|
|
2931
2988
|
try {
|
|
2932
|
-
install = installEnabledCliResources({ home: options.home,
|
|
2989
|
+
install = installEnabledCliResources({ home: options.home, resourcesRoot: options.resourcesRoot });
|
|
2933
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 {
|
|
2934
3021
|
streams.stderr.write(
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
success: false,
|
|
2938
|
-
apiKey: maskSecret(trimmed),
|
|
2939
|
-
settingsPath,
|
|
2940
|
-
error: error instanceof Error ? error.message : String(error)
|
|
2941
|
-
},
|
|
2942
|
-
null,
|
|
2943
|
-
2
|
|
2944
|
-
) + "\n"
|
|
3022
|
+
`auto-update: invalid value "${rawState ?? ""}". Accepted values: enable, disable, 1, 0.
|
|
3023
|
+
`
|
|
2945
3024
|
);
|
|
2946
3025
|
return 1;
|
|
2947
3026
|
}
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
2
|
|
2961
|
-
) + "\n"
|
|
2962
|
-
);
|
|
2963
|
-
return install.errors.length > 0 ? 1 : 0;
|
|
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;
|
|
2964
3039
|
}
|
|
2965
3040
|
function runInstallUninstallCommand(operation, options) {
|
|
2966
3041
|
const streams = options.streams ?? { stdout: process.stdout, stderr: process.stderr };
|
|
@@ -2981,7 +3056,11 @@ function runInstallUninstallCommand(operation, options) {
|
|
|
2981
3056
|
}
|
|
2982
3057
|
let result;
|
|
2983
3058
|
try {
|
|
2984
|
-
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 });
|
|
2985
3064
|
} catch (error) {
|
|
2986
3065
|
streams.stderr.write(
|
|
2987
3066
|
JSON.stringify({ success: false, errors: [error instanceof Error ? error.message : String(error)] }, null, 2) + "\n"
|
|
@@ -3036,42 +3115,29 @@ if (isRunDirectly || isMainModule) {
|
|
|
3036
3115
|
type: "string",
|
|
3037
3116
|
description: "Hostname to bind the server to (default 127.0.0.1 loopback; 0.0.0.0 for all interfaces)",
|
|
3038
3117
|
default: process.env.MCP_SERVER_HOST || "127.0.0.1"
|
|
3039
|
-
}).option("apikey", {
|
|
3040
|
-
alias: "k",
|
|
3041
|
-
type: "string",
|
|
3042
|
-
description: "Google Maps API key",
|
|
3043
|
-
default: process.env.GOOGLE_MAPS_API_KEY
|
|
3044
3118
|
}).option("stdio", {
|
|
3045
3119
|
type: "boolean",
|
|
3046
3120
|
description: "Use stdio transport instead of HTTP",
|
|
3047
3121
|
default: false
|
|
3048
3122
|
}).example([
|
|
3049
3123
|
["$0 start", "Start HTTP server with default settings"],
|
|
3050
|
-
['$0 start --port 3000 --apikey "your_api_key"', "Start HTTP with custom port and API key"],
|
|
3051
3124
|
["$0 start --host 0.0.0.0 --port 3000", "Start HTTP accessible from all interfaces"],
|
|
3052
3125
|
["$0 start --stdio", "Start in stdio mode (for MCP clients)"],
|
|
3053
3126
|
["$0 run --stdio", "Alias: run the server in stdio mode"]
|
|
3054
3127
|
]);
|
|
3055
3128
|
const runServerCommand = async (argv) => {
|
|
3056
|
-
|
|
3057
|
-
|
|
3129
|
+
const effectiveApiKey = loadConfiguredApiKey();
|
|
3130
|
+
ApiKeyManager.getInstance().setDefaultApiKey(effectiveApiKey);
|
|
3131
|
+
if (loadCliSettings().autoUpdate) {
|
|
3132
|
+
void checkVersionIdle({ currentVersion: packageVersion }).catch(() => void 0);
|
|
3058
3133
|
}
|
|
3059
|
-
let effectiveApiKey = isUnsetApiKey(process.env.GOOGLE_MAPS_API_KEY) ? void 0 : process.env.GOOGLE_MAPS_API_KEY;
|
|
3060
|
-
if (effectiveApiKey === void 0) {
|
|
3061
|
-
const persistedApiKey = loadConfiguredApiKey();
|
|
3062
|
-
if (persistedApiKey !== void 0) {
|
|
3063
|
-
process.env.GOOGLE_MAPS_API_KEY = persistedApiKey;
|
|
3064
|
-
effectiveApiKey = persistedApiKey;
|
|
3065
|
-
}
|
|
3066
|
-
}
|
|
3067
|
-
void checkVersionIdle({ currentVersion: packageVersion }).catch(() => void 0);
|
|
3068
3134
|
const tools = filterTools(config_default[0].tools);
|
|
3069
3135
|
if (argv.stdio) {
|
|
3070
3136
|
if (effectiveApiKey === void 0) {
|
|
3071
3137
|
process.stderr.write(
|
|
3072
3138
|
JSON.stringify(
|
|
3073
3139
|
{
|
|
3074
|
-
error: "Google Maps API key is not configured. Run 'mcp-google-map api-key <your-api-key>' to configure it
|
|
3140
|
+
error: "Google Maps API key is not configured. Run 'mcp-google-map api-key <your-api-key>' to configure it."
|
|
3075
3141
|
},
|
|
3076
3142
|
null,
|
|
3077
3143
|
2
|
|
@@ -3088,7 +3154,7 @@ if (isRunDirectly || isMainModule) {
|
|
|
3088
3154
|
Logger.log("");
|
|
3089
3155
|
if (effectiveApiKey === void 0) {
|
|
3090
3156
|
Logger.log("\u26A0\uFE0F Google Maps API Key not found!");
|
|
3091
|
-
Logger.log(" Run 'mcp-google-map api-key <your-api-key>' to configure it
|
|
3157
|
+
Logger.log(" Run 'mcp-google-map api-key <your-api-key>' to configure it.");
|
|
3092
3158
|
Logger.log("");
|
|
3093
3159
|
}
|
|
3094
3160
|
startServer(argv.port, effectiveApiKey, argv.host).then((outcome) => {
|
|
@@ -3247,6 +3313,24 @@ Usage: mcp-google-map <command> [options]
|
|
|
3247
3313
|
home: argv.home
|
|
3248
3314
|
});
|
|
3249
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
|
+
}
|
|
3250
3334
|
).command(
|
|
3251
3335
|
"api-key <key>",
|
|
3252
3336
|
"Save the Google Maps API key in the user settings and refresh every enabled CLI registration",
|
|
@@ -3269,21 +3353,19 @@ Usage: mcp-google-map <command> [options]
|
|
|
3269
3353
|
(yargs2) => yargs2.option("home", {
|
|
3270
3354
|
type: "string",
|
|
3271
3355
|
description: "Home-directory override for CLI configuration paths (default: user home)"
|
|
3272
|
-
}).option("
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
}).example([
|
|
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
|
+
]),
|
|
3277
3364
|
(argv) => {
|
|
3278
|
-
const config = resolveRuntimeConfig(process.env, { envFile: extractEnvFileOption(process.argv) });
|
|
3279
3365
|
process.exitCode = runInstallUninstallCommand("install", {
|
|
3280
3366
|
home: argv.home,
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
envKey: config.apiKey,
|
|
3284
|
-
home: argv.home
|
|
3285
|
-
}),
|
|
3286
|
-
resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, ".."))
|
|
3367
|
+
resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, "..")),
|
|
3368
|
+
includeDebugSkills: argv.debugSkills === true
|
|
3287
3369
|
});
|
|
3288
3370
|
}
|
|
3289
3371
|
).command(
|
|
@@ -3322,11 +3404,6 @@ Usage: mcp-google-map <command> [options]
|
|
|
3322
3404
|
}).positional("params", {
|
|
3323
3405
|
type: "string",
|
|
3324
3406
|
describe: "JSON parameters string"
|
|
3325
|
-
}).option("apikey", {
|
|
3326
|
-
alias: "k",
|
|
3327
|
-
type: "string",
|
|
3328
|
-
description: "Google Maps API key",
|
|
3329
|
-
default: process.env.GOOGLE_MAPS_API_KEY
|
|
3330
3407
|
}).example([
|
|
3331
3408
|
[`$0 exec geocode '{"address":"Tokyo Tower"}'`, "Geocode an address"],
|
|
3332
3409
|
[
|
|
@@ -3337,11 +3414,12 @@ Usage: mcp-google-map <command> [options]
|
|
|
3337
3414
|
]);
|
|
3338
3415
|
},
|
|
3339
3416
|
async (argv) => {
|
|
3340
|
-
|
|
3417
|
+
const apiKey = loadConfiguredApiKey();
|
|
3418
|
+
if (!apiKey) {
|
|
3341
3419
|
process.stderr.write(
|
|
3342
3420
|
JSON.stringify(
|
|
3343
3421
|
{
|
|
3344
|
-
error: "
|
|
3422
|
+
error: "Google Maps API key is not configured. Run 'mcp-google-map api-key <your-api-key>' to configure it."
|
|
3345
3423
|
},
|
|
3346
3424
|
null,
|
|
3347
3425
|
2
|
|
@@ -3352,7 +3430,7 @@ Usage: mcp-google-map <command> [options]
|
|
|
3352
3430
|
}
|
|
3353
3431
|
try {
|
|
3354
3432
|
const params = argv.params ? JSON.parse(argv.params) : {};
|
|
3355
|
-
process.exitCode = await runExecCommand(argv.tool, params,
|
|
3433
|
+
process.exitCode = await runExecCommand(argv.tool, params, apiKey);
|
|
3356
3434
|
} catch (error) {
|
|
3357
3435
|
process.stderr.write(JSON.stringify({ error: error.message }, null, 2) + "\n");
|
|
3358
3436
|
process.exitCode = 1;
|
|
@@ -3376,11 +3454,6 @@ Usage: mcp-google-map <command> [options]
|
|
|
3376
3454
|
type: "number",
|
|
3377
3455
|
describe: "Max parallel requests",
|
|
3378
3456
|
default: 20
|
|
3379
|
-
}).option("apikey", {
|
|
3380
|
-
alias: "k",
|
|
3381
|
-
type: "string",
|
|
3382
|
-
description: "Google Maps API key",
|
|
3383
|
-
default: process.env.GOOGLE_MAPS_API_KEY
|
|
3384
3457
|
}).example([
|
|
3385
3458
|
["$0 batch-geocode -i addresses.txt", "Geocode to stdout"],
|
|
3386
3459
|
["$0 batch-geocode -i addresses.txt -o results.json", "Geocode to file"],
|
|
@@ -3388,8 +3461,9 @@ Usage: mcp-google-map <command> [options]
|
|
|
3388
3461
|
]);
|
|
3389
3462
|
},
|
|
3390
3463
|
async (argv) => {
|
|
3391
|
-
|
|
3392
|
-
|
|
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>'.");
|
|
3393
3467
|
process.exit(1);
|
|
3394
3468
|
}
|
|
3395
3469
|
let lines;
|
|
@@ -3411,7 +3485,7 @@ Usage: mcp-google-map <command> [options]
|
|
|
3411
3485
|
console.error("Error: No addresses found in input.");
|
|
3412
3486
|
process.exit(1);
|
|
3413
3487
|
}
|
|
3414
|
-
const searcher = new PlacesSearcher(
|
|
3488
|
+
const searcher = new PlacesSearcher(apiKey);
|
|
3415
3489
|
const concurrency = Math.min(Math.max(argv.concurrency, 1), 50);
|
|
3416
3490
|
const results = [];
|
|
3417
3491
|
let completed = 0;
|
|
@@ -3495,6 +3569,7 @@ export {
|
|
|
3495
3569
|
installShutdownHandlers,
|
|
3496
3570
|
parseDoctorProbes,
|
|
3497
3571
|
runApiKeyCommand,
|
|
3572
|
+
runAutoUpdateCommand,
|
|
3498
3573
|
runDoctor,
|
|
3499
3574
|
runEnableDisableCliCommand,
|
|
3500
3575
|
runExecCommand,
|