mcp-google-map 0.10.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/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  Logger,
4
4
  PlacesSearcher
5
- } from "./chunk-OAML6T2D.js";
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: isAutoUpdateDisabled(env),
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 || process.env.GOOGLE_MAPS_API_KEY;
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 dirname2 } from "path";
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
- const settings = { enabled: uniqueStrings(record.enabled) };
1488
- if (typeof record.apiKey === "string" && record.apiKey.length > 0) {
1489
- settings.apiKey = record.apiKey;
1490
- }
1491
- return settings;
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 = { enabled: uniqueStrings(settings.enabled) };
1504
- if (typeof settings.apiKey === "string" && settings.apiKey.length > 0) {
1505
- payload.apiKey = settings.apiKey;
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
- function syncSkillTree(source, destination) {
2175
+ var SKILL_DOCUMENT_FILE = "SKILL.md";
2176
+ function syncSkillTree(source, destination, layout = {}) {
2135
2177
  mkdirSync3(destination, { recursive: true });
2136
- cpSync(source, destination, { recursive: true, force: true });
2137
- const expected = new Set(listFilesRecursive(source));
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
- if (readFileSync3(target).toString("utf-8") !== readFileSync3(join3(source, ...rel.split("/"))).toString("utf-8")) {
2156
- return "STALE";
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(apiKey) {
2189
- const env = {
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
- if (!existsSync3(join4(resourcesRoot, skill.path))) {
2232
- throw new Error(`manifest skill file not found: ${join4(resourcesRoot, skill.path)}`);
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(options.apiKey);
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(join4(options.resourcesRoot, skill.id), join4(target.skillsDir(options.home), skill.id));
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 = dirname2(__filename);
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
- if (apiKey) {
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
- JSON.stringify(
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
- settingsPath = saveCliSettings(settings, options.home);
2978
+ saveCliSettings(settings, options.home);
2924
2979
  } catch (error) {
2925
- streams.stderr.write(
2926
- JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) + "\n"
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, apiKey: trimmed, resourcesRoot: options.resourcesRoot });
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
- JSON.stringify(
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
- const zeroEnabled = install.summaries.length === 0 && install.errors.length === 0;
2949
- streams.stdout.write(
2950
- JSON.stringify(
2951
- {
2952
- success: install.errors.length === 0,
2953
- command: "api-key",
2954
- apiKey: maskSecret(trimmed),
2955
- settingsPath,
2956
- ...zeroEnabled ? { message: "API key saved. No CLI enabled. Use 'mcp-google-map enable <cli name>' first." } : {},
2957
- install: { operation: "install", summaries: install.summaries, errors: install.errors }
2958
- },
2959
- null,
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({ home: options.home, apiKey: options.apiKey, resourcesRoot: options.resourcesRoot }) : uninstallEnabledCliResources({ home: options.home, resourcesRoot: options.resourcesRoot });
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
- if (argv.apikey) {
3057
- process.env.GOOGLE_MAPS_API_KEY = argv.apikey;
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, or pass --apikey / set GOOGLE_MAPS_API_KEY."
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, or set GOOGLE_MAPS_API_KEY / pass --apikey");
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("apikey", {
3273
- alias: "k",
3274
- type: "string",
3275
- description: "Google Maps API key embedded in the registered entry (priority: this flag, persisted api-key settings, GOOGLE_MAPS_API_KEY)"
3276
- }).example([["$0 install", "Register the server and skills in every enabled CLI"]]),
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
- apiKey: resolveInstallApiKey({
3282
- flagKey: argv.apikey,
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
- if (!argv.apikey) {
3417
+ const apiKey = loadConfiguredApiKey();
3418
+ if (!apiKey) {
3341
3419
  process.stderr.write(
3342
3420
  JSON.stringify(
3343
3421
  {
3344
- error: "GOOGLE_MAPS_API_KEY not set. Use --apikey or set GOOGLE_MAPS_API_KEY environment variable."
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, argv.apikey);
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
- if (!argv.apikey) {
3392
- console.error("Error: GOOGLE_MAPS_API_KEY not set. Use --apikey or set env var.");
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(argv.apikey);
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,