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/README.md +14 -14
- package/dist/cli.js +723 -494
- package/dist/cli.js.map +1 -1
- package/docs/CONFIGURATION.md +7 -7
- package/package.json +1 -1
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
|
|
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
|
|
1627
|
-
readFileSync as
|
|
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
|
|
1825
|
+
writeFileSync as writeFileSync3
|
|
1633
1826
|
} from "fs";
|
|
1634
|
-
import { join as
|
|
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) =>
|
|
1642
|
-
skillsDir: (home) =>
|
|
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) =>
|
|
1648
|
-
skillsDir: (home) =>
|
|
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) =>
|
|
1654
|
-
skillsDir: (home) =>
|
|
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) =>
|
|
1660
|
-
skillsDir: (home) =>
|
|
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) =>
|
|
1666
|
-
skillsDir: (home) =>
|
|
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(
|
|
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
|
-
|
|
1692
|
-
|
|
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) ?
|
|
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
|
-
|
|
1785
|
-
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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(
|
|
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 =
|
|
2030
|
+
const target = join3(destination, ...rel.split("/"));
|
|
1838
2031
|
if (!existsSync2(target)) return "MISSING";
|
|
1839
|
-
if (
|
|
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
|
|
1871
|
-
import { join as
|
|
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 =
|
|
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(
|
|
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(
|
|
1907
|
-
throw new Error(`manifest skill file not found: ${
|
|
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(
|
|
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(
|
|
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
|
|
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(
|
|
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 =
|
|
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) =>
|
|
2470
|
-
writeFileSync: (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(
|
|
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
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
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: "
|
|
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
|
|
2848
|
+
description: "Google Maps API key",
|
|
2647
2849
|
default: process.env.GOOGLE_MAPS_API_KEY
|
|
2648
|
-
}).
|
|
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
|
-
|
|
2673
|
-
|
|
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
|
|
2729
|
-
[
|
|
2730
|
-
["$0
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
)
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
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
|
-
|
|
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
|
-
[
|
|
2836
|
-
[
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
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
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
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
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
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
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2967
|
+
choices: ["npx", "node", "bin"],
|
|
2968
|
+
default: "npx",
|
|
2969
|
+
description: "stdio launcher command"
|
|
2970
|
+
}).option("command", {
|
|
2876
2971
|
type: "string",
|
|
2877
|
-
|
|
2878
|
-
}).option("
|
|
2879
|
-
|
|
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
|
-
|
|
2882
|
-
|
|
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.
|
|
2888
|
-
}).example([
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
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
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
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
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
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
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
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
|
|
2938
|
-
|
|
3119
|
+
const params = argv.params ? JSON.parse(argv.params) : {};
|
|
3120
|
+
process.exitCode = await runExecCommand(argv.tool, params, argv.apikey);
|
|
2939
3121
|
} catch (error) {
|
|
2940
|
-
|
|
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
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
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
|
-
|
|
3006
|
-
|
|
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
|
-
|
|
3010
|
-
|
|
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
|
-
|
|
3014
|
-
|
|
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
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
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,
|