@yawlabs/aws-mcp 1.5.0 → 1.5.3

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/index.js CHANGED
@@ -7,7 +7,11 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
9
  var __commonJS = (cb, mod) => function __require() {
10
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ try {
11
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
12
+ } catch (e) {
13
+ throw mod = 0, e;
14
+ }
11
15
  };
12
16
  var __export = (target, all) => {
13
17
  for (var name in all)
@@ -30055,6 +30059,7 @@ var require_turndown_cjs = __commonJS({
30055
30059
  });
30056
30060
 
30057
30061
  // src/index.ts
30062
+ import { createRequire } from "node:module";
30058
30063
  import { pathToFileURL } from "node:url";
30059
30064
 
30060
30065
  // node_modules/zod/v3/helpers/util.js
@@ -53846,7 +53851,7 @@ function mergeProfileBody(existingBody, creds) {
53846
53851
  updated.push(line);
53847
53852
  continue;
53848
53853
  }
53849
- const key = line.slice(0, eqIdx).trim();
53854
+ const key = line.slice(0, eqIdx).trim().toLowerCase();
53850
53855
  if (managedKeys.has(key)) {
53851
53856
  seen.add(key);
53852
53857
  updated.push(`${key} = ${creds[key]}`);
@@ -54061,7 +54066,7 @@ var assumeTools = [
54061
54066
  error: `SSO session expired for source profile '${sourceProfile}'. Call aws_login_start with profile='${sourceProfile}' before assuming.`
54062
54067
  };
54063
54068
  }
54064
- return { ok: false, error: result.error, rawBody: result.rawStderr ?? result.rawStdout };
54069
+ return { ok: false, error: result.error, rawBody: result.rawStderr };
54065
54070
  }
54066
54071
  const data = result.data ?? {};
54067
54072
  const creds = data.Credentials;
@@ -54069,11 +54074,22 @@ var assumeTools = [
54069
54074
  return { ok: false, error: "STS AssumeRole succeeded but returned incomplete credentials." };
54070
54075
  }
54071
54076
  const credentialsPath = join(homedir(), ".aws", "credentials");
54072
- await upsertProfile(credentialsPath, targetProfile, {
54073
- aws_access_key_id: creds.AccessKeyId,
54074
- aws_secret_access_key: creds.SecretAccessKey,
54075
- aws_session_token: creds.SessionToken
54076
- });
54077
+ try {
54078
+ await upsertProfile(credentialsPath, targetProfile, {
54079
+ aws_access_key_id: creds.AccessKeyId,
54080
+ aws_secret_access_key: creds.SecretAccessKey,
54081
+ aws_session_token: creds.SessionToken
54082
+ });
54083
+ } catch (err) {
54084
+ const code = err.code;
54085
+ if (code === "EACCES" || code === "EROFS" || code === "EPERM") {
54086
+ return {
54087
+ ok: false,
54088
+ error: `Cannot write ${credentialsPath} (permission denied). Check directory permissions or set AWS_SHARED_CREDENTIALS_FILE to a writable path.`
54089
+ };
54090
+ }
54091
+ throw err;
54092
+ }
54077
54093
  const expiration = creds.Expiration;
54078
54094
  return {
54079
54095
  ok: true,
@@ -54841,6 +54857,7 @@ function parseSearchResults(json2, limit) {
54841
54857
  const t = tes;
54842
54858
  const url2 = typeof t.link === "string" ? t.link : void 0;
54843
54859
  if (!url2) continue;
54860
+ if (!isValidDocsUrl(url2)) continue;
54844
54861
  const title = typeof t.title === "string" ? t.title : url2;
54845
54862
  const result = { title, url: url2 };
54846
54863
  if (typeof t.summary === "string" && t.summary.length > 0) result.summary = t.summary;
@@ -55156,9 +55173,25 @@ function parseSimulationResults(raw) {
55156
55173
  const matched = Array.isArray(er.MatchedStatements) ? er.MatchedStatements : [];
55157
55174
  const ids = [];
55158
55175
  for (const m of matched) {
55159
- if (m && typeof m === "object" && typeof m.SourcePolicyId === "string") {
55160
- ids.push(m.SourcePolicyId);
55176
+ if (!m || typeof m !== "object") continue;
55177
+ const ms = m;
55178
+ const sourceId = ms.SourcePolicyId;
55179
+ if (typeof sourceId === "string" && sourceId.length > 0) {
55180
+ ids.push(sourceId);
55181
+ continue;
55182
+ }
55183
+ if (sourceId !== void 0 && sourceId !== "") continue;
55184
+ const sourceType = ms.SourcePolicyType;
55185
+ if (typeof sourceType !== "string") continue;
55186
+ const startPos = ms.StartPosition;
55187
+ if (startPos && typeof startPos === "object") {
55188
+ const line = startPos.Line;
55189
+ if (typeof line === "number") {
55190
+ ids.push(`inline#L${line}`);
55191
+ continue;
55192
+ }
55161
55193
  }
55194
+ ids.push("inline");
55162
55195
  }
55163
55196
  if (ids.length > 0) result.matchedStatementIds = ids;
55164
55197
  const missing = Array.isArray(er.MissingContextValues) ? er.MissingContextValues : [];
@@ -55369,6 +55402,12 @@ var logsTools = [
55369
55402
  error: `Invalid logStreamNamePrefix '${i.logStreamNamePrefix}'. Must be 1-512 chars, not start with '-', and contain no ':', '*', or control characters.`
55370
55403
  };
55371
55404
  }
55405
+ if (i.filterPattern?.startsWith("-")) {
55406
+ return {
55407
+ ok: false,
55408
+ error: "Invalid filterPattern: must not start with '-'."
55409
+ };
55410
+ }
55372
55411
  const extraFlags = [i.logGroupName, "--format", "json", "--since", i.since ?? "10m"];
55373
55412
  if (i.filterPattern) extraFlags.push("--filter-pattern", i.filterPattern);
55374
55413
  if (i.logStreamNames && i.logStreamNames.length > 0) {
@@ -55989,6 +56028,11 @@ function _applyJsonPatchInPlace(doc, ops) {
55989
56028
  throw new Error(`op '${op.op}' at index ${i} is not implemented in aws_resource_diff (use add/remove/replace).`);
55990
56029
  }
55991
56030
  const tokens = parseJsonPointer(op.path);
56031
+ for (const seg of tokens) {
56032
+ if (seg === "__proto__" || seg === "constructor" || seg === "prototype") {
56033
+ throw new Error(`Path '${op.path}' contains reserved segment '${seg}' at op index ${i}.`);
56034
+ }
56035
+ }
55992
56036
  if (tokens.length === 0) {
55993
56037
  if (op.op === "remove") {
55994
56038
  throw new Error(`Cannot remove the document root at index ${i}.`);
@@ -56013,7 +56057,7 @@ function _applyJsonPatchInPlace(doc, ops) {
56013
56057
  }
56014
56058
  parent = parent[idx];
56015
56059
  } else if (isObj(parent)) {
56016
- if (!(segment in parent)) {
56060
+ if (!Object.hasOwn(parent, segment)) {
56017
56061
  if (op.op === "add") {
56018
56062
  parent[segment] = {};
56019
56063
  parent = parent[segment];
@@ -56056,12 +56100,12 @@ function _applyJsonPatchInPlace(doc, ops) {
56056
56100
  }
56057
56101
  } else if (isObj(parent)) {
56058
56102
  if (op.op === "remove") {
56059
- if (!(lastToken in parent)) {
56103
+ if (!Object.hasOwn(parent, lastToken)) {
56060
56104
  throw new Error(`Cannot remove missing key '${lastToken}' at index ${i}.`);
56061
56105
  }
56062
56106
  delete parent[lastToken];
56063
56107
  } else if (op.op === "replace") {
56064
- if (!(lastToken in parent)) {
56108
+ if (!Object.hasOwn(parent, lastToken)) {
56065
56109
  throw new Error(`Cannot replace missing key '${lastToken}' at index ${i} (use 'add' to create it).`);
56066
56110
  }
56067
56111
  parent[lastToken] = clone2(op.value);
@@ -56275,12 +56319,12 @@ function buildMetricDataQueries(inputs, autoPeriod) {
56275
56319
  if (q.period !== void 0) base.Period = q.period;
56276
56320
  return base;
56277
56321
  }
56278
- const dimensions = q.dimensions ? Object.entries(q.dimensions).map(([Name, Value]) => ({ Name, Value })) : void 0;
56322
+ const dimEntries = q.dimensions ? Object.entries(q.dimensions) : [];
56279
56323
  const stat = {
56280
56324
  Metric: {
56281
56325
  Namespace: q.namespace,
56282
56326
  MetricName: q.metricName,
56283
- ...dimensions ? { Dimensions: dimensions } : {}
56327
+ ...dimEntries.length > 0 ? { Dimensions: dimEntries.map(([Name, Value]) => ({ Name, Value })) } : {}
56284
56328
  },
56285
56329
  Period: q.period ?? autoPeriod,
56286
56330
  Stat: q.statistic !== void 0 ? canonicalizeStatistic(q.statistic) : "Average"
@@ -56313,14 +56357,14 @@ var metricsTools = [
56313
56357
  ),
56314
56358
  period: external_exports3.number().int().positive().optional().describe("Period in seconds. Defaults to an auto-pick from the time range (60s/300s/900s/3600s)."),
56315
56359
  expression: external_exports3.string().min(1).optional().describe(
56316
- `CloudWatch metric math expression, e.g. 'SUM([m1, m2])' or 'AVG(METRICS("AWS/Lambda"))'. Mutually exclusive with namespace/metricName/dimensions.`
56360
+ `CloudWatch metric math expression, e.g. 'SUM([m1, m2])' or 'AVG(METRICS("AWS/Lambda"))'. Mutually exclusive with namespace/metricName/dimensions. Validated server-side by CloudWatch; malformed values surface as a downstream ValidationError rather than a local rejection.`
56317
56361
  ),
56318
56362
  label: external_exports3.string().optional().describe("Human-readable label for the series in the response."),
56319
56363
  returnData: external_exports3.boolean().optional().describe(
56320
56364
  "Set false to compute this query but not return its data (useful for intermediate values in expressions). Default true."
56321
56365
  ),
56322
56366
  unit: external_exports3.string().optional().describe(
56323
- "Restrict to a specific Unit (e.g. 'Seconds', 'Bytes'). Default: no filter. Only meaningful on metric-stat queries."
56367
+ "Restrict to a specific Unit (e.g. 'Seconds', 'Bytes'). Default: no filter. Only meaningful on metric-stat queries. Validated server-side by CloudWatch; malformed values surface as a downstream ValidationError rather than a local rejection."
56324
56368
  )
56325
56369
  })
56326
56370
  ).min(1).max(MAX_QUERIES).describe(`1-${MAX_QUERIES} queries. Each is either a metric-stat (namespace + metricName) or an expression.`),
@@ -56535,34 +56579,43 @@ var multiRegionTools = [
56535
56579
  }
56536
56580
  const concurrency = i.concurrency ?? DEFAULT_CONCURRENCY;
56537
56581
  const results = await runWithConcurrency(regions, concurrency, async (region) => {
56538
- if (!isValidRegionName(region)) {
56539
- return {
56582
+ try {
56583
+ if (!isValidRegionName(region)) {
56584
+ return {
56585
+ region,
56586
+ ok: false,
56587
+ error: `Invalid region '${region}'. Must match ${REGION_NAME_RE} (e.g. 'us-east-1').`,
56588
+ errorKind: "bad_input"
56589
+ };
56590
+ }
56591
+ const r = await runAwsCall({
56592
+ service: i.service,
56593
+ operation: i.operation,
56594
+ params: i.params,
56595
+ query: i.query,
56596
+ profile: i.profile,
56540
56597
  region,
56541
- ok: false,
56542
- error: `Invalid region '${region}'. Must match ${REGION_NAME_RE} (e.g. 'us-east-1').`,
56543
- errorKind: "bad_input"
56544
- };
56545
- }
56546
- const r = await runAwsCall({
56547
- service: i.service,
56548
- operation: i.operation,
56549
- params: i.params,
56550
- query: i.query,
56551
- profile: i.profile,
56552
- region,
56553
- outputFormat: i.outputFormat,
56554
- timeoutMs: i.timeoutMs
56555
- });
56556
- if (!r.ok) {
56598
+ outputFormat: i.outputFormat,
56599
+ timeoutMs: i.timeoutMs
56600
+ });
56601
+ if (!r.ok) {
56602
+ return {
56603
+ region,
56604
+ ok: false,
56605
+ command: r.command,
56606
+ error: r.error,
56607
+ errorKind: r.kind
56608
+ };
56609
+ }
56610
+ return { region, ok: true, command: r.command, data: r.data };
56611
+ } catch (err) {
56557
56612
  return {
56558
56613
  region,
56559
56614
  ok: false,
56560
- command: r.command,
56561
- error: r.error,
56562
- errorKind: r.kind
56615
+ error: err instanceof Error ? err.message : String(err),
56616
+ errorKind: "unexpected"
56563
56617
  };
56564
56618
  }
56565
- return { region, ok: true, command: r.command, data: r.data };
56566
56619
  });
56567
56620
  const okCount = results.filter((r) => r.ok).length;
56568
56621
  const errCount = results.length - okCount;
@@ -56976,8 +57029,18 @@ function errorToMcpResult(err, toolName) {
56976
57029
  isError: true
56977
57030
  };
56978
57031
  }
56979
- var version2 = true ? "1.5.0" : (await null).createRequire(import.meta.url)("../package.json").version;
56980
- var isEntryPoint = (() => {
57032
+ var version2 = true ? "1.5.3" : (await null).createRequire(import.meta.url)("../package.json").version;
57033
+ var isSeaBinary = (() => {
57034
+ try {
57035
+ const base = import.meta.url || pathToFileURL(process.execPath).href;
57036
+ const require2 = createRequire(base);
57037
+ const sea = require2("node:sea");
57038
+ return typeof sea.isSea === "function" && sea.isSea() === true;
57039
+ } catch {
57040
+ return false;
57041
+ }
57042
+ })();
57043
+ var isEntryPoint = isSeaBinary || (() => {
56981
57044
  const entry = process.argv[1];
56982
57045
  if (!entry) return false;
56983
57046
  return import.meta.url === pathToFileURL(entry).href;
@@ -57017,8 +57080,13 @@ if (isEntryPoint) {
57017
57080
  });
57018
57081
  }
57019
57082
  const transport = new StdioServerTransport();
57020
- await server.connect(transport);
57021
- console.error(`@yawlabs/aws-mcp v${version2} ready (${allTools.length} tools)`);
57083
+ server.connect(transport).then(() => {
57084
+ console.error(`@yawlabs/aws-mcp v${version2} ready (${allTools.length} tools)`);
57085
+ }).catch((err) => {
57086
+ process.stderr.write(`aws-mcp: ${err instanceof Error ? err.message : String(err)}
57087
+ `);
57088
+ process.exit(1);
57089
+ });
57022
57090
  }
57023
57091
  export {
57024
57092
  allTools,