mcp-google-map 0.5.0 → 0.7.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
@@ -19,6 +19,46 @@ var AUTO_UPDATE_DISABLED_ENV = "MCP_AUTO_UPDATE_DISABLED";
19
19
  var DEFAULT_PACKAGE_NAME = "mcp-google-map";
20
20
  var DEFAULT_REGISTRY_BASE_URL = "https://registry.npmjs.org";
21
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
+ }
22
62
  function isAutoUpdateDisabled(env = process.env) {
23
63
  const raw = env[AUTO_UPDATE_DISABLED_ENV];
24
64
  return typeof raw === "string" && /^(1|true|yes)$/i.test(raw.trim());
@@ -40,54 +80,6 @@ function isNewerVersion(candidate, current) {
40
80
  }
41
81
  return false;
42
82
  }
43
- async function checkForUpdates(deps = {}) {
44
- const logger = deps.logger ?? Logger;
45
- const env = deps.env ?? process.env;
46
- try {
47
- if (isAutoUpdateDisabled(env)) {
48
- return null;
49
- }
50
- const currentVersion = deps.currentVersion;
51
- if (!currentVersion) {
52
- logger.error(
53
- `\u26A0\uFE0F [${DEFAULT_PACKAGE_NAME}] Automatic update check skipped: running package version is unknown.`
54
- );
55
- return null;
56
- }
57
- const packageName = deps.packageName ?? DEFAULT_PACKAGE_NAME;
58
- const registryBaseUrl = deps.registryBaseUrl ?? DEFAULT_REGISTRY_BASE_URL;
59
- const timeoutMs = deps.timeoutMs ?? DEFAULT_UPDATE_CHECK_TIMEOUT_MS;
60
- const fetchImpl = deps.fetchImpl ?? fetch;
61
- const response = await fetchImpl(`${registryBaseUrl}/${packageName}/latest`, {
62
- headers: { accept: "application/vnd.npm.install-v1+json" },
63
- signal: AbortSignal.timeout(timeoutMs)
64
- });
65
- if (!response.ok) {
66
- logger.error(
67
- `\u26A0\uFE0F [${DEFAULT_PACKAGE_NAME}] Automatic update check failed: registry responded with HTTP ${response.status}.`
68
- );
69
- return null;
70
- }
71
- const payload = await response.json();
72
- if (typeof payload?.version !== "string") {
73
- logger.error(
74
- `\u26A0\uFE0F [${DEFAULT_PACKAGE_NAME}] Automatic update check failed: registry response has no version field.`
75
- );
76
- return null;
77
- }
78
- if (!isNewerVersion(payload.version, currentVersion)) {
79
- return null;
80
- }
81
- logger.log(
82
- `\u26A0\uFE0F Update available: ${packageName} ${currentVersion} \u2192 ${payload.version}. Upgrade with: npm install -g ${packageName}@latest (or run npx -y ${packageName}@latest).`
83
- );
84
- return { currentVersion, latestVersion: payload.version };
85
- } catch (error) {
86
- const message = error instanceof Error ? error.message : String(error);
87
- logger.error(`\u26A0\uFE0F [${DEFAULT_PACKAGE_NAME}] Automatic update check failed: ${message}`);
88
- return null;
89
- }
90
- }
91
83
 
92
84
  // src/utils/configResolver.ts
93
85
  var NODE_ENGINE_FLOOR = 22;
@@ -1451,10 +1443,255 @@ var BaseMcpServer = class {
1451
1443
 
1452
1444
  // src/cli.ts
1453
1445
  import { fileURLToPath } from "url";
1454
- import { dirname } from "path";
1455
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4 } from "fs";
1446
+ import { dirname as dirname2 } from "path";
1447
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync4 } from "fs";
1456
1448
  import { createInterface } from "readline";
1457
1449
 
1450
+ // src/utils/upgradeManager.ts
1451
+ import { spawnSync } from "child_process";
1452
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
1453
+ import { homedir } from "os";
1454
+ import { dirname, join as join2 } from "path";
1455
+
1456
+ // src/utils/cliSettings.ts
1457
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
1458
+ import { join, resolve } from "path";
1459
+ var SETTINGS_PROGRAM_NAME = "mcp-google-map";
1460
+ var CLI_SETTINGS_RELATIVE = [".config", SETTINGS_PROGRAM_NAME, "config.json"];
1461
+ var MCP_SERVER_NAME = "mcp-google-map";
1462
+ function resolveCliSettingsPath(home) {
1463
+ const root = home ?? (process.env.HOME ?? process.cwd());
1464
+ return resolve(root, ...CLI_SETTINGS_RELATIVE);
1465
+ }
1466
+ function uniqueStrings(value) {
1467
+ if (!Array.isArray(value)) return [];
1468
+ const result = [];
1469
+ for (const item of value) {
1470
+ if (typeof item === "string" && item.length > 0 && !result.includes(item)) {
1471
+ result.push(item);
1472
+ }
1473
+ }
1474
+ return result;
1475
+ }
1476
+ function loadCliSettings(home) {
1477
+ try {
1478
+ const raw = JSON.parse(readFileSync(resolveCliSettingsPath(home), "utf-8"));
1479
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
1480
+ return { enabled: [] };
1481
+ }
1482
+ return { enabled: uniqueStrings(raw.enabled) };
1483
+ } catch {
1484
+ return { enabled: [] };
1485
+ }
1486
+ }
1487
+ function saveCliSettings(settings, home) {
1488
+ const path = resolveCliSettingsPath(home);
1489
+ const temporary = `${path}.tmp`;
1490
+ try {
1491
+ mkdirSync(join(path, ".."), { recursive: true });
1492
+ writeFileSync(temporary, JSON.stringify({ enabled: uniqueStrings(settings.enabled) }, null, 2) + "\n", "utf-8");
1493
+ renameSync(temporary, path);
1494
+ } catch (error) {
1495
+ throw new Error(`settings write failed: ${error instanceof Error ? error.message : String(error)}`);
1496
+ }
1497
+ return path;
1498
+ }
1499
+
1500
+ // src/utils/upgradeManager.ts
1501
+ var ANSI_GREEN = "\x1B[92m";
1502
+ var ANSI_RED = "\x1B[91m";
1503
+ var ANSI_RESET = "\x1B[0m";
1504
+ var green = (text) => `${ANSI_GREEN}${text}${ANSI_RESET}`;
1505
+ var red = (text) => `${ANSI_RED}${text}${ANSI_RESET}`;
1506
+ var IDLE_CACHE_DIR_NAME = "mcp-google-map";
1507
+ var IDLE_CACHE_FILE_NAME = "check_version_idle-time.json";
1508
+ var IDLE_WINDOW_NEWER_MS = 60 * 60 * 1e3;
1509
+ var IDLE_WINDOW_DEFAULT_MS = 24 * 60 * 60 * 1e3;
1510
+ var PACKAGE_UPGRADE_COMMAND = [
1511
+ "npm",
1512
+ "install",
1513
+ "-g",
1514
+ `${DEFAULT_PACKAGE_NAME}@latest`
1515
+ ];
1516
+ var PACKAGE_UNINSTALL_COMMAND = [
1517
+ "npm",
1518
+ "uninstall",
1519
+ "-g",
1520
+ DEFAULT_PACKAGE_NAME
1521
+ ];
1522
+ var POST_UPGRADE_INSTALL_COMMAND = [
1523
+ "npx",
1524
+ "-y",
1525
+ DEFAULT_PACKAGE_NAME,
1526
+ "install"
1527
+ ];
1528
+ function resolveIdleCachePath(home) {
1529
+ return join2(home ?? homedir(), ".cache", IDLE_CACHE_DIR_NAME, IDLE_CACHE_FILE_NAME);
1530
+ }
1531
+ function loadIdleCache(cachePath, fs = {}) {
1532
+ try {
1533
+ const readFile = fs.readFile ?? ((path) => readFileSync2(path, "utf-8"));
1534
+ const raw = readFile(cachePath);
1535
+ const parsed = JSON.parse(raw);
1536
+ if (typeof parsed !== "object" || parsed === null) {
1537
+ return {};
1538
+ }
1539
+ const record = parsed;
1540
+ const isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
1541
+ return {
1542
+ last_success_epoch: isFiniteNumber(record.last_success_epoch) ? record.last_success_epoch : void 0,
1543
+ last_success_human: typeof record.last_success_human === "string" ? record.last_success_human : void 0,
1544
+ idle_time_epoch: isFiniteNumber(record.idle_time_epoch) ? record.idle_time_epoch : void 0,
1545
+ idle_time_human: typeof record.idle_time_human === "string" ? record.idle_time_human : void 0
1546
+ };
1547
+ } catch {
1548
+ return {};
1549
+ }
1550
+ }
1551
+ function persistIdleCache(cachePath, lastSuccess, idleUntil, fs = {}, logger = Logger) {
1552
+ const toIso = (epoch) => epoch === void 0 ? null : new Date(epoch).toISOString();
1553
+ const data = {
1554
+ last_success_epoch: lastSuccess ?? null,
1555
+ last_success_human: toIso(lastSuccess),
1556
+ idle_time_epoch: idleUntil,
1557
+ idle_time_human: toIso(idleUntil)
1558
+ };
1559
+ try {
1560
+ const mkdir = fs.mkdir ?? ((path) => mkdirSync2(path, { recursive: true }));
1561
+ const writeFile = fs.writeFile ?? ((path, data2) => writeFileSync2(path, data2));
1562
+ mkdir(dirname(cachePath));
1563
+ writeFile(cachePath, JSON.stringify(data, null, 2) + "\n");
1564
+ } catch (error) {
1565
+ const message = error instanceof Error ? error.message : String(error);
1566
+ logger.error(red(`Version cache error: ${message}`));
1567
+ }
1568
+ }
1569
+ async function checkVersionIdle(deps = {}) {
1570
+ const logger = deps.logger ?? Logger;
1571
+ const now = deps.now ?? (() => Date.now());
1572
+ const cachePath = deps.cachePath ?? resolveIdleCachePath();
1573
+ const cache = loadIdleCache(cachePath, deps.fs);
1574
+ if (deps.force !== true) {
1575
+ const idle = cache.idle_time_epoch;
1576
+ if (typeof idle === "number" && idle > now()) {
1577
+ return { checked: false, status: "idle" };
1578
+ }
1579
+ }
1580
+ const probe = await probeLatestVersion(deps);
1581
+ if (probe.status === "disabled") {
1582
+ return { checked: false, status: "disabled" };
1583
+ }
1584
+ let delayMs = IDLE_WINDOW_DEFAULT_MS;
1585
+ let lastSuccess = typeof cache.last_success_epoch === "number" ? cache.last_success_epoch : void 0;
1586
+ const result = { checked: true, status: probe.status };
1587
+ switch (probe.status) {
1588
+ case "unknown-version":
1589
+ logger.error(red("Version check error: running package version is unknown."));
1590
+ break;
1591
+ case "error":
1592
+ logger.error(red(`Version check error: ${probe.message}`));
1593
+ break;
1594
+ case "current":
1595
+ lastSuccess = now();
1596
+ result.currentVersion = probe.currentVersion;
1597
+ break;
1598
+ case "newer": {
1599
+ lastSuccess = now();
1600
+ delayMs = IDLE_WINDOW_NEWER_MS;
1601
+ result.currentVersion = probe.currentVersion;
1602
+ result.latestVersion = probe.latestVersion;
1603
+ logger.log(
1604
+ green(
1605
+ `Available Version: ${probe.latestVersion} | Installed Version: ${probe.currentVersion}`
1606
+ )
1607
+ );
1608
+ logger.log(
1609
+ green(
1610
+ `Upgrade with: npm install -g ${DEFAULT_PACKAGE_NAME}@latest (or run: ${DEFAULT_PACKAGE_NAME} --upgrade)`
1611
+ )
1612
+ );
1613
+ break;
1614
+ }
1615
+ }
1616
+ const finishedAt = now();
1617
+ const idleUntil = finishedAt + delayMs;
1618
+ persistIdleCache(cachePath, lastSuccess, idleUntil, deps.fs, logger);
1619
+ result.idleUntilEpoch = idleUntil;
1620
+ result.lastSuccessEpoch = lastSuccess;
1621
+ return result;
1622
+ }
1623
+ function parseManagementCommand(args) {
1624
+ if (args.length !== 1) {
1625
+ return void 0;
1626
+ }
1627
+ const arg = args[0];
1628
+ if (arg === "--ver" || arg === "--version" || arg === "--upgrade" || arg === "--uninstall") {
1629
+ return arg;
1630
+ }
1631
+ return void 0;
1632
+ }
1633
+ function runPackageManagerCommand(command, deps = {}) {
1634
+ const logger = deps.logger ?? Logger;
1635
+ const spawnImpl = deps.spawn ?? spawnSync;
1636
+ const reportSpawnFailure = (message) => {
1637
+ logger.error(`Error executing ${command[0]}: ${message}`);
1638
+ logger.log(`Warning: run this command manually: ${command.join(" ")}`);
1639
+ return 1;
1640
+ };
1641
+ try {
1642
+ const result = spawnImpl(command[0], [...command.slice(1)], {
1643
+ stdio: "inherit",
1644
+ shell: process.platform === "win32"
1645
+ });
1646
+ if (result.error) {
1647
+ return reportSpawnFailure(result.error.message);
1648
+ }
1649
+ return result.status ?? 1;
1650
+ } catch (error) {
1651
+ const message = error instanceof Error ? error.message : String(error);
1652
+ return reportSpawnFailure(message);
1653
+ }
1654
+ }
1655
+ function runPostUpgradeSkillInstall(options, deps = {}) {
1656
+ const enabled = loadCliSettings(options.home).enabled;
1657
+ if (enabled.length === 0) {
1658
+ return 0;
1659
+ }
1660
+ return runPackageManagerCommand(POST_UPGRADE_INSTALL_COMMAND, deps);
1661
+ }
1662
+ async function runVersionCommand(options, deps = {}) {
1663
+ await checkVersionIdle({
1664
+ ...deps.idleCheck,
1665
+ force: true,
1666
+ currentVersion: options.currentVersion
1667
+ });
1668
+ const stdout = deps.stdout ?? process.stdout;
1669
+ stdout.write(`${options.currentVersion}
1670
+ `);
1671
+ return 0;
1672
+ }
1673
+ function runUpgradeCommand(options, deps = {}) {
1674
+ const upgraded = runPackageManagerCommand(PACKAGE_UPGRADE_COMMAND, deps);
1675
+ if (upgraded !== 0) {
1676
+ return upgraded;
1677
+ }
1678
+ return runPostUpgradeSkillInstall(options, deps);
1679
+ }
1680
+ function runUninstallCommand(deps = {}) {
1681
+ return runPackageManagerCommand(PACKAGE_UNINSTALL_COMMAND, deps);
1682
+ }
1683
+ async function runManagementCommand(command, options, deps = {}) {
1684
+ switch (command) {
1685
+ case "--ver":
1686
+ case "--version":
1687
+ return runVersionCommand(options, deps);
1688
+ case "--upgrade":
1689
+ return runUpgradeCommand(options, deps);
1690
+ case "--uninstall":
1691
+ return runUninstallCommand(deps);
1692
+ }
1693
+ }
1694
+
1458
1695
  // src/utils/toolProfiles.ts
1459
1696
  var TOOL_API_PROFILES = {
1460
1697
  maps_geocode: { tool: "maps_geocode", apis: ["geocoding"], dependsOnTools: [] },
@@ -1550,14 +1787,14 @@ function renderClientSnippet(options = {}) {
1550
1787
  const host = options.host ?? SNIPPET_DEFAULT_HOST;
1551
1788
  const port = options.port ?? SNIPPET_DEFAULT_PORT;
1552
1789
  entry = { url: `http://${host}:${port}/mcp` };
1553
- notes.push(`Start the server first: mcp-google-map --host ${host} --port ${port}.`);
1790
+ notes.push(`Start the server first: mcp-google-map start --host ${host} --port ${port}.`);
1554
1791
  } else {
1555
1792
  const launcher = options.launcher ?? "npx";
1556
1793
  if (launcher === "node" && !options.commandPath) {
1557
1794
  throw new Error("--launcher node requires --command <path> pointing at dist/cli.js");
1558
1795
  }
1559
1796
  const command = launcher === "npx" ? "npx" : launcher === "bin" ? "mcp-google-map" : "node";
1560
- const args = launcher === "npx" ? ["-y", "mcp-google-map", "--stdio"] : launcher === "bin" ? ["--stdio"] : [options.commandPath, "--stdio"];
1797
+ const args = launcher === "npx" ? ["-y", "mcp-google-map", "start", "--stdio"] : launcher === "bin" ? ["start", "--stdio"] : [options.commandPath, "start", "--stdio"];
1561
1798
  if (launcher === "npx") {
1562
1799
  notes.push("The npx launcher runs the published package; npm must be available on PATH.");
1563
1800
  }
@@ -1575,95 +1812,51 @@ function renderClientSnippet(options = {}) {
1575
1812
  return { json, notes };
1576
1813
  }
1577
1814
 
1578
- // src/utils/cliSettings.ts
1579
- import { mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
1580
- import { join, resolve } from "path";
1581
- var SETTINGS_PROGRAM_NAME = "mcp-google-map";
1582
- var CLI_SETTINGS_RELATIVE = [".config", SETTINGS_PROGRAM_NAME, "config.json"];
1583
- var MCP_SERVER_NAME = "mcp-google-map";
1584
- function resolveCliSettingsPath(home) {
1585
- const root = home ?? (process.env.HOME ?? process.cwd());
1586
- return resolve(root, ...CLI_SETTINGS_RELATIVE);
1587
- }
1588
- function uniqueStrings(value) {
1589
- if (!Array.isArray(value)) return [];
1590
- const result = [];
1591
- for (const item of value) {
1592
- if (typeof item === "string" && item.length > 0 && !result.includes(item)) {
1593
- result.push(item);
1594
- }
1595
- }
1596
- return result;
1597
- }
1598
- function loadCliSettings(home) {
1599
- try {
1600
- const raw = JSON.parse(readFileSync(resolveCliSettingsPath(home), "utf-8"));
1601
- if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
1602
- return { enabled: [] };
1603
- }
1604
- return { enabled: uniqueStrings(raw.enabled) };
1605
- } catch {
1606
- return { enabled: [] };
1607
- }
1608
- }
1609
- function saveCliSettings(settings, home) {
1610
- const path = resolveCliSettingsPath(home);
1611
- const temporary = `${path}.tmp`;
1612
- try {
1613
- mkdirSync(join(path, ".."), { recursive: true });
1614
- writeFileSync(temporary, JSON.stringify({ enabled: uniqueStrings(settings.enabled) }, null, 2) + "\n", "utf-8");
1615
- renameSync(temporary, path);
1616
- } catch (error) {
1617
- throw new Error(`settings write failed: ${error instanceof Error ? error.message : String(error)}`);
1618
- }
1619
- return path;
1620
- }
1621
-
1622
1815
  // src/utils/cliTargets.ts
1623
1816
  import {
1624
1817
  cpSync,
1625
1818
  existsSync as existsSync2,
1626
- mkdirSync as mkdirSync2,
1627
- readFileSync as readFileSync2,
1819
+ mkdirSync as mkdirSync3,
1820
+ readFileSync as readFileSync3,
1628
1821
  readdirSync,
1629
1822
  renameSync as renameSync2,
1630
1823
  rmSync,
1631
1824
  statSync,
1632
- writeFileSync as writeFileSync2
1825
+ writeFileSync as writeFileSync3
1633
1826
  } from "fs";
1634
- import { join as join2, relative } from "path";
1827
+ import { join as join3, relative } from "path";
1635
1828
  function homeRoot(home) {
1636
1829
  return home ?? (process.env.HOME ?? process.cwd());
1637
1830
  }
1638
1831
  var PI_TARGET = {
1639
1832
  id: "pi",
1640
1833
  configFormat: "json",
1641
- mcpConfigPath: (home) => join2(homeRoot(home), ".pi", "agent", "mcp.json"),
1642
- skillsDir: (home) => join2(homeRoot(home), ".pi", "agent", "skills")
1834
+ mcpConfigPath: (home) => join3(homeRoot(home), ".pi", "agent", "mcp.json"),
1835
+ skillsDir: (home) => join3(homeRoot(home), ".pi", "agent", "skills")
1643
1836
  };
1644
1837
  var OPENCLAW_TARGET = {
1645
1838
  id: "openclaw",
1646
1839
  configFormat: "json",
1647
- mcpConfigPath: (home) => join2(homeRoot(home), ".openclaw", "openclaw.json"),
1648
- skillsDir: (home) => join2(homeRoot(home), ".openclaw", "workspace", "skills")
1840
+ mcpConfigPath: (home) => join3(homeRoot(home), ".openclaw", "openclaw.json"),
1841
+ skillsDir: (home) => join3(homeRoot(home), ".openclaw", "workspace", "skills")
1649
1842
  };
1650
1843
  var CODEX_TARGET = {
1651
1844
  id: "codex",
1652
1845
  configFormat: "toml",
1653
- mcpConfigPath: (home) => join2(homeRoot(home), ".codex", "config.toml"),
1654
- skillsDir: (home) => join2(homeRoot(home), ".codex", "skills")
1846
+ mcpConfigPath: (home) => join3(homeRoot(home), ".codex", "config.toml"),
1847
+ skillsDir: (home) => join3(homeRoot(home), ".codex", "skills")
1655
1848
  };
1656
1849
  var ANTIGRAVITY_TARGET = {
1657
1850
  id: "antigravity",
1658
1851
  configFormat: "json",
1659
- mcpConfigPath: (home) => join2(homeRoot(home), ".gemini", "settings.json"),
1660
- skillsDir: (home) => join2(homeRoot(home), ".gemini", "config", "skills")
1852
+ mcpConfigPath: (home) => join3(homeRoot(home), ".gemini", "settings.json"),
1853
+ skillsDir: (home) => join3(homeRoot(home), ".gemini", "config", "skills")
1661
1854
  };
1662
1855
  var CLAUDE_TARGET = {
1663
1856
  id: "claude",
1664
1857
  configFormat: "json",
1665
- mcpConfigPath: (home) => join2(homeRoot(home), ".claude.json"),
1666
- skillsDir: (home) => join2(homeRoot(home), ".claude", "skills")
1858
+ mcpConfigPath: (home) => join3(homeRoot(home), ".claude.json"),
1859
+ skillsDir: (home) => join3(homeRoot(home), ".claude", "skills")
1667
1860
  };
1668
1861
  var CLI_TARGETS = {
1669
1862
  pi: PI_TARGET,
@@ -1680,7 +1873,7 @@ function supportedCliNames() {
1680
1873
  }
1681
1874
  function readJsonConfig(configPath) {
1682
1875
  if (!existsSync2(configPath)) return {};
1683
- const parsed = JSON.parse(readFileSync2(configPath, "utf-8"));
1876
+ const parsed = JSON.parse(readFileSync3(configPath, "utf-8"));
1684
1877
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
1685
1878
  throw new Error(`configuration is not a JSON object: ${configPath}`);
1686
1879
  }
@@ -1688,8 +1881,8 @@ function readJsonConfig(configPath) {
1688
1881
  }
1689
1882
  function writeJsonConfig(configPath, value) {
1690
1883
  const temporary = `${configPath}.tmp`;
1691
- mkdirSync2(join2(configPath, ".."), { recursive: true });
1692
- writeFileSync2(temporary, JSON.stringify(value, null, 2) + "\n", "utf-8");
1884
+ mkdirSync3(join3(configPath, ".."), { recursive: true });
1885
+ writeFileSync3(temporary, JSON.stringify(value, null, 2) + "\n", "utf-8");
1693
1886
  renameSync2(temporary, configPath);
1694
1887
  }
1695
1888
  function writeJsonMcpServerEntry(configPath, serverName, entry) {
@@ -1776,35 +1969,35 @@ function registrationToTomlLines(entry) {
1776
1969
  return lines;
1777
1970
  }
1778
1971
  function writeTomlMcpServerSection(configPath, serverName, entry) {
1779
- const previous = existsSync2(configPath) ? readFileSync2(configPath, "utf-8") : "";
1972
+ const previous = existsSync2(configPath) ? readFileSync3(configPath, "utf-8") : "";
1780
1973
  const base = removeTomlSection(previous, serverName);
1781
1974
  const table = [tomlSectionHeader(serverName), ...registrationToTomlLines(entry), ""].join("\n");
1782
1975
  const content = base.length > 0 ? base.replace(/\n*$/, "\n") + table : table;
1783
1976
  const temporary = `${configPath}.tmp`;
1784
- mkdirSync2(join2(configPath, ".."), { recursive: true });
1785
- writeFileSync2(temporary, content, "utf-8");
1977
+ mkdirSync3(join3(configPath, ".."), { recursive: true });
1978
+ writeFileSync3(temporary, content, "utf-8");
1786
1979
  renameSync2(temporary, configPath);
1787
1980
  }
1788
1981
  function removeTomlMcpServerSection(configPath, serverName) {
1789
1982
  if (!existsSync2(configPath)) return false;
1790
- const previous = readFileSync2(configPath, "utf-8");
1983
+ const previous = readFileSync3(configPath, "utf-8");
1791
1984
  if (!hasTomlSection(previous, serverName)) return false;
1792
1985
  const content = removeTomlSection(previous, serverName);
1793
1986
  const temporary = `${configPath}.tmp`;
1794
- writeFileSync2(temporary, content, "utf-8");
1987
+ writeFileSync3(temporary, content, "utf-8");
1795
1988
  renameSync2(temporary, configPath);
1796
1989
  return true;
1797
1990
  }
1798
1991
  function hasTomlMcpServerSection(configPath, serverName) {
1799
1992
  if (!existsSync2(configPath)) return false;
1800
- return hasTomlSection(readFileSync2(configPath, "utf-8"), serverName);
1993
+ return hasTomlSection(readFileSync3(configPath, "utf-8"), serverName);
1801
1994
  }
1802
1995
  function listFilesRecursive(root) {
1803
1996
  if (!existsSync2(root)) return [];
1804
1997
  const files = [];
1805
1998
  const walk = (dir) => {
1806
1999
  for (const entry of readdirSync(dir)) {
1807
- const full = join2(dir, entry);
2000
+ const full = join3(dir, entry);
1808
2001
  if (statSync(full).isDirectory()) {
1809
2002
  walk(full);
1810
2003
  } else {
@@ -1816,14 +2009,14 @@ function listFilesRecursive(root) {
1816
2009
  return files;
1817
2010
  }
1818
2011
  function syncSkillTree(source, destination) {
1819
- mkdirSync2(destination, { recursive: true });
2012
+ mkdirSync3(destination, { recursive: true });
1820
2013
  cpSync(source, destination, { recursive: true, force: true });
1821
2014
  const expected = new Set(listFilesRecursive(source));
1822
2015
  const existing = listFilesRecursive(destination);
1823
2016
  existing.sort((a, b) => b.length - a.length);
1824
2017
  for (const rel of existing) {
1825
2018
  if (expected.has(rel)) continue;
1826
- rmSync(join2(destination, rel), { recursive: true, force: true });
2019
+ rmSync(join3(destination, rel), { recursive: true, force: true });
1827
2020
  }
1828
2021
  }
1829
2022
  function removeSkillDir(skillDir) {
@@ -1834,9 +2027,9 @@ function compareSkillTree(source, destination) {
1834
2027
  if (packaged.length === 0) return "MISSING";
1835
2028
  if (!existsSync2(destination)) return "MISSING";
1836
2029
  for (const rel of packaged) {
1837
- const target = join2(destination, ...rel.split("/"));
2030
+ const target = join3(destination, ...rel.split("/"));
1838
2031
  if (!existsSync2(target)) return "MISSING";
1839
- if (readFileSync2(target).toString("utf-8") !== readFileSync2(join2(source, ...rel.split("/"))).toString("utf-8")) {
2032
+ if (readFileSync3(target).toString("utf-8") !== readFileSync3(join3(source, ...rel.split("/"))).toString("utf-8")) {
1840
2033
  return "STALE";
1841
2034
  }
1842
2035
  }
@@ -1867,14 +2060,14 @@ function applyServerRegistration(target, serverName, entry, home) {
1867
2060
  }
1868
2061
 
1869
2062
  // src/utils/cliInstaller.ts
1870
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
1871
- import { join as join3, resolve as resolve3 } from "path";
2063
+ import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
2064
+ import { join as join4, resolve as resolve3 } from "path";
1872
2065
  function buildServerRegistration(apiKey) {
1873
2066
  const env = {};
1874
2067
  if (apiKey !== void 0 && apiKey.length > 0) {
1875
2068
  env.GOOGLE_MAPS_API_KEY = apiKey;
1876
2069
  }
1877
- return { command: "npx", args: ["-y", MCP_SERVER_NAME, "--stdio"], env };
2070
+ return { command: "npx", args: ["-y", MCP_SERVER_NAME, "start", "--stdio"], env };
1878
2071
  }
1879
2072
  function resolveSkillsResourcesRoot(packageRoot) {
1880
2073
  const candidate = resolve3(packageRoot, "src", "resources", "skills");
@@ -1884,13 +2077,13 @@ function resolveSkillsResourcesRoot(packageRoot) {
1884
2077
  return candidate;
1885
2078
  }
1886
2079
  function loadSkillsManifest(resourcesRoot) {
1887
- const manifestPath = join3(resourcesRoot, "manifest.json");
2080
+ const manifestPath = join4(resourcesRoot, "manifest.json");
1888
2081
  if (!existsSync3(manifestPath)) {
1889
2082
  throw new Error(`skills manifest not found: ${manifestPath}`);
1890
2083
  }
1891
2084
  let parsed;
1892
2085
  try {
1893
- parsed = JSON.parse(readFileSync3(manifestPath, "utf-8"));
2086
+ parsed = JSON.parse(readFileSync4(manifestPath, "utf-8"));
1894
2087
  } catch (error) {
1895
2088
  throw new Error(`skills manifest is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
1896
2089
  }
@@ -1903,8 +2096,8 @@ function loadSkillsManifest(resourcesRoot) {
1903
2096
  if (typeof skill.id !== "string" || typeof skill.path !== "string") {
1904
2097
  throw new Error(`skills manifest entry is missing id or path: ${manifestPath}`);
1905
2098
  }
1906
- if (!existsSync3(join3(resourcesRoot, skill.path))) {
1907
- throw new Error(`manifest skill file not found: ${join3(resourcesRoot, skill.path)}`);
2099
+ if (!existsSync3(join4(resourcesRoot, skill.path))) {
2100
+ throw new Error(`manifest skill file not found: ${join4(resourcesRoot, skill.path)}`);
1908
2101
  }
1909
2102
  return {
1910
2103
  id: skill.id,
@@ -1929,7 +2122,7 @@ function installEnabledCliResources(options) {
1929
2122
  applyServerRegistration(target, MCP_SERVER_NAME, entry, options.home);
1930
2123
  let skills = 0;
1931
2124
  for (const skill of manifest) {
1932
- syncSkillTree(join3(options.resourcesRoot, skill.id), join3(target.skillsDir(options.home), skill.id));
2125
+ syncSkillTree(join4(options.resourcesRoot, skill.id), join4(target.skillsDir(options.home), skill.id));
1933
2126
  skills += 1;
1934
2127
  }
1935
2128
  result.summaries.push({ cli: target.id, server: 1, skills });
@@ -1952,7 +2145,7 @@ function uninstallEnabledCliResources(options) {
1952
2145
  applyServerRegistration(target, MCP_SERVER_NAME, void 0, options.home);
1953
2146
  let skills = 0;
1954
2147
  for (const skill of manifest) {
1955
- removeSkillDir(join3(target.skillsDir(options.home), skill.id));
2148
+ removeSkillDir(join4(target.skillsDir(options.home), skill.id));
1956
2149
  skills += 1;
1957
2150
  }
1958
2151
  result.summaries.push({ cli: target.id, server: 0, skills });
@@ -1964,7 +2157,7 @@ function uninstallEnabledCliResources(options) {
1964
2157
  }
1965
2158
 
1966
2159
  // src/utils/cliShow.ts
1967
- import { join as join4 } from "path";
2160
+ import { join as join5 } from "path";
1968
2161
  import { relative as relative2, resolve as resolve4 } from "path";
1969
2162
  var MAX_CELL_WIDTH = 48;
1970
2163
  var STATUS_OK = "OK";
@@ -2051,7 +2244,7 @@ function buildInstallRows(home, resourcesRoot) {
2051
2244
  skill.id,
2052
2245
  target.id,
2053
2246
  "yes",
2054
- compareSkillTree(join4(resourcesRoot, skill.id), join4(target.skillsDir(home), skill.id))
2247
+ compareSkillTree(join5(resourcesRoot, skill.id), join5(target.skillsDir(home), skill.id))
2055
2248
  ]);
2056
2249
  }
2057
2250
  }
@@ -2069,7 +2262,7 @@ function buildCliShowReport(options) {
2069
2262
 
2070
2263
  // src/cli.ts
2071
2264
  var __filename = fileURLToPath(import.meta.url);
2072
- var __dirname = dirname(__filename);
2265
+ var __dirname = dirname2(__filename);
2073
2266
  function extractEnvFileOption(argv) {
2074
2267
  for (let i = 0; i < argv.length; i++) {
2075
2268
  const arg = argv[i];
@@ -2466,8 +2659,8 @@ async function runDoctor(packageVersion, apiKey, live = false, runner = execTool
2466
2659
  async function runSetup(options, deps = {}) {
2467
2660
  const fsImpl = deps.fs ?? {
2468
2661
  existsSync: (path) => existsSync4(path),
2469
- readFileSync: (path, encoding) => readFileSync4(path, encoding),
2470
- writeFileSync: (path, data, encoding) => writeFileSync3(path, data, encoding)
2662
+ readFileSync: (path, encoding) => readFileSync5(path, encoding),
2663
+ writeFileSync: (path, data, encoding) => writeFileSync4(path, data, encoding)
2471
2664
  };
2472
2665
  const nodeVersion = deps.nodeVersion ?? process.versions.node;
2473
2666
  const nodeMajor = Number.parseInt(nodeVersion.split(".")[0] ?? "0", 10);
@@ -2625,402 +2818,438 @@ if (isRunDirectly || isMainModule) {
2625
2818
  let packageVersion = "0.0.0";
2626
2819
  try {
2627
2820
  const packageJsonPath = resolve5(__dirname, "../package.json");
2628
- const packageJson = JSON.parse(readFileSync4(packageJsonPath, "utf-8"));
2821
+ const packageJson = JSON.parse(readFileSync5(packageJsonPath, "utf-8"));
2629
2822
  packageVersion = packageJson.version;
2630
2823
  } catch (e) {
2631
2824
  packageVersion = "0.0.0";
2632
2825
  }
2633
- yargs(hideBin(process.argv)).command(
2634
- "doctor",
2635
- "Check standalone CLI readiness without starting an MCP server",
2636
- (yargs2) => yargs2.option("live", {
2637
- type: "boolean",
2638
- default: false,
2639
- description: "Make billable test requests to Geocoding, Places (New), and Routes APIs"
2640
- }).option("probes", {
2826
+ const managementCommand = parseManagementCommand(hideBin(process.argv));
2827
+ if (managementCommand !== void 0) {
2828
+ void runManagementCommand(managementCommand, { currentVersion: packageVersion }).then((code) => {
2829
+ process.exitCode = code;
2830
+ }).catch((error) => {
2831
+ const message = error instanceof Error ? error.message : String(error);
2832
+ process.stderr.write(JSON.stringify({ error: message }, null, 2) + "\n");
2833
+ process.exitCode = 1;
2834
+ });
2835
+ } else {
2836
+ const buildServerCommandOptions = (yargs2) => yargs2.option("port", {
2837
+ alias: "p",
2838
+ type: "number",
2839
+ description: "Port to run the MCP server on",
2840
+ default: process.env.MCP_SERVER_PORT ? parseInt(process.env.MCP_SERVER_PORT) : 3e3
2841
+ }).option("host", {
2641
2842
  type: "string",
2642
- description: "Comma-separated subset of live probes: geocoding, places-new, routes (default: all three)"
2843
+ description: "Hostname to bind the server to (default 127.0.0.1 loopback; 0.0.0.0 for all interfaces)",
2844
+ default: process.env.MCP_SERVER_HOST || "127.0.0.1"
2643
2845
  }).option("apikey", {
2644
2846
  alias: "k",
2645
2847
  type: "string",
2646
- description: "Google Maps API key (prefer GOOGLE_MAPS_API_KEY to avoid shell history exposure)",
2848
+ description: "Google Maps API key",
2647
2849
  default: process.env.GOOGLE_MAPS_API_KEY
2648
- }).example([
2649
- ["$0 doctor", "Check local runtime and API key configuration without network calls"],
2650
- ["$0 doctor --live", "Also verify three Google Maps APIs with billable requests"],
2651
- ["$0 doctor --live --probes geocoding,routes", "Probe only the selected APIs"]
2652
- ]),
2653
- async (argv) => {
2654
- const parsedProbes = parseDoctorProbes(argv.probes);
2655
- if (parsedProbes.error) {
2656
- process.stderr.write(JSON.stringify({ error: parsedProbes.error }, null, 2) + "\n");
2657
- process.exitCode = 1;
2658
- return;
2659
- }
2660
- const report = await runDoctor(packageVersion, argv.apikey, argv.live, void 0, {
2661
- probes: parsedProbes.probes,
2662
- config: resolveRuntimeConfig(process.env, { envFile: extractEnvFileOption(process.argv) })
2663
- });
2664
- process.stdout.write(JSON.stringify(report, null, 2) + "\n");
2665
- process.exitCode = report.success ? 0 : 1;
2666
- }
2667
- ).command(
2668
- "setup",
2669
- "Non-interactive onboarding: verify local readiness, optionally scaffold .env",
2670
- (yargs2) => yargs2.option("write-env", {
2850
+ }).option("stdio", {
2671
2851
  type: "boolean",
2672
- default: false,
2673
- description: "Create .env from .env.example in --env-dir when it does not exist (never overwrites)"
2674
- }).option("env-dir", {
2675
- type: "string",
2676
- default: process.cwd(),
2677
- description: "Directory where .env is looked up / created"
2678
- }).example([
2679
- ["$0 setup", "Check readiness without writing anything"],
2680
- ["$0 setup --write-env", "Also scaffold .env from the package template"]
2681
- ]),
2682
- async (argv) => {
2683
- const report = await runSetup({
2684
- packageDir: resolve5(__dirname, ".."),
2685
- targetDir: argv.envDir,
2686
- writeEnv: argv.writeEnv
2687
- });
2688
- process.stdout.write(JSON.stringify(report, null, 2) + "\n");
2689
- process.exitCode = report.success ? 0 : 1;
2690
- }
2691
- ).command(
2692
- "snippet",
2693
- "Print an MCP client registration snippet (JSON on stdout; never writes files)",
2694
- (yargs2) => yargs2.option("client", {
2695
- type: "string",
2696
- choices: ["generic", "claude", "cursor", "pi"],
2697
- default: "generic",
2698
- description: "Target client (selects the documented target file)"
2699
- }).option("transport", {
2700
- type: "string",
2701
- choices: ["stdio", "http"],
2702
- default: "stdio",
2703
- description: "MCP transport of the snippet"
2704
- }).option("launcher", {
2705
- type: "string",
2706
- choices: ["npx", "node", "bin"],
2707
- default: "npx",
2708
- description: "stdio launcher command"
2709
- }).option("command", {
2710
- type: "string",
2711
- description: "Absolute path to dist/cli.js (required for --launcher node)"
2712
- }).option("host", {
2713
- type: "string",
2714
- default: "127.0.0.1",
2715
- description: "Host used in the URL (transport http)"
2716
- }).option("port", {
2717
- type: "number",
2718
- default: 3e3,
2719
- description: "Port used in the URL (transport http)"
2720
- }).option("env-key", {
2721
- type: "string",
2722
- description: "Emit a ${NAME} variable reference instead of a literal placeholder (expansion is client-specific)"
2723
- }).option("name", {
2724
- type: "string",
2725
- default: "mcp-google-map",
2726
- description: "Server name inside mcpServers"
2852
+ description: "Use stdio transport instead of HTTP",
2853
+ default: false
2727
2854
  }).example([
2728
- ["$0 snippet --client claude", "stdio snippet using the npx launcher"],
2729
- ["$0 snippet --client pi --launcher node --command /abs/path/dist/cli.js", "stdio snippet with an explicit artifact"],
2730
- ["$0 snippet --transport http --port 3100", "HTTP URL snippet"]
2731
- ]),
2732
- (argv) => {
2733
- process.exitCode = runSnippetCommand({
2734
- client: argv.client,
2735
- transport: argv.transport,
2736
- launcher: argv.launcher,
2737
- commandPath: argv.command,
2738
- host: argv.host,
2739
- port: argv.port,
2740
- envKey: argv.envKey,
2741
- serverName: argv.name
2742
- });
2743
- }
2744
- ).command(
2745
- "enable <cli>",
2746
- "Enable MCP-server and skill installation for a supported CLI",
2747
- (yargs2) => yargs2.positional("cli", {
2748
- type: "string",
2749
- describe: `CLI name: ${supportedCliNames()}`
2750
- }).option("home", {
2751
- type: "string",
2752
- description: "Home-directory override for the settings file (default: user home)"
2753
- }).example([["$0 enable pi", "Enable pi for install/uninstall/show"]]),
2754
- (argv) => {
2755
- process.exitCode = runEnableDisableCliCommand(argv.cli, true, {
2756
- home: argv.home
2757
- });
2758
- }
2759
- ).command(
2760
- "disable <cli>",
2761
- "Disable MCP-server and skill installation for a supported CLI",
2762
- (yargs2) => yargs2.positional("cli", {
2763
- type: "string",
2764
- describe: `CLI name: ${supportedCliNames()}`
2765
- }).option("home", {
2766
- type: "string",
2767
- description: "Home-directory override for the settings file (default: user home)"
2768
- }).example([["$0 disable claude", "Disable claude for install/uninstall/show"]]),
2769
- (argv) => {
2770
- process.exitCode = runEnableDisableCliCommand(argv.cli, false, {
2771
- home: argv.home
2772
- });
2773
- }
2774
- ).command(
2775
- "install",
2776
- "Register the mcp-google-map stdio server and install packaged skills for every enabled CLI",
2777
- (yargs2) => yargs2.option("home", {
2778
- type: "string",
2779
- description: "Home-directory override for CLI configuration paths (default: user home)"
2780
- }).option("apikey", {
2781
- alias: "k",
2782
- type: "string",
2783
- description: "Google Maps API key embedded in the registered entry (prefer GOOGLE_MAPS_API_KEY)",
2784
- default: resolveRuntimeConfig(process.env, { envFile: extractEnvFileOption(process.argv) }).apiKey
2785
- }).example([["$0 install", "Register the server and skills in every enabled CLI"]]),
2786
- (argv) => {
2787
- process.exitCode = runInstallUninstallCommand("install", {
2788
- home: argv.home,
2789
- apiKey: argv.apikey,
2790
- resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, ".."))
2791
- });
2792
- }
2793
- ).command(
2794
- "uninstall",
2795
- "Remove the mcp-google-map server entry and managed skills from every enabled CLI",
2796
- (yargs2) => yargs2.option("home", {
2797
- type: "string",
2798
- description: "Home-directory override for CLI configuration paths (default: user home)"
2799
- }).example([["$0 uninstall", "Reciprocal removal of install for every enabled CLI"]]),
2800
- (argv) => {
2801
- process.exitCode = runInstallUninstallCommand("uninstall", {
2802
- home: argv.home,
2803
- resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, ".."))
2804
- });
2805
- }
2806
- ).command(
2807
- "show",
2808
- "Show CLI configuration and installation status tables (human-readable)",
2809
- (yargs2) => yargs2.option("home", {
2810
- type: "string",
2811
- description: "Home-directory override for CLI configuration paths (default: user home)"
2812
- }).example([["$0 show", "Print CLI Configuration and Installation Status tables"]]),
2813
- (argv) => {
2814
- process.exitCode = runShowCommand({
2815
- home: argv.home,
2816
- resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, ".."))
2817
- });
2818
- }
2819
- ).command(
2820
- "exec <tool> [params]",
2821
- "Execute a tool directly and output JSON",
2822
- (yargs2) => {
2823
- return yargs2.positional("tool", {
2824
- type: "string",
2825
- describe: `Tool name: ${EXEC_TOOLS.join(", ")}`
2826
- }).positional("params", {
2855
+ ["$0 start", "Start HTTP server with default settings"],
2856
+ ['$0 start --port 3000 --apikey "your_api_key"', "Start HTTP with custom port and API key"],
2857
+ ["$0 start --host 0.0.0.0 --port 3000", "Start HTTP accessible from all interfaces"],
2858
+ ["$0 start --stdio", "Start in stdio mode (for MCP clients)"],
2859
+ ["$0 run --stdio", "Alias: run the server in stdio mode"]
2860
+ ]);
2861
+ const runServerCommand = async (argv) => {
2862
+ if (argv.apikey) {
2863
+ process.env.GOOGLE_MAPS_API_KEY = argv.apikey;
2864
+ }
2865
+ void checkVersionIdle({ currentVersion: packageVersion }).catch(() => void 0);
2866
+ const tools = filterTools(config_default[0].tools);
2867
+ if (argv.stdio) {
2868
+ const server = new BaseMcpServer(config_default[0].name, tools);
2869
+ await server.startStdio();
2870
+ } else {
2871
+ Logger.log("\u{1F5FA}\uFE0F Google Maps MCP Server");
2872
+ Logger.log(" A Model Context Protocol server for Google Maps services");
2873
+ Logger.log("");
2874
+ if (!argv.apikey) {
2875
+ Logger.log("\u26A0\uFE0F Google Maps API Key not found!");
2876
+ Logger.log(" Please provide --apikey parameter or set GOOGLE_MAPS_API_KEY in your .env file");
2877
+ Logger.log("");
2878
+ }
2879
+ startServer(argv.port, argv.apikey, argv.host).then((outcome) => {
2880
+ if (outcome.started === 0) {
2881
+ process.exit(1);
2882
+ }
2883
+ }).catch((error) => {
2884
+ Logger.error("\u274C Failed to start server:", error);
2885
+ process.exit(1);
2886
+ });
2887
+ }
2888
+ };
2889
+ const cli = yargs(hideBin(process.argv)).scriptName("mcp-google-map").usage(
2890
+ `mcp-google-map v${packageVersion}
2891
+
2892
+ Usage: mcp-google-map <command> [options]
2893
+ mcp-google-map start|run [--stdio] [options]`
2894
+ ).command(
2895
+ "doctor",
2896
+ "Check standalone CLI readiness without starting an MCP server",
2897
+ (yargs2) => yargs2.option("live", {
2898
+ type: "boolean",
2899
+ default: false,
2900
+ description: "Make billable test requests to Geocoding, Places (New), and Routes APIs"
2901
+ }).option("probes", {
2827
2902
  type: "string",
2828
- describe: "JSON parameters string"
2903
+ description: "Comma-separated subset of live probes: geocoding, places-new, routes (default: all three)"
2829
2904
  }).option("apikey", {
2830
2905
  alias: "k",
2831
2906
  type: "string",
2832
- description: "Google Maps API key",
2907
+ description: "Google Maps API key (prefer GOOGLE_MAPS_API_KEY to avoid shell history exposure)",
2833
2908
  default: process.env.GOOGLE_MAPS_API_KEY
2834
2909
  }).example([
2835
- [`$0 exec geocode '{"address":"Tokyo Tower"}'`, "Geocode an address"],
2836
- [
2837
- `$0 exec search-nearby '{"center":{"value":"35.68,139.74","isCoordinates":true},"keyword":"restaurant"}'`,
2838
- "Search nearby"
2839
- ],
2840
- [`$0 exec search-places '{"query":"ramen in Tokyo"}'`, "Text search"]
2841
- ]);
2842
- },
2843
- async (argv) => {
2844
- if (!argv.apikey) {
2845
- process.stderr.write(
2846
- JSON.stringify(
2847
- {
2848
- error: "GOOGLE_MAPS_API_KEY not set. Use --apikey or set GOOGLE_MAPS_API_KEY environment variable."
2849
- },
2850
- null,
2851
- 2
2852
- ) + "\n"
2853
- );
2854
- process.exitCode = 1;
2855
- return;
2910
+ ["$0 doctor", "Check local runtime and API key configuration without network calls"],
2911
+ ["$0 doctor --live", "Also verify three Google Maps APIs with billable requests"],
2912
+ ["$0 doctor --live --probes geocoding,routes", "Probe only the selected APIs"]
2913
+ ]),
2914
+ async (argv) => {
2915
+ const parsedProbes = parseDoctorProbes(argv.probes);
2916
+ if (parsedProbes.error) {
2917
+ process.stderr.write(JSON.stringify({ error: parsedProbes.error }, null, 2) + "\n");
2918
+ process.exitCode = 1;
2919
+ return;
2920
+ }
2921
+ const report = await runDoctor(packageVersion, argv.apikey, argv.live, void 0, {
2922
+ probes: parsedProbes.probes,
2923
+ config: resolveRuntimeConfig(process.env, { envFile: extractEnvFileOption(process.argv) })
2924
+ });
2925
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
2926
+ process.exitCode = report.success ? 0 : 1;
2856
2927
  }
2857
- try {
2858
- const params = argv.params ? JSON.parse(argv.params) : {};
2859
- process.exitCode = await runExecCommand(argv.tool, params, argv.apikey);
2860
- } catch (error) {
2861
- process.stderr.write(JSON.stringify({ error: error.message }, null, 2) + "\n");
2862
- process.exitCode = 1;
2928
+ ).command(
2929
+ "setup",
2930
+ "Non-interactive onboarding: verify local readiness, optionally scaffold .env",
2931
+ (yargs2) => yargs2.option("write-env", {
2932
+ type: "boolean",
2933
+ default: false,
2934
+ description: "Create .env from .env.example in --env-dir when it does not exist (never overwrites)"
2935
+ }).option("env-dir", {
2936
+ type: "string",
2937
+ default: process.cwd(),
2938
+ description: "Directory where .env is looked up / created"
2939
+ }).example([
2940
+ ["$0 setup", "Check readiness without writing anything"],
2941
+ ["$0 setup --write-env", "Also scaffold .env from the package template"]
2942
+ ]),
2943
+ async (argv) => {
2944
+ const report = await runSetup({
2945
+ packageDir: resolve5(__dirname, ".."),
2946
+ targetDir: argv.envDir,
2947
+ writeEnv: argv.writeEnv
2948
+ });
2949
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
2950
+ process.exitCode = report.success ? 0 : 1;
2863
2951
  }
2864
- }
2865
- ).command(
2866
- "batch-geocode",
2867
- "Geocode multiple addresses from a file (one address per line)",
2868
- (yargs2) => {
2869
- return yargs2.option("input", {
2870
- alias: "i",
2952
+ ).command(
2953
+ "snippet",
2954
+ "Print an MCP client registration snippet (JSON on stdout; never writes files)",
2955
+ (yargs2) => yargs2.option("client", {
2956
+ type: "string",
2957
+ choices: ["generic", "claude", "cursor", "pi"],
2958
+ default: "generic",
2959
+ description: "Target client (selects the documented target file)"
2960
+ }).option("transport", {
2961
+ type: "string",
2962
+ choices: ["stdio", "http"],
2963
+ default: "stdio",
2964
+ description: "MCP transport of the snippet"
2965
+ }).option("launcher", {
2871
2966
  type: "string",
2872
- describe: "Input file path (one address per line). Use - for stdin.",
2873
- demandOption: true
2874
- }).option("output", {
2875
- alias: "o",
2967
+ choices: ["npx", "node", "bin"],
2968
+ default: "npx",
2969
+ description: "stdio launcher command"
2970
+ }).option("command", {
2876
2971
  type: "string",
2877
- describe: "Output file path (JSON). Defaults to stdout."
2878
- }).option("concurrency", {
2879
- alias: "c",
2972
+ description: "Absolute path to dist/cli.js (required for --launcher node)"
2973
+ }).option("host", {
2974
+ type: "string",
2975
+ default: "127.0.0.1",
2976
+ description: "Host used in the URL (transport http)"
2977
+ }).option("port", {
2880
2978
  type: "number",
2881
- describe: "Max parallel requests",
2882
- default: 20
2979
+ default: 3e3,
2980
+ description: "Port used in the URL (transport http)"
2981
+ }).option("env-key", {
2982
+ type: "string",
2983
+ description: "Emit a ${NAME} variable reference instead of a literal placeholder (expansion is client-specific)"
2984
+ }).option("name", {
2985
+ type: "string",
2986
+ default: "mcp-google-map",
2987
+ description: "Server name inside mcpServers"
2988
+ }).example([
2989
+ ["$0 snippet --client claude", "stdio snippet using the npx launcher"],
2990
+ ["$0 snippet --client pi --launcher node --command /abs/path/dist/cli.js", "stdio snippet with an explicit artifact"],
2991
+ ["$0 snippet --transport http --port 3100", "HTTP URL snippet"]
2992
+ ]),
2993
+ (argv) => {
2994
+ process.exitCode = runSnippetCommand({
2995
+ client: argv.client,
2996
+ transport: argv.transport,
2997
+ launcher: argv.launcher,
2998
+ commandPath: argv.command,
2999
+ host: argv.host,
3000
+ port: argv.port,
3001
+ envKey: argv.envKey,
3002
+ serverName: argv.name
3003
+ });
3004
+ }
3005
+ ).command(
3006
+ "enable <cli>",
3007
+ "Enable MCP-server and skill installation for a supported CLI",
3008
+ (yargs2) => yargs2.positional("cli", {
3009
+ type: "string",
3010
+ describe: `CLI name: ${supportedCliNames()}`
3011
+ }).option("home", {
3012
+ type: "string",
3013
+ description: "Home-directory override for the settings file (default: user home)"
3014
+ }).example([["$0 enable pi", "Enable pi for install/uninstall/show"]]),
3015
+ (argv) => {
3016
+ process.exitCode = runEnableDisableCliCommand(argv.cli, true, {
3017
+ home: argv.home
3018
+ });
3019
+ }
3020
+ ).command(
3021
+ "disable <cli>",
3022
+ "Disable MCP-server and skill installation for a supported CLI",
3023
+ (yargs2) => yargs2.positional("cli", {
3024
+ type: "string",
3025
+ describe: `CLI name: ${supportedCliNames()}`
3026
+ }).option("home", {
3027
+ type: "string",
3028
+ description: "Home-directory override for the settings file (default: user home)"
3029
+ }).example([["$0 disable claude", "Disable claude for install/uninstall/show"]]),
3030
+ (argv) => {
3031
+ process.exitCode = runEnableDisableCliCommand(argv.cli, false, {
3032
+ home: argv.home
3033
+ });
3034
+ }
3035
+ ).command(
3036
+ "install",
3037
+ "Register the mcp-google-map stdio server and install packaged skills for every enabled CLI",
3038
+ (yargs2) => yargs2.option("home", {
3039
+ type: "string",
3040
+ description: "Home-directory override for CLI configuration paths (default: user home)"
2883
3041
  }).option("apikey", {
2884
3042
  alias: "k",
2885
3043
  type: "string",
2886
- description: "Google Maps API key",
2887
- default: process.env.GOOGLE_MAPS_API_KEY
2888
- }).example([
2889
- ["$0 batch-geocode -i addresses.txt", "Geocode to stdout"],
2890
- ["$0 batch-geocode -i addresses.txt -o results.json", "Geocode to file"],
2891
- ["cat addresses.txt | $0 batch-geocode -i -", "Geocode from stdin"]
2892
- ]);
2893
- },
2894
- async (argv) => {
2895
- if (!argv.apikey) {
2896
- console.error("Error: GOOGLE_MAPS_API_KEY not set. Use --apikey or set env var.");
2897
- process.exit(1);
3044
+ description: "Google Maps API key embedded in the registered entry (prefer GOOGLE_MAPS_API_KEY)",
3045
+ default: resolveRuntimeConfig(process.env, { envFile: extractEnvFileOption(process.argv) }).apiKey
3046
+ }).example([["$0 install", "Register the server and skills in every enabled CLI"]]),
3047
+ (argv) => {
3048
+ process.exitCode = runInstallUninstallCommand("install", {
3049
+ home: argv.home,
3050
+ apiKey: argv.apikey,
3051
+ resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, ".."))
3052
+ });
2898
3053
  }
2899
- let lines;
2900
- if (argv.input === "-") {
2901
- const rl = createInterface({ input: process.stdin });
2902
- lines = [];
2903
- for await (const line of rl) {
2904
- const trimmed = line.trim();
2905
- if (trimmed) lines.push(trimmed);
2906
- }
2907
- } else {
2908
- if (!existsSync4(argv.input)) {
2909
- console.error(`Error: File not found: ${argv.input}`);
2910
- process.exit(1);
2911
- }
2912
- lines = readFileSync4(argv.input, "utf-8").split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
3054
+ ).command(
3055
+ "uninstall",
3056
+ "Remove the mcp-google-map server entry and managed skills from every enabled CLI",
3057
+ (yargs2) => yargs2.option("home", {
3058
+ type: "string",
3059
+ description: "Home-directory override for CLI configuration paths (default: user home)"
3060
+ }).example([["$0 uninstall", "Reciprocal removal of install for every enabled CLI"]]),
3061
+ (argv) => {
3062
+ process.exitCode = runInstallUninstallCommand("uninstall", {
3063
+ home: argv.home,
3064
+ resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, ".."))
3065
+ });
2913
3066
  }
2914
- if (lines.length === 0) {
2915
- console.error("Error: No addresses found in input.");
2916
- process.exit(1);
3067
+ ).command(
3068
+ "show",
3069
+ "Show CLI configuration and installation status tables (human-readable)",
3070
+ (yargs2) => yargs2.option("home", {
3071
+ type: "string",
3072
+ description: "Home-directory override for CLI configuration paths (default: user home)"
3073
+ }).example([["$0 show", "Print CLI Configuration and Installation Status tables"]]),
3074
+ (argv) => {
3075
+ process.exitCode = runShowCommand({
3076
+ home: argv.home,
3077
+ resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, ".."))
3078
+ });
2917
3079
  }
2918
- const searcher = new PlacesSearcher(argv.apikey);
2919
- const concurrency = Math.min(Math.max(argv.concurrency, 1), 50);
2920
- const results = [];
2921
- let completed = 0;
2922
- const semaphore = async (tasks2, limit) => {
2923
- const executing = [];
2924
- for (const task of tasks2) {
2925
- const p = task().then(() => {
2926
- executing.splice(executing.indexOf(p), 1);
2927
- });
2928
- executing.push(p);
2929
- if (executing.length >= limit) {
2930
- await Promise.race(executing);
2931
- }
3080
+ ).command(
3081
+ "exec <tool> [params]",
3082
+ "Execute a tool directly and output JSON",
3083
+ (yargs2) => {
3084
+ return yargs2.positional("tool", {
3085
+ type: "string",
3086
+ describe: `Tool name: ${EXEC_TOOLS.join(", ")}`
3087
+ }).positional("params", {
3088
+ type: "string",
3089
+ describe: "JSON parameters string"
3090
+ }).option("apikey", {
3091
+ alias: "k",
3092
+ type: "string",
3093
+ description: "Google Maps API key",
3094
+ default: process.env.GOOGLE_MAPS_API_KEY
3095
+ }).example([
3096
+ [`$0 exec geocode '{"address":"Tokyo Tower"}'`, "Geocode an address"],
3097
+ [
3098
+ `$0 exec search-nearby '{"center":{"value":"35.68,139.74","isCoordinates":true},"keyword":"restaurant"}'`,
3099
+ "Search nearby"
3100
+ ],
3101
+ [`$0 exec search-places '{"query":"ramen in Tokyo"}'`, "Text search"]
3102
+ ]);
3103
+ },
3104
+ async (argv) => {
3105
+ if (!argv.apikey) {
3106
+ process.stderr.write(
3107
+ JSON.stringify(
3108
+ {
3109
+ error: "GOOGLE_MAPS_API_KEY not set. Use --apikey or set GOOGLE_MAPS_API_KEY environment variable."
3110
+ },
3111
+ null,
3112
+ 2
3113
+ ) + "\n"
3114
+ );
3115
+ process.exitCode = 1;
3116
+ return;
2932
3117
  }
2933
- await Promise.all(executing);
2934
- };
2935
- const tasks = lines.map((address, index) => async () => {
2936
3118
  try {
2937
- const result = await searcher.geocode(address);
2938
- results[index] = { address, ...result };
3119
+ const params = argv.params ? JSON.parse(argv.params) : {};
3120
+ process.exitCode = await runExecCommand(argv.tool, params, argv.apikey);
2939
3121
  } catch (error) {
2940
- results[index] = { address, success: false, error: error.message };
3122
+ process.stderr.write(JSON.stringify({ error: error.message }, null, 2) + "\n");
3123
+ process.exitCode = 1;
2941
3124
  }
2942
- completed++;
2943
- if (!argv.output) return;
2944
- process.stderr.write(`\r ${completed}/${lines.length} geocoded`);
2945
- });
2946
- await semaphore(tasks, concurrency);
2947
- if (argv.output) {
2948
- process.stderr.write("\n");
2949
3125
  }
2950
- const succeeded = results.filter((r) => r.success).length;
2951
- const failed = results.filter((r) => !r.success).length;
2952
- const summary = { total: lines.length, succeeded, failed, results };
2953
- const json = JSON.stringify(summary, null, 2);
2954
- if (argv.output) {
2955
- writeFileSync3(argv.output, json, "utf-8");
2956
- console.error(`Done: ${succeeded}/${lines.length} succeeded. Output: ${argv.output}`);
2957
- } else {
2958
- console.log(json);
2959
- }
2960
- process.exit(failed > 0 ? 1 : 0);
2961
- }
2962
- ).command(
2963
- "$0",
2964
- "Start the MCP server (HTTP by default, --stdio for stdio mode)",
2965
- (yargs2) => {
2966
- return yargs2.option("port", {
2967
- alias: "p",
2968
- type: "number",
2969
- description: "Port to run the MCP server on",
2970
- default: process.env.MCP_SERVER_PORT ? parseInt(process.env.MCP_SERVER_PORT) : 3e3
2971
- }).option("host", {
2972
- type: "string",
2973
- description: "Hostname to bind the server to (default 127.0.0.1 loopback; 0.0.0.0 for all interfaces)",
2974
- default: process.env.MCP_SERVER_HOST || "127.0.0.1"
2975
- }).option("apikey", {
2976
- alias: "k",
2977
- type: "string",
2978
- description: "Google Maps API key",
2979
- default: process.env.GOOGLE_MAPS_API_KEY
2980
- }).option("stdio", {
2981
- type: "boolean",
2982
- description: "Use stdio transport instead of HTTP",
2983
- default: false
2984
- }).example([
2985
- ["$0", "Start HTTP server with default settings"],
2986
- ['$0 --port 3000 --apikey "your_api_key"', "Start HTTP with custom port and API key"],
2987
- ["$0 --host 0.0.0.0 --port 3000", "Start HTTP accessible from all interfaces"],
2988
- ["$0 --stdio", "Start in stdio mode (for Claude Desktop, Cursor, etc.)"]
2989
- ]);
2990
- },
2991
- async (argv) => {
2992
- if (argv.apikey) {
2993
- process.env.GOOGLE_MAPS_API_KEY = argv.apikey;
2994
- }
2995
- void checkForUpdates({ currentVersion: packageVersion }).catch(() => void 0);
2996
- const tools = filterTools(config_default[0].tools);
2997
- if (argv.stdio) {
2998
- const server = new BaseMcpServer(config_default[0].name, tools);
2999
- await server.startStdio();
3000
- } else {
3001
- Logger.log("\u{1F5FA}\uFE0F Google Maps MCP Server");
3002
- Logger.log(" A Model Context Protocol server for Google Maps services");
3003
- Logger.log("");
3126
+ ).command(
3127
+ "batch-geocode",
3128
+ "Geocode multiple addresses from a file (one address per line)",
3129
+ (yargs2) => {
3130
+ return yargs2.option("input", {
3131
+ alias: "i",
3132
+ type: "string",
3133
+ describe: "Input file path (one address per line). Use - for stdin.",
3134
+ demandOption: true
3135
+ }).option("output", {
3136
+ alias: "o",
3137
+ type: "string",
3138
+ describe: "Output file path (JSON). Defaults to stdout."
3139
+ }).option("concurrency", {
3140
+ alias: "c",
3141
+ type: "number",
3142
+ describe: "Max parallel requests",
3143
+ default: 20
3144
+ }).option("apikey", {
3145
+ alias: "k",
3146
+ type: "string",
3147
+ description: "Google Maps API key",
3148
+ default: process.env.GOOGLE_MAPS_API_KEY
3149
+ }).example([
3150
+ ["$0 batch-geocode -i addresses.txt", "Geocode to stdout"],
3151
+ ["$0 batch-geocode -i addresses.txt -o results.json", "Geocode to file"],
3152
+ ["cat addresses.txt | $0 batch-geocode -i -", "Geocode from stdin"]
3153
+ ]);
3154
+ },
3155
+ async (argv) => {
3004
3156
  if (!argv.apikey) {
3005
- Logger.log("\u26A0\uFE0F Google Maps API Key not found!");
3006
- Logger.log(" Please provide --apikey parameter or set GOOGLE_MAPS_API_KEY in your .env file");
3007
- Logger.log("");
3157
+ console.error("Error: GOOGLE_MAPS_API_KEY not set. Use --apikey or set env var.");
3158
+ process.exit(1);
3008
3159
  }
3009
- startServer(argv.port, argv.apikey, argv.host).then((outcome) => {
3010
- if (outcome.started === 0) {
3160
+ let lines;
3161
+ if (argv.input === "-") {
3162
+ const rl = createInterface({ input: process.stdin });
3163
+ lines = [];
3164
+ for await (const line of rl) {
3165
+ const trimmed = line.trim();
3166
+ if (trimmed) lines.push(trimmed);
3167
+ }
3168
+ } else {
3169
+ if (!existsSync4(argv.input)) {
3170
+ console.error(`Error: File not found: ${argv.input}`);
3011
3171
  process.exit(1);
3012
3172
  }
3013
- }).catch((error) => {
3014
- Logger.error("\u274C Failed to start server:", error);
3173
+ lines = readFileSync5(argv.input, "utf-8").split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
3174
+ }
3175
+ if (lines.length === 0) {
3176
+ console.error("Error: No addresses found in input.");
3015
3177
  process.exit(1);
3178
+ }
3179
+ const searcher = new PlacesSearcher(argv.apikey);
3180
+ const concurrency = Math.min(Math.max(argv.concurrency, 1), 50);
3181
+ const results = [];
3182
+ let completed = 0;
3183
+ const semaphore = async (tasks2, limit) => {
3184
+ const executing = [];
3185
+ for (const task of tasks2) {
3186
+ const p = task().then(() => {
3187
+ executing.splice(executing.indexOf(p), 1);
3188
+ });
3189
+ executing.push(p);
3190
+ if (executing.length >= limit) {
3191
+ await Promise.race(executing);
3192
+ }
3193
+ }
3194
+ await Promise.all(executing);
3195
+ };
3196
+ const tasks = lines.map((address, index) => async () => {
3197
+ try {
3198
+ const result = await searcher.geocode(address);
3199
+ results[index] = { address, ...result };
3200
+ } catch (error) {
3201
+ results[index] = { address, success: false, error: error.message };
3202
+ }
3203
+ completed++;
3204
+ if (!argv.output) return;
3205
+ process.stderr.write(`\r ${completed}/${lines.length} geocoded`);
3016
3206
  });
3207
+ await semaphore(tasks, concurrency);
3208
+ if (argv.output) {
3209
+ process.stderr.write("\n");
3210
+ }
3211
+ const succeeded = results.filter((r) => r.success).length;
3212
+ const failed = results.filter((r) => !r.success).length;
3213
+ const summary = { total: lines.length, succeeded, failed, results };
3214
+ const json = JSON.stringify(summary, null, 2);
3215
+ if (argv.output) {
3216
+ writeFileSync4(argv.output, json, "utf-8");
3217
+ console.error(`Done: ${succeeded}/${lines.length} succeeded. Output: ${argv.output}`);
3218
+ } else {
3219
+ console.log(json);
3220
+ }
3221
+ process.exit(failed > 0 ? 1 : 0);
3017
3222
  }
3018
- }
3019
- ).version(packageVersion).alias("version", "v").option("env-file", {
3020
- type: "string",
3021
- global: true,
3022
- description: "Load environment variables from this exact file (error if missing; no implicit .env fallback)"
3023
- }).help().parse();
3223
+ ).command(
3224
+ "start",
3225
+ "Start the MCP server (HTTP by default, --stdio for stdio mode)",
3226
+ buildServerCommandOptions,
3227
+ runServerCommand
3228
+ ).command(
3229
+ "run",
3230
+ "Alias of start: run the MCP server (HTTP by default, --stdio for stdio mode)",
3231
+ buildServerCommandOptions,
3232
+ runServerCommand
3233
+ ).command(
3234
+ "$0",
3235
+ "Print the help text (use start or run to launch the MCP server)",
3236
+ (yargs2) => yargs2,
3237
+ () => {
3238
+ cli.showHelp("log");
3239
+ }
3240
+ ).version(packageVersion).alias("version", "v").option("env-file", {
3241
+ type: "string",
3242
+ global: true,
3243
+ description: "Load environment variables from this exact file (error if missing; no implicit .env fallback)"
3244
+ }).epilog(
3245
+ `Management commands (single flags, dispatched before subcommands):
3246
+ --ver Print the installed version and force one update check
3247
+ --version Alias of --ver
3248
+ --upgrade Upgrade the global package to the latest version and refresh installed skills
3249
+ --uninstall Remove the globally installed mcp-google-map package`
3250
+ ).help();
3251
+ cli.parse();
3252
+ }
3024
3253
  }
3025
3254
  export {
3026
3255
  DOCTOR_PROBES,