mcp-google-map 0.9.0 → 0.10.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 CHANGED
@@ -1,4 +1,4 @@
1
- # mcp-google-map (0.9.0)
1
+ # mcp-google-map (0.10.0)
2
2
 
3
3
  <p align="center">
4
4
  <img src="https://img.shields.io/badge/node-%3E%3D22-339933?style=flat-square&logo=nodedotjs&logoColor=white" alt="Node.js >= 22">
@@ -164,6 +164,7 @@ mcp-google-map doctor --live --probes geocoding,routes # probe only the selecte
164
164
  mcp-google-map exec geocode '{"address":"Tokyo Tower"}' # one tool call from the terminal
165
165
  mcp-google-map batch-geocode -i addresses.txt -o results.json
166
166
  mcp-google-map enable pi claude # enable MCP registration + skills for specific CLIs
167
+ mcp-google-map api-key "AIza..." # save the API key in the user settings and refresh every enabled CLI registration
167
168
  mcp-google-map install # register the stdio server and install skills in every enabled CLI
168
169
  mcp-google-map uninstall # reciprocal removal of install in every enabled CLI
169
170
  mcp-google-map show # CLI Configuration and Installation Status tables
@@ -178,9 +179,10 @@ mcp-google-map snippet --client cursor # print an MCP client re
178
179
  - `snippet` prints a valid `mcpServers` JSON registration to stdout (guidance notes on stderr) and never writes or edits configuration files; by default it embeds a literal placeholder, and `--env-key NAME` emits a `${NAME}` reference whose expansion is client-specific.
179
180
  - `--env-file <path>` loads exactly the given environment file for any command and exits 1 with a JSON error when the file is missing (no implicit `.env` fallback).
180
181
  - `enable <cli>` / `disable <cli>` manage the persisted enabled-CLI set at `~/.config/mcp-google-map/config.json`; accepted names (case-insensitive): `pi`, `openclaw`, `codex`, `antigravity`, `claude`; unsupported names exit 2 listing the supported ones.
181
- - `install` registers for every enabled CLI the stdio server entry `mcp-google-map` (`npx -y mcp-google-map start --stdio`, embedding the resolved `GOOGLE_MAPS_API_KEY` when set) and installs every bundled skill; `uninstall` is the reciprocal removal. Per-CLI targets: pi `~/.pi/agent/mcp.json` + `~/.pi/agent/skills`, openclaw `~/.openclaw/openclaw.json` + `~/.openclaw/workspace/skills`, codex `~/.codex/config.toml` (`mcp_servers` table) + `~/.codex/skills`, antigravity `~/.gemini/settings.json` + `~/.gemini/config/skills`, claude `~/.claude.json` + `~/.claude/skills`. Existing unrelated configuration entries are always preserved.
182
+ - `api-key <key>` validates the key (20-50 characters of letters, digits, hyphens, underscores), saves it as `apiKey` in the persisted settings at `~/.config/mcp-google-map/config.json` (masked in the JSON output), and immediately re-runs `install` for every enabled CLI; invalid keys fail with a JSON error and persist nothing.
183
+ - `install` registers for every enabled CLI the stdio server entry `mcp-google-map` (`npx -y mcp-google-map start --stdio`) and installs every bundled skill; the embedded `GOOGLE_MAPS_API_KEY` is resolved with priority `--apikey`, the persisted `api-key` settings, then the `GOOGLE_MAPS_API_KEY` environment — when none resolves, a literal placeholder that names the `api-key` command is embedded instead; `uninstall` is the reciprocal removal. Per-CLI targets: pi `~/.pi/agent/mcp.json` + `~/.pi/agent/skills`, openclaw `~/.openclaw/openclaw.json` + `~/.openclaw/workspace/skills`, codex `~/.codex/config.toml` (`mcp_servers` table) + `~/.codex/skills`, antigravity `~/.gemini/settings.json` + `~/.gemini/config/skills`, claude `~/.claude.json` + `~/.claude/skills`. Existing unrelated configuration entries are always preserved.
182
184
  - `show` prints two human-readable tables: CLI Configuration (CLI, Enabled, MCP Config Path, Skills Config Path for all five CLIs) and Installation Status (Type, Name, CLI, Enabled, Installed with OK/MISSING/STALE per enabled CLI).
183
- - HTTP mode starts even without an API key and logs a warning; stdio mode and the CLI commands require a key (`--apikey` or `GOOGLE_MAPS_API_KEY`). When no HTTP instance can start (invalid or taken port), the process exits non-zero.
185
+ - HTTP mode starts even without an API key and logs a warning (per-request header keys remain supported); stdio mode resolves the effective key with priority `--apikey`, `GOOGLE_MAPS_API_KEY`, then the persisted `api-key` settings, and exits 1 with a JSON error on stderr inviting `mcp-google-map api-key <key>` when no key resolves; the CLI commands require a key (`--apikey` or `GOOGLE_MAPS_API_KEY`). When no HTTP instance can start (invalid or taken port), the process exits non-zero.
184
186
 
185
187
  ## Registering in an MCP client
186
188
 
package/dist/cli.d.ts CHANGED
@@ -138,6 +138,11 @@ declare function runEnableDisableCliCommand(name: string, enable: boolean, optio
138
138
  home?: string;
139
139
  streams?: ExecStreams;
140
140
  }): number;
141
+ declare function runApiKeyCommand(key: string | undefined, options: {
142
+ home?: string;
143
+ resourcesRoot: string;
144
+ streams?: ExecStreams;
145
+ }): number;
141
146
  declare function runInstallUninstallCommand(operation: "install" | "uninstall", options: {
142
147
  home?: string;
143
148
  apiKey?: string;
@@ -150,4 +155,4 @@ declare function runShowCommand(options: {
150
155
  streams?: ExecStreams;
151
156
  }): number;
152
157
 
153
- export { DOCTOR_PROBES, type DoctorCheck, type DoctorLiveProbe, type DoctorOptions, type DoctorProbeId, type DoctorProbesParseResult, type DoctorReport, EXEC_TOOLS, type ServerStartupOutcome, type SetupCheck, type SetupDeps, type SetupFs, type SetupOptions, type SetupReport, type ShutdownExitHook, createShutdownHandler, execTool, extractEnvFileOption, installShutdownHandlers, parseDoctorProbes, runDoctor, runEnableDisableCliCommand, runExecCommand, runInstallUninstallCommand, runSetup, runShowCommand, runSnippetCommand, startServer };
158
+ export { DOCTOR_PROBES, type DoctorCheck, type DoctorLiveProbe, type DoctorOptions, type DoctorProbeId, type DoctorProbesParseResult, type DoctorReport, EXEC_TOOLS, type ServerStartupOutcome, type SetupCheck, type SetupDeps, type SetupFs, type SetupOptions, type SetupReport, type ShutdownExitHook, createShutdownHandler, execTool, extractEnvFileOption, installShutdownHandlers, parseDoctorProbes, runApiKeyCommand, runDoctor, runEnableDisableCliCommand, runExecCommand, runInstallUninstallCommand, runSetup, runShowCommand, runSnippetCommand, startServer };
package/dist/cli.js CHANGED
@@ -1459,6 +1459,7 @@ import { join, resolve } from "path";
1459
1459
  var SETTINGS_PROGRAM_NAME = "mcp-google-map";
1460
1460
  var CLI_SETTINGS_RELATIVE = [".config", SETTINGS_PROGRAM_NAME, "config.json"];
1461
1461
  var MCP_SERVER_NAME = "mcp-google-map";
1462
+ var INSTALL_API_KEY_PLACEHOLDER = "__RUN_mcp-google-map_api-key_TO_CONFIGURE_YOUR_API_KEY__";
1462
1463
  function resolveCliSettingsPath(home) {
1463
1464
  const root = home ?? (process.env.HOME ?? process.cwd());
1464
1465
  return resolve(root, ...CLI_SETTINGS_RELATIVE);
@@ -1473,23 +1474,39 @@ function uniqueStrings(value) {
1473
1474
  }
1474
1475
  return result;
1475
1476
  }
1477
+ function isUnsetApiKey(value) {
1478
+ return value === void 0 || value === null || value.trim().length === 0 || value === INSTALL_API_KEY_PLACEHOLDER;
1479
+ }
1476
1480
  function loadCliSettings(home) {
1477
1481
  try {
1478
1482
  const raw = JSON.parse(readFileSync(resolveCliSettingsPath(home), "utf-8"));
1479
1483
  if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
1480
1484
  return { enabled: [] };
1481
1485
  }
1482
- return { enabled: uniqueStrings(raw.enabled) };
1486
+ const record = raw;
1487
+ const settings = { enabled: uniqueStrings(record.enabled) };
1488
+ if (typeof record.apiKey === "string" && record.apiKey.length > 0) {
1489
+ settings.apiKey = record.apiKey;
1490
+ }
1491
+ return settings;
1483
1492
  } catch {
1484
1493
  return { enabled: [] };
1485
1494
  }
1486
1495
  }
1496
+ function loadConfiguredApiKey(home) {
1497
+ const apiKey = loadCliSettings(home).apiKey;
1498
+ return isUnsetApiKey(apiKey) ? void 0 : apiKey;
1499
+ }
1487
1500
  function saveCliSettings(settings, home) {
1488
1501
  const path = resolveCliSettingsPath(home);
1489
1502
  const temporary = `${path}.tmp`;
1503
+ const payload = { enabled: uniqueStrings(settings.enabled) };
1504
+ if (typeof settings.apiKey === "string" && settings.apiKey.length > 0) {
1505
+ payload.apiKey = settings.apiKey;
1506
+ }
1490
1507
  try {
1491
1508
  mkdirSync(join(path, ".."), { recursive: true });
1492
- writeFileSync(temporary, JSON.stringify({ enabled: uniqueStrings(settings.enabled) }, null, 2) + "\n", "utf-8");
1509
+ writeFileSync(temporary, JSON.stringify(payload, null, 2) + "\n", "utf-8");
1493
1510
  renameSync(temporary, path);
1494
1511
  } catch (error) {
1495
1512
  throw new Error(`settings write failed: ${error instanceof Error ? error.message : String(error)}`);
@@ -2169,12 +2186,21 @@ function applyServerRegistration(target, serverName, entry, home) {
2169
2186
  import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
2170
2187
  import { join as join4, resolve as resolve3 } from "path";
2171
2188
  function buildServerRegistration(apiKey) {
2172
- const env = {};
2173
- if (apiKey !== void 0 && apiKey.length > 0) {
2174
- env.GOOGLE_MAPS_API_KEY = apiKey;
2175
- }
2189
+ const env = {
2190
+ GOOGLE_MAPS_API_KEY: isUnsetApiKey(apiKey) ? INSTALL_API_KEY_PLACEHOLDER : apiKey
2191
+ };
2176
2192
  return { command: "npx", args: ["-y", MCP_SERVER_NAME, "start", "--stdio"], env };
2177
2193
  }
2194
+ function resolveInstallApiKey(options) {
2195
+ if (!isUnsetApiKey(options.flagKey)) {
2196
+ return options.flagKey;
2197
+ }
2198
+ const persisted = loadConfiguredApiKey(options.home);
2199
+ if (persisted !== void 0) {
2200
+ return persisted;
2201
+ }
2202
+ return isUnsetApiKey(options.envKey) ? void 0 : options.envKey;
2203
+ }
2178
2204
  function resolveSkillsResourcesRoot(packageRoot) {
2179
2205
  const candidate = resolve3(packageRoot, "src", "resources", "skills");
2180
2206
  if (!existsSync3(candidate)) {
@@ -2874,6 +2900,68 @@ function runEnableDisableCliCommand(name, enable, options = {}) {
2874
2900
  );
2875
2901
  return 0;
2876
2902
  }
2903
+ function runApiKeyCommand(key, options) {
2904
+ const streams = options.streams ?? { stdout: process.stdout, stderr: process.stderr };
2905
+ const trimmed = (key ?? "").trim();
2906
+ if (!ApiKeyManager.getInstance().isValidApiKeyFormat(trimmed)) {
2907
+ streams.stderr.write(
2908
+ JSON.stringify(
2909
+ {
2910
+ success: false,
2911
+ error: "Invalid Google Maps API key. Expected 20-50 characters of letters, digits, hyphens, or underscores. Usage: mcp-google-map api-key <your-api-key>"
2912
+ },
2913
+ null,
2914
+ 2
2915
+ ) + "\n"
2916
+ );
2917
+ return 1;
2918
+ }
2919
+ let settingsPath;
2920
+ try {
2921
+ const settings = loadCliSettings(options.home);
2922
+ settings.apiKey = trimmed;
2923
+ settingsPath = saveCliSettings(settings, options.home);
2924
+ } catch (error) {
2925
+ streams.stderr.write(
2926
+ JSON.stringify({ success: false, error: error instanceof Error ? error.message : String(error) }, null, 2) + "\n"
2927
+ );
2928
+ return 1;
2929
+ }
2930
+ let install;
2931
+ try {
2932
+ install = installEnabledCliResources({ home: options.home, apiKey: trimmed, resourcesRoot: options.resourcesRoot });
2933
+ } catch (error) {
2934
+ streams.stderr.write(
2935
+ JSON.stringify(
2936
+ {
2937
+ success: false,
2938
+ apiKey: maskSecret(trimmed),
2939
+ settingsPath,
2940
+ error: error instanceof Error ? error.message : String(error)
2941
+ },
2942
+ null,
2943
+ 2
2944
+ ) + "\n"
2945
+ );
2946
+ return 1;
2947
+ }
2948
+ const zeroEnabled = install.summaries.length === 0 && install.errors.length === 0;
2949
+ streams.stdout.write(
2950
+ JSON.stringify(
2951
+ {
2952
+ success: install.errors.length === 0,
2953
+ command: "api-key",
2954
+ apiKey: maskSecret(trimmed),
2955
+ settingsPath,
2956
+ ...zeroEnabled ? { message: "API key saved. No CLI enabled. Use 'mcp-google-map enable <cli name>' first." } : {},
2957
+ install: { operation: "install", summaries: install.summaries, errors: install.errors }
2958
+ },
2959
+ null,
2960
+ 2
2961
+ ) + "\n"
2962
+ );
2963
+ return install.errors.length > 0 ? 1 : 0;
2964
+ }
2877
2965
  function runInstallUninstallCommand(operation, options) {
2878
2966
  const streams = options.streams ?? { stdout: process.stdout, stderr: process.stderr };
2879
2967
  if (loadCliSettings(options.home).enabled.length === 0) {
@@ -2968,21 +3056,42 @@ if (isRunDirectly || isMainModule) {
2968
3056
  if (argv.apikey) {
2969
3057
  process.env.GOOGLE_MAPS_API_KEY = argv.apikey;
2970
3058
  }
3059
+ let effectiveApiKey = isUnsetApiKey(process.env.GOOGLE_MAPS_API_KEY) ? void 0 : process.env.GOOGLE_MAPS_API_KEY;
3060
+ if (effectiveApiKey === void 0) {
3061
+ const persistedApiKey = loadConfiguredApiKey();
3062
+ if (persistedApiKey !== void 0) {
3063
+ process.env.GOOGLE_MAPS_API_KEY = persistedApiKey;
3064
+ effectiveApiKey = persistedApiKey;
3065
+ }
3066
+ }
2971
3067
  void checkVersionIdle({ currentVersion: packageVersion }).catch(() => void 0);
2972
3068
  const tools = filterTools(config_default[0].tools);
2973
3069
  if (argv.stdio) {
3070
+ if (effectiveApiKey === void 0) {
3071
+ process.stderr.write(
3072
+ JSON.stringify(
3073
+ {
3074
+ error: "Google Maps API key is not configured. Run 'mcp-google-map api-key <your-api-key>' to configure it, or pass --apikey / set GOOGLE_MAPS_API_KEY."
3075
+ },
3076
+ null,
3077
+ 2
3078
+ ) + "\n"
3079
+ );
3080
+ process.exitCode = 1;
3081
+ return;
3082
+ }
2974
3083
  const server = new BaseMcpServer(config_default[0].name, tools);
2975
3084
  await server.startStdio();
2976
3085
  } else {
2977
3086
  Logger.log("\u{1F5FA}\uFE0F Google Maps MCP Server");
2978
3087
  Logger.log(" A Model Context Protocol server for Google Maps services");
2979
3088
  Logger.log("");
2980
- if (!argv.apikey) {
3089
+ if (effectiveApiKey === void 0) {
2981
3090
  Logger.log("\u26A0\uFE0F Google Maps API Key not found!");
2982
- Logger.log(" Please provide --apikey parameter or set GOOGLE_MAPS_API_KEY in your .env file");
3091
+ Logger.log(" Run 'mcp-google-map api-key <your-api-key>' to configure it, or set GOOGLE_MAPS_API_KEY / pass --apikey");
2983
3092
  Logger.log("");
2984
3093
  }
2985
- startServer(argv.port, argv.apikey, argv.host).then((outcome) => {
3094
+ startServer(argv.port, effectiveApiKey, argv.host).then((outcome) => {
2986
3095
  if (outcome.started === 0) {
2987
3096
  process.exit(1);
2988
3097
  }
@@ -3138,6 +3247,22 @@ Usage: mcp-google-map <command> [options]
3138
3247
  home: argv.home
3139
3248
  });
3140
3249
  }
3250
+ ).command(
3251
+ "api-key <key>",
3252
+ "Save the Google Maps API key in the user settings and refresh every enabled CLI registration",
3253
+ (yargs2) => yargs2.positional("key", {
3254
+ type: "string",
3255
+ describe: "Google Maps API key (20-50 characters: letters, digits, hyphens, underscores)"
3256
+ }).option("home", {
3257
+ type: "string",
3258
+ description: "Home-directory override for CLI configuration paths (default: user home)"
3259
+ }).example([["$0 api-key AIzaSy...", "Save the key and reinstall every enabled CLI"]]),
3260
+ (argv) => {
3261
+ process.exitCode = runApiKeyCommand(argv.key, {
3262
+ home: argv.home,
3263
+ resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, ".."))
3264
+ });
3265
+ }
3141
3266
  ).command(
3142
3267
  "install",
3143
3268
  "Register the mcp-google-map stdio server and install packaged skills for every enabled CLI",
@@ -3147,13 +3272,17 @@ Usage: mcp-google-map <command> [options]
3147
3272
  }).option("apikey", {
3148
3273
  alias: "k",
3149
3274
  type: "string",
3150
- description: "Google Maps API key embedded in the registered entry (prefer GOOGLE_MAPS_API_KEY)",
3151
- default: resolveRuntimeConfig(process.env, { envFile: extractEnvFileOption(process.argv) }).apiKey
3275
+ description: "Google Maps API key embedded in the registered entry (priority: this flag, persisted api-key settings, GOOGLE_MAPS_API_KEY)"
3152
3276
  }).example([["$0 install", "Register the server and skills in every enabled CLI"]]),
3153
3277
  (argv) => {
3278
+ const config = resolveRuntimeConfig(process.env, { envFile: extractEnvFileOption(process.argv) });
3154
3279
  process.exitCode = runInstallUninstallCommand("install", {
3155
3280
  home: argv.home,
3156
- apiKey: argv.apikey,
3281
+ apiKey: resolveInstallApiKey({
3282
+ flagKey: argv.apikey,
3283
+ envKey: config.apiKey,
3284
+ home: argv.home
3285
+ }),
3157
3286
  resourcesRoot: resolveSkillsResourcesRoot(resolve5(__dirname, ".."))
3158
3287
  });
3159
3288
  }
@@ -3365,6 +3494,7 @@ export {
3365
3494
  extractEnvFileOption,
3366
3495
  installShutdownHandlers,
3367
3496
  parseDoctorProbes,
3497
+ runApiKeyCommand,
3368
3498
  runDoctor,
3369
3499
  runEnableDisableCliCommand,
3370
3500
  runExecCommand,