@chrischall/mcp-utils 0.23.0 → 0.23.2

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
@@ -145,7 +145,9 @@ from one, and a value that silently aliases to another is a lie in the schema.
145
145
  `stripMediaUrls(payload)` is the highest-value projection that needs no
146
146
  knowledge of the API: it drops `avatar` / `picture` / `cover_photo` /
147
147
  `thumbnail` keys — including the `…Link` / `…Uri` / `…Url` suffixed forms every
148
- Google Workspace API uses (`thumbnailLink`, `iconUri`, `photoUrl`) and bare
148
+ Google Workspace API uses (`thumbnailLink`, `iconUri`, `photoUrl`), and the
149
+ snake_case and kebab-case forms most other APIs use (`image_url`,
150
+ `primary_photo_url`, `avatar_image_url`) — and bare
149
151
  image URLs. The suffix is load-bearing outside consumer-social APIs: without it
150
152
  the rule matched none of Google's media fields, and `thumbnailLink` alone is 32%
151
153
  of a `gog drive ls` listing. Its key rule stays anchored at the START, so a key
@@ -161,9 +163,15 @@ mutates its input. Do **not** apply it to a tool whose product IS the image —
161
163
  records are literally a `photoUrls` bundle) — where it empties the response
162
164
  rather than shrinking it.
163
165
 
166
+ **Arrays of bare image URLs under a non-media key are kept** — `floorplan_urls:
167
+ ['a.jpg', 'b.jpg']` comes back whole. That is deliberate: removing a *key* is
168
+ visible, removing *elements* is not, and a caller reading `.length` to report
169
+ "4 floor plans" would be quietly wrong. Use `drop` for those. An array under a
170
+ media-named key (`photos: [...]`) is already removed by the key rule.
171
+
164
172
  Two escape hatches, and they are symmetric: `keep` preserves a key that looks
165
173
  like media but is the thing the caller asked for; `drop` adds keys this pattern
166
- does not know, so a service with an unguessed naming convention can fix itself
174
+ does not know. Both take `string | RegExp`, so a service with an unguessed naming convention can fix itself
167
175
  **without a library release** — which is what Google Workspace's
168
176
  `thumbnailLink`/`iconUri`/`photoUrl` cost the first time round. `keep` wins over
169
177
  `drop`.
@@ -25,6 +25,10 @@
25
25
  * answered. Three points is not worth a payload that can no longer distinguish
26
26
  * "no value" from "not reported".
27
27
  *
28
+ * **Arrays of bare image URLs under a non-media key are KEPT** — see the note
29
+ * in `walk`. Use `drop` for those; the key rule already covers an array under
30
+ * a media-named key (`photos: [...]`).
31
+ *
28
32
  * **Never apply this to a tool whose PRODUCT is the image.**
29
33
  * `alltrails_get_trail_photos`, `zillow_get_property_photos`,
30
34
  * `sw_get_receipt`, `musescore_fetch_svgs` exist to return exactly these URLs,
@@ -36,8 +40,20 @@ export interface StripMediaOptions {
36
40
  /**
37
41
  * Keys to keep even when they look like media — for a payload that mixes a
38
42
  * decorative avatar with an image the caller actually asked for.
43
+ *
44
+ * Takes the same `string | RegExp` shapes as `drop`. It did not until this
45
+ * was noticed: `drop` gained RegExp support in #194 and `keep` was left on
46
+ * strings, so a repo preserving several CONSTRUCTED media fields that share a
47
+ * prefix — redfin-mcp's `image_url` + `thumbnail_url`, compass-mcp's
48
+ * `primary_photo_url` + `primary_thumbnail_url` — had to enumerate each one
49
+ * while the opposite intent could be a pattern.
50
+ *
51
+ * That was an oversight in the API rather than a judgement, and if either
52
+ * side deserved the expressiveness first it was this one: a missed `drop`
53
+ * entry leaves bytes in the response, while a missed `keep` entry silently
54
+ * deletes a field the caller asked for.
39
55
  */
40
- keep?: readonly string[];
56
+ keep?: readonly (string | RegExp)[];
41
57
  /**
42
58
  * Extra keys to drop, for a service whose naming this pattern does not know.
43
59
  *
@@ -1 +1 @@
1
- {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/response/media.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAuDH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB;;;;;;;;;;;;;;OAcG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;CACrC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,GAAE,iBAAsB,GAAG,CAAC,CAmB3E"}
1
+ {"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../src/response/media.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAiFH,MAAM,WAAW,iBAAiB;IAChC;;;;;;;;;;;;;;;OAeG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IACpC;;;;;;;;;;;;;;OAcG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;CACrC;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,GAAE,iBAAsB,GAAG,CAAC,CAoB3E"}
@@ -25,6 +25,10 @@
25
25
  * answered. Three points is not worth a payload that can no longer distinguish
26
26
  * "no value" from "not reported".
27
27
  *
28
+ * **Arrays of bare image URLs under a non-media key are KEPT** — see the note
29
+ * in `walk`. Use `drop` for those; the key rule already covers an array under
30
+ * a media-named key (`photos: [...]`).
31
+ *
28
32
  * **Never apply this to a tool whose PRODUCT is the image.**
29
33
  * `alltrails_get_trail_photos`, `zillow_get_property_photos`,
30
34
  * `sw_get_receipt`, `musescore_fetch_svgs` exist to return exactly these URLs,
@@ -62,8 +66,29 @@
62
66
  * node_modules. An earlier draft said 33 across the two and named `avatarUrls`
63
67
  * as a third form; neither reproduced.)
64
68
  */
65
- const MEDIA_NOUN = '(?:avatar|tall_avatar|cover_photo|cover_image|picture|photo|thumbnail|thumb|image|icon|banner|profile_pic(?:ture)?|logo)';
66
- const MEDIA_KEY = new RegExp(`^${MEDIA_NOUN}s?(?:(?:link|uri|url)s?)?$`, 'i');
69
+ const MEDIA_NOUN = '(?:avatar|picture|photo|thumbnail|thumb|image|icon|banner|profile_pic(?:ture)?|logo)';
70
+ /**
71
+ * A bounded set of qualifiers that may precede the noun in a snake_case or
72
+ * kebab-case key: `primary_photo_url`, `profile_image_url`, `hero-banner`.
73
+ *
74
+ * CLOSED on purpose, never `\w+`. That is the whole difference between this
75
+ * and the two clauses removed in #191 — a bare `\bavatar\b` and an
76
+ * `/avatars?/` path segment — which were open-ended, stripped genuine page
77
+ * URLs, and (measured) removed zero bytes. A media noun is also allowed here,
78
+ * for `avatar_image_url`.
79
+ *
80
+ * `cover` and `tall` live here rather than as `cover_photo` / `cover_image` /
81
+ * `tall_avatar` entries in MEDIA_NOUN. Those three were redundant once this
82
+ * list existed — `cover` + `photo` already composes — and keeping both spellings
83
+ * meant the snake_case form matched while the camelCase one silently did not.
84
+ *
85
+ * The separator is OPTIONAL for the same reason. With `[_-]` required,
86
+ * `cover_photo` was stripped and `coverPhoto` was kept: the same field, the
87
+ * same meaning, a different answer decided by an API's casing convention. That
88
+ * asymmetry is the exact shape of the bug #197 was about, one level up.
89
+ */
90
+ const MEDIA_QUALIFIER = '(?:primary|secondary|main|default|cover|hero|profile|master|rendered|small|medium|large|full|original|tall)';
91
+ const MEDIA_KEY = new RegExp(`^(?:(?:${MEDIA_QUALIFIER}|${MEDIA_NOUN})[_-]?)?${MEDIA_NOUN}s?(?:[_-]?(?:link|uri|url|src)s?)?$`, 'i');
67
92
  /**
68
93
  * A URL that points at an image rather than at a page: a known image extension
69
94
  * ending the PATH.
@@ -92,7 +117,9 @@ const MEDIA_URL = /^https?:\/\/[^\s]+?\.(png|jpe?g|gif|webp|svg|avif|bmp|ico)([?
92
117
  * The input is never mutated: several repos hand these helpers live cache rows.
93
118
  */
94
119
  export function stripMediaUrls(value, opts = {}) {
95
- const keep = new Set((opts.keep ?? []).map((k) => k.toLowerCase()));
120
+ // `keep` is normalised exactly like `drop` below — same copy-the-regex
121
+ // reasoning, same once-per-call lowercasing.
122
+ const keep = normalizeRules(opts.keep ?? []);
96
123
  // Every RegExp rule is COPIED, once per call, for two reasons.
97
124
  //
98
125
  // `test()` on a `g`- or `y`-flagged regex advances `lastIndex` on a match, so
@@ -107,13 +134,17 @@ export function stripMediaUrls(value, opts = {}) {
107
134
  // caller's RegExp is input too. The docs invite hoisting `drop` as a shared
108
135
  // constant, which is exactly when someone else's `lastIndex` would be ours to
109
136
  // corrupt. Strings are lowercased here for the same once-per-call reason.
110
- const drop = (opts.drop ?? []).map((rule) => typeof rule === 'string' ? rule.toLowerCase() : new RegExp(rule.source, rule.flags));
137
+ const drop = normalizeRules(opts.drop ?? []);
111
138
  return walk(value, keep, drop);
112
139
  }
113
- /** Does `key` match one of the caller's extra drop rules? */
114
- function alsoDrop(key, drop) {
140
+ /** Lowercase the strings and copy the regexes, once per call. See above. */
141
+ function normalizeRules(rules) {
142
+ return rules.map((rule) => (typeof rule === 'string' ? rule.toLowerCase() : new RegExp(rule.source, rule.flags)));
143
+ }
144
+ /** Does `key` match one of the caller's rules? Used for both `keep` and `drop`. */
145
+ function matchesRule(key, rules) {
115
146
  const lower = key.toLowerCase();
116
- for (const rule of drop) {
147
+ for (const rule of rules) {
117
148
  if (typeof rule === 'string') {
118
149
  if (rule === lower)
119
150
  return true;
@@ -127,6 +158,20 @@ function alsoDrop(key, drop) {
127
158
  return false;
128
159
  }
129
160
  function walk(value, keep, drop) {
161
+ // Array ELEMENTS are walked but never value-tested, so an array of bare image
162
+ // URLs under a non-media key — homes-mcp's `floorplan_urls` — comes back
163
+ // whole. That is deliberate, and it is the one place this helper knowingly
164
+ // leaves bytes on the table.
165
+ //
166
+ // Removing a KEY is visible: the field is gone and a reader can see that it
167
+ // is. Removing ELEMENTS is invisible — the array is merely shorter, and a
168
+ // caller reading `floorplan_urls.length` to say "this listing has 4 floor
169
+ // plans" would be quietly wrong. That is the same class of harm as the
170
+ // dropped-nulls rule this helper also refuses (see the docblock above):
171
+ // a silently altered count reads as fact.
172
+ //
173
+ // The fix for such a field is `drop: ['floorplan_urls']` at the call site,
174
+ // which removes the key outright and stays legible in the response.
130
175
  if (Array.isArray(value))
131
176
  return value.map((v) => walk(v, keep, drop));
132
177
  // `null` is data here, not an empty object — see the docblock.
@@ -139,11 +184,11 @@ function walk(value, keep, drop) {
139
184
  return value;
140
185
  const out = {};
141
186
  for (const [key, v] of Object.entries(value)) {
142
- if (keep.has(key.toLowerCase())) {
187
+ if (matchesRule(key, keep)) {
143
188
  out[key] = v;
144
189
  continue;
145
190
  }
146
- if (MEDIA_KEY.test(key) || alsoDrop(key, drop))
191
+ if (MEDIA_KEY.test(key) || matchesRule(key, drop))
147
192
  continue;
148
193
  if (typeof v === 'string' && MEDIA_URL.test(v))
149
194
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/response/media.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../src/response/media.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrischall/mcp-utils",
3
- "version": "0.23.0",
3
+ "version": "0.23.2",
4
4
  "description": "Shared scaffolding for the chrischall MCP fleet — server bootstrap, tool-result formatting, helpful errors, hardened env/config, a bearer API-client kit, zod atoms, session registries, a fetchproxy transport adapter, auth resolver skeletons, an in-memory test harness, and opt-in HTML helpers. The generic MCP glue hoisted out of ~19 sibling servers.",
5
5
  "type": "module",
6
6
  "license": "MIT",