@chrischall/gemini-mcp 1.11.1 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bundle.js CHANGED
@@ -26542,9 +26542,28 @@ var require_utils = __commonJS({
26542
26542
  "use strict";
26543
26543
  var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
26544
26544
  var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
26545
+ var isPort = RegExp.prototype.test.bind(/^\d*$/u);
26545
26546
  var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
26546
26547
  var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
26547
- var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
26548
+ var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
26549
+ var isQueryFragmentCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/?]$/u);
26550
+ var isUserinfoCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:]$/u);
26551
+ var BYTE_HEX = new Array(256);
26552
+ {
26553
+ const HEX_DIGITS = "0123456789ABCDEF";
26554
+ for (let i = 0; i < 256; i++) {
26555
+ BYTE_HEX[i] = "%" + HEX_DIGITS[i >> 4] + HEX_DIGITS[i & 15];
26556
+ }
26557
+ }
26558
+ function percentEncodeNonAscii(cp) {
26559
+ if (cp < 2048) {
26560
+ return BYTE_HEX[192 | cp >> 6] + BYTE_HEX[128 | cp & 63];
26561
+ }
26562
+ if (cp < 65536) {
26563
+ return BYTE_HEX[224 | cp >> 12] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
26564
+ }
26565
+ return BYTE_HEX[240 | cp >> 18] + BYTE_HEX[128 | cp >> 12 & 63] + BYTE_HEX[128 | cp >> 6 & 63] + BYTE_HEX[128 | cp & 63];
26566
+ }
26548
26567
  function stringArrayToHexStripped(input) {
26549
26568
  let acc = "";
26550
26569
  let code = 0;
@@ -26569,91 +26588,105 @@ var require_utils = __commonJS({
26569
26588
  }
26570
26589
  return acc;
26571
26590
  }
26591
+ var isHextet = RegExp.prototype.test.bind(/^[\dA-Fa-f]{1,4}$/);
26592
+ var isIPvFuture = RegExp.prototype.test.bind(/^[vV][\dA-Fa-f]+\.[A-Za-z\d\-._~!$&'()*+,;=:]+$/);
26593
+ var isZoneCharacter = RegExp.prototype.test.bind(/^[A-Za-z\d\-._~]$/);
26572
26594
  var nonSimpleDomain = RegExp.prototype.test.bind(/[^!"$&'()*+,\-.;=_`a-z{}~]/u);
26573
- function consumeIsZone(buffer) {
26574
- buffer.length = 0;
26575
- return true;
26576
- }
26577
- function consumeHextets(buffer, address, output) {
26578
- if (buffer.length) {
26579
- const hex3 = stringArrayToHexStripped(buffer);
26580
- if (hex3 !== "") {
26581
- address.push(hex3);
26582
- } else {
26583
- output.error = true;
26584
- return false;
26595
+ function isZoneIdentifier(zone) {
26596
+ if (zone.length === 0) return false;
26597
+ for (let i = 0; i < zone.length; i++) {
26598
+ if (isZoneCharacter(zone[i])) continue;
26599
+ if (zone[i] === "%" && i + 2 < zone.length && isHexPair(zone.slice(i + 1, i + 3))) {
26600
+ i += 2;
26601
+ continue;
26585
26602
  }
26586
- buffer.length = 0;
26603
+ return false;
26587
26604
  }
26588
26605
  return true;
26589
26606
  }
26590
- function getIPV6(input) {
26591
- let tokenCount = 0;
26592
- const output = { error: false, address: "", zone: "" };
26593
- const address = [];
26594
- const buffer = [];
26595
- let endipv6Encountered = false;
26596
- let endIpv6 = false;
26597
- let consume = consumeHextets;
26598
- for (let i = 0; i < input.length; i++) {
26599
- const cursor = input[i];
26600
- if (cursor === "[" || cursor === "]") {
26601
- continue;
26602
- }
26603
- if (cursor === ":") {
26604
- if (endipv6Encountered === true) {
26605
- endIpv6 = true;
26606
- }
26607
- if (!consume(buffer, address, output)) {
26608
- break;
26609
- }
26610
- if (++tokenCount > 7) {
26611
- output.error = true;
26612
- break;
26613
- }
26614
- if (i > 0 && input[i - 1] === ":") {
26615
- endipv6Encountered = true;
26616
- }
26617
- address.push(":");
26618
- continue;
26619
- } else if (cursor === "%") {
26620
- if (!consume(buffer, address, output)) {
26621
- break;
26607
+ function compressIPv6ZeroRun(hextets) {
26608
+ let bestStart = -1;
26609
+ let bestLength = 0;
26610
+ let runStart = -1;
26611
+ let runLength = 0;
26612
+ for (let i = 0; i < hextets.length; i++) {
26613
+ if (hextets[i] === "0") {
26614
+ if (runStart === -1) runStart = i;
26615
+ runLength++;
26616
+ if (runLength > bestLength) {
26617
+ bestLength = runLength;
26618
+ bestStart = runStart;
26622
26619
  }
26623
- consume = consumeIsZone;
26624
26620
  } else {
26625
- buffer.push(cursor);
26621
+ runStart = -1;
26622
+ runLength = 0;
26623
+ }
26624
+ }
26625
+ if (bestLength < 2) return hextets.join(":");
26626
+ const head = hextets.slice(0, bestStart).join(":");
26627
+ const tail = hextets.slice(bestStart + bestLength).join(":");
26628
+ return head + "::" + tail;
26629
+ }
26630
+ function normalizeIPv6Address(input) {
26631
+ const compression = input.indexOf("::");
26632
+ if (compression !== -1 && input.indexOf("::", compression + 1) !== -1) return void 0;
26633
+ const left = compression === -1 ? input.split(":") : input.slice(0, compression).split(":");
26634
+ const right = compression === -1 ? [] : input.slice(compression + 2).split(":");
26635
+ if (compression !== -1) {
26636
+ if (left.length === 1 && left[0] === "") left.length = 0;
26637
+ if (right.length === 1 && right[0] === "") right.length = 0;
26638
+ }
26639
+ const parts = left.concat(right);
26640
+ let hextetCount = 0;
26641
+ for (let i = 0; i < parts.length; i++) {
26642
+ const part = parts[i];
26643
+ if (part === "") return void 0;
26644
+ if (part.indexOf(".") !== -1) {
26645
+ if (i !== parts.length - 1 || compression !== -1 && right.length === 0 || !isIPv4(part)) return void 0;
26646
+ hextetCount += 2;
26626
26647
  continue;
26627
26648
  }
26649
+ if (!isHextet(part)) return void 0;
26650
+ parts[i] = parseInt(part, 16).toString(16);
26651
+ hextetCount++;
26628
26652
  }
26629
- if (buffer.length) {
26630
- if (consume === consumeIsZone) {
26631
- output.zone = buffer.join("");
26632
- } else if (endIpv6) {
26633
- address.push(buffer.join(""));
26634
- } else {
26635
- address.push(stringArrayToHexStripped(buffer));
26636
- }
26653
+ if (compression === -1) {
26654
+ if (hextetCount !== 8) return void 0;
26655
+ return compressIPv6ZeroRun(parts);
26637
26656
  }
26638
- output.address = address.join("");
26639
- return output;
26657
+ if (hextetCount >= 8) return void 0;
26658
+ const expanded = parts.slice(0, left.length);
26659
+ for (let i = hextetCount; i < 8; i++) expanded.push("0");
26660
+ for (let i = left.length; i < parts.length; i++) expanded.push(parts[i]);
26661
+ return compressIPv6ZeroRun(expanded);
26640
26662
  }
26641
26663
  function normalizeIPv6(host) {
26642
- if (findToken(host, ":") < 2) {
26643
- return { host, isIPV6: false };
26644
- }
26645
- const ipv63 = getIPV6(host);
26646
- if (!ipv63.error) {
26647
- let newHost = ipv63.address;
26648
- let escapedHost = ipv63.address;
26649
- if (ipv63.zone) {
26650
- newHost += "%" + ipv63.zone;
26651
- escapedHost += "%25" + ipv63.zone;
26652
- }
26653
- return { host: newHost, isIPV6: true, escapedHost };
26654
- } else {
26655
- return { host, isIPV6: false };
26656
- }
26664
+ const bracketed = host[0] === "[" && host[host.length - 1] === "]";
26665
+ const hasBracket = host[0] === "[" || host[host.length - 1] === "]";
26666
+ if (hasBracket && !bracketed) return { host, isIPV6: false, error: true };
26667
+ let input = bracketed ? host.slice(1, -1) : host;
26668
+ if (bracketed && isIPvFuture(input)) {
26669
+ input = input.toLowerCase();
26670
+ return { host: `[${input}]`, escapedHost: input, isIPV6: false, isIPVFuture: true };
26671
+ }
26672
+ if (findToken(input, ":") < 2) {
26673
+ return { host, isIPV6: false, error: bracketed };
26674
+ }
26675
+ let zoneIdentifier = "";
26676
+ const zoneSeparator = input.indexOf("%");
26677
+ if (zoneSeparator !== -1) {
26678
+ const separatorLength = input.slice(zoneSeparator, zoneSeparator + 3).toLowerCase() === "%25" ? 3 : 1;
26679
+ zoneIdentifier = input.slice(zoneSeparator + separatorLength);
26680
+ if (!isZoneIdentifier(zoneIdentifier)) return { host, isIPV6: false, error: true };
26681
+ input = input.slice(0, zoneSeparator);
26682
+ }
26683
+ const address = normalizeIPv6Address(input);
26684
+ if (address === void 0) return { host, isIPV6: false, error: true };
26685
+ return {
26686
+ host: address + (zoneIdentifier ? "%" + zoneIdentifier : ""),
26687
+ escapedHost: address + (zoneIdentifier ? "%25" + zoneIdentifier : ""),
26688
+ isIPV6: true
26689
+ };
26657
26690
  }
26658
26691
  function findToken(str, token) {
26659
26692
  let ind = 0;
@@ -26772,7 +26805,8 @@ var require_utils = __commonJS({
26772
26805
  function normalizePathEncoding(input) {
26773
26806
  let output = "";
26774
26807
  for (let i = 0; i < input.length; i++) {
26775
- if (input[i] === "%" && i + 2 < input.length) {
26808
+ const ch = input[i];
26809
+ if (ch === "%" && i + 2 < input.length) {
26776
26810
  const hex3 = input.slice(i + 1, i + 3);
26777
26811
  if (isHexPair(hex3)) {
26778
26812
  const normalizedHex = hex3.toUpperCase();
@@ -26786,10 +26820,152 @@ var require_utils = __commonJS({
26786
26820
  continue;
26787
26821
  }
26788
26822
  }
26789
- if (isPathCharacter(input[i])) {
26790
- output += input[i];
26823
+ if (isPathCharacter(ch)) {
26824
+ output += ch;
26791
26825
  } else {
26792
- output += escape(input[i]);
26826
+ const code = input.charCodeAt(i);
26827
+ if (code < 128) {
26828
+ output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
26829
+ } else if (code < 55296 || code > 57343) {
26830
+ output += percentEncodeNonAscii(code);
26831
+ } else if (code <= 56319 && i + 1 < input.length) {
26832
+ const low = input.charCodeAt(i + 1);
26833
+ if (low >= 56320 && low <= 57343) {
26834
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
26835
+ i++;
26836
+ } else {
26837
+ output += percentEncodeNonAscii(65533);
26838
+ }
26839
+ } else {
26840
+ output += percentEncodeNonAscii(65533);
26841
+ }
26842
+ }
26843
+ }
26844
+ return output;
26845
+ }
26846
+ function serializePathEncoding(input, pathNoScheme = false) {
26847
+ let output = "";
26848
+ let firstSegment = pathNoScheme && input[0] !== "/";
26849
+ for (let i = 0; i < input.length; i++) {
26850
+ const ch = input[i];
26851
+ if (ch === "%" && i + 2 < input.length) {
26852
+ const hex3 = input.slice(i + 1, i + 3);
26853
+ if (isHexPair(hex3)) {
26854
+ output += "%" + hex3.toUpperCase();
26855
+ i += 2;
26856
+ continue;
26857
+ }
26858
+ }
26859
+ if (ch === "/") {
26860
+ firstSegment = false;
26861
+ }
26862
+ if (isPathCharacter(ch) && (ch !== ":" || !firstSegment)) {
26863
+ output += ch;
26864
+ } else {
26865
+ const code = input.charCodeAt(i);
26866
+ if (code < 128) {
26867
+ output += BYTE_HEX[code];
26868
+ } else if (code < 55296 || code > 57343) {
26869
+ output += percentEncodeNonAscii(code);
26870
+ } else if (code <= 56319 && i + 1 < input.length) {
26871
+ const low = input.charCodeAt(i + 1);
26872
+ if (low >= 56320 && low <= 57343) {
26873
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
26874
+ i++;
26875
+ } else {
26876
+ output += percentEncodeNonAscii(65533);
26877
+ }
26878
+ } else {
26879
+ output += percentEncodeNonAscii(65533);
26880
+ }
26881
+ }
26882
+ }
26883
+ return output;
26884
+ }
26885
+ function encodeComponent(input, isAllowed) {
26886
+ let output = "";
26887
+ for (let i = 0; i < input.length; i++) {
26888
+ const ch = input[i];
26889
+ if (ch === "%" && i + 2 < input.length) {
26890
+ const hex3 = input.slice(i + 1, i + 3);
26891
+ if (isHexPair(hex3)) {
26892
+ output += "%" + hex3.toUpperCase();
26893
+ i += 2;
26894
+ continue;
26895
+ }
26896
+ }
26897
+ if (isAllowed(ch)) {
26898
+ output += ch;
26899
+ } else {
26900
+ const code = input.charCodeAt(i);
26901
+ if (code < 128) {
26902
+ output += BYTE_HEX[code];
26903
+ } else if (code < 55296 || code > 57343) {
26904
+ output += percentEncodeNonAscii(code);
26905
+ } else if (code <= 56319 && i + 1 < input.length) {
26906
+ const low = input.charCodeAt(i + 1);
26907
+ if (low >= 56320 && low <= 57343) {
26908
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
26909
+ i++;
26910
+ } else {
26911
+ output += percentEncodeNonAscii(65533);
26912
+ }
26913
+ } else {
26914
+ output += percentEncodeNonAscii(65533);
26915
+ }
26916
+ }
26917
+ }
26918
+ return output;
26919
+ }
26920
+ function encodeUserinfo(input) {
26921
+ return encodeComponent(input, isUserinfoCharacter);
26922
+ }
26923
+ function encodeQuery(input) {
26924
+ return encodeComponent(input, isQueryFragmentCharacter);
26925
+ }
26926
+ function encodeFragment(input) {
26927
+ return encodeComponent(input, isQueryFragmentCharacter);
26928
+ }
26929
+ function isEscapeSafe(cp) {
26930
+ return cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 42 || cp === 43 || cp === 45 || cp === 46 || cp === 47 || cp === 64 || cp === 95;
26931
+ }
26932
+ function normalizeQueryFragmentEncoding(input) {
26933
+ let output = "";
26934
+ for (let i = 0; i < input.length; i++) {
26935
+ const ch = input[i];
26936
+ if (ch === "%" && i + 2 < input.length) {
26937
+ const hex3 = input.slice(i + 1, i + 3);
26938
+ if (isHexPair(hex3)) {
26939
+ const normalizedHex = hex3.toUpperCase();
26940
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
26941
+ if (isUnreserved(decoded)) {
26942
+ output += decoded;
26943
+ } else {
26944
+ output += "%" + normalizedHex;
26945
+ }
26946
+ i += 2;
26947
+ continue;
26948
+ }
26949
+ }
26950
+ if (isQueryFragmentCharacter(ch)) {
26951
+ output += ch;
26952
+ } else {
26953
+ const code = input.charCodeAt(i);
26954
+ if (code < 128) {
26955
+ output += isEscapeSafe(code) ? ch : BYTE_HEX[code];
26956
+ } else if (code < 55296 || code > 57343) {
26957
+ output += percentEncodeNonAscii(code);
26958
+ } else if (code <= 56319 && i + 1 < input.length) {
26959
+ const low = input.charCodeAt(i + 1);
26960
+ if (low >= 56320 && low <= 57343) {
26961
+ output += percentEncodeNonAscii(65536 + (code - 55296 << 10) + (low - 56320));
26962
+ i++;
26963
+ } else {
26964
+ output += percentEncodeNonAscii(65533);
26965
+ }
26966
+ } else {
26967
+ output += percentEncodeNonAscii(65533);
26968
+ }
26793
26969
  }
26794
26970
  }
26795
26971
  return output;
@@ -26812,14 +26988,18 @@ var require_utils = __commonJS({
26812
26988
  function recomposeAuthority(component) {
26813
26989
  const uriTokens = [];
26814
26990
  if (component.userinfo !== void 0) {
26815
- uriTokens.push(component.userinfo);
26991
+ uriTokens.push(encodeUserinfo(component.userinfo));
26816
26992
  uriTokens.push("@");
26817
26993
  }
26818
26994
  if (component.host !== void 0) {
26819
- let host = unescape(component.host);
26995
+ let host = component.host;
26820
26996
  if (!isIPv4(host)) {
26821
- const ipV6res = normalizeIPv6(host);
26822
- if (ipV6res.isIPV6 === true) {
26997
+ let ipV6res = normalizeIPv6(host);
26998
+ if (ipV6res.isIPV6 !== true && ipV6res.isIPVFuture !== true) {
26999
+ host = normalizePercentEncoding(host, true);
27000
+ ipV6res = normalizeIPv6(host);
27001
+ }
27002
+ if (ipV6res.isIPV6 === true || ipV6res.isIPVFuture === true) {
26823
27003
  host = `[${ipV6res.escapedHost}]`;
26824
27004
  } else {
26825
27005
  host = reescapeHostDelimiters(host, false);
@@ -26828,8 +27008,12 @@ var require_utils = __commonJS({
26828
27008
  uriTokens.push(host);
26829
27009
  }
26830
27010
  if (typeof component.port === "number" || typeof component.port === "string") {
27011
+ const port = String(component.port);
27012
+ if (!isPort(port)) {
27013
+ throw new TypeError("URI port is malformed.");
27014
+ }
26831
27015
  uriTokens.push(":");
26832
- uriTokens.push(String(component.port));
27016
+ uriTokens.push(port);
26833
27017
  }
26834
27018
  return uriTokens.length ? uriTokens.join("") : void 0;
26835
27019
  }
@@ -26839,6 +27023,11 @@ var require_utils = __commonJS({
26839
27023
  reescapeHostDelimiters,
26840
27024
  normalizePercentEncoding,
26841
27025
  normalizePathEncoding,
27026
+ serializePathEncoding,
27027
+ normalizeQueryFragmentEncoding,
27028
+ encodeUserinfo,
27029
+ encodeQuery,
27030
+ encodeFragment,
26842
27031
  escapePreservingEscapes,
26843
27032
  removeDotSegments,
26844
27033
  isIPv4,
@@ -26854,7 +27043,7 @@ var require_schemes = __commonJS({
26854
27043
  "node_modules/fast-uri/lib/schemes.js"(exports, module) {
26855
27044
  "use strict";
26856
27045
  var { isUUID } = require_utils();
26857
- var URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu;
27046
+ var URN_REG = /^([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-./:;=@]|%[\da-f]{2})+)$/iu;
26858
27047
  var supportedSchemeNames = (
26859
27048
  /** @type {const} */
26860
27049
  [
@@ -26915,9 +27104,10 @@ var require_schemes = __commonJS({
26915
27104
  wsComponent.secure = void 0;
26916
27105
  }
26917
27106
  if (wsComponent.resourceName) {
26918
- const [path, query] = wsComponent.resourceName.split("?");
27107
+ const queryIndex = wsComponent.resourceName.indexOf("?");
27108
+ const path = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
26919
27109
  wsComponent.path = path && path !== "/" ? path : void 0;
26920
- wsComponent.query = query;
27110
+ wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
26921
27111
  wsComponent.resourceName = void 0;
26922
27112
  }
26923
27113
  wsComponent.fragment = void 0;
@@ -26929,7 +27119,7 @@ var require_schemes = __commonJS({
26929
27119
  return urnComponent;
26930
27120
  }
26931
27121
  const matches = urnComponent.path.match(URN_REG);
26932
- if (matches) {
27122
+ if (matches && matches[0] === urnComponent.path) {
26933
27123
  const scheme = options.scheme || urnComponent.scheme || "urn";
26934
27124
  urnComponent.nid = matches[1].toLowerCase();
26935
27125
  urnComponent.nss = matches[2];
@@ -27063,8 +27253,17 @@ var require_schemes = __commonJS({
27063
27253
  var require_fast_uri = __commonJS({
27064
27254
  "node_modules/fast-uri/index.js"(exports, module) {
27065
27255
  "use strict";
27066
- var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
27256
+ var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, serializePathEncoding, normalizeQueryFragmentEncoding, encodeQuery, encodeFragment, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
27067
27257
  var { SCHEMES, getSchemeHandler } = require_schemes();
27258
+ var VALID_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*$/u;
27259
+ var MALFORMED_SCHEME_ERROR = "URI scheme is malformed.";
27260
+ function decodeValidScheme(scheme) {
27261
+ const decodedScheme = unescape(String(scheme));
27262
+ if (!VALID_SCHEME.test(decodedScheme)) {
27263
+ throw new TypeError(MALFORMED_SCHEME_ERROR);
27264
+ }
27265
+ return decodedScheme;
27266
+ }
27068
27267
  function normalize(uri, options) {
27069
27268
  if (typeof uri === "string") {
27070
27269
  uri = /** @type {T} */
@@ -27077,12 +27276,34 @@ var require_fast_uri = __commonJS({
27077
27276
  }
27078
27277
  function resolve2(baseURI, relativeURI, options) {
27079
27278
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
27080
- const { parsed: baseParsed, malformedAuthorityOrPort: baseMalformed } = parseWithStatus(baseURI, schemelessOptions);
27081
- const { parsed: relativeParsed, malformedAuthorityOrPort: relativeMalformed } = parseWithStatus(relativeURI, schemelessOptions);
27082
- if (baseMalformed || relativeMalformed) {
27279
+ const {
27280
+ parsed: baseParsed,
27281
+ malformedAuthorityOrPort: baseMalformed,
27282
+ malformedPercentEncoding: baseMalformedPercentEncoding,
27283
+ malformedSchemeSpecific: baseMalformedSchemeSpecific,
27284
+ malformedHost: baseMalformedHost,
27285
+ malformedScheme: baseMalformedScheme
27286
+ } = parseWithStatus(baseURI, schemelessOptions);
27287
+ const {
27288
+ parsed: relativeParsed,
27289
+ malformedAuthorityOrPort: relativeMalformed,
27290
+ malformedPercentEncoding: relativeMalformedPercentEncoding,
27291
+ malformedSchemeSpecific: relativeMalformedSchemeSpecific,
27292
+ malformedHost: relativeMalformedHost,
27293
+ malformedScheme: relativeMalformedScheme
27294
+ } = parseWithStatus(relativeURI, schemelessOptions);
27295
+ if (baseMalformed || relativeMalformed || baseMalformedPercentEncoding || relativeMalformedPercentEncoding || baseMalformedSchemeSpecific || relativeMalformedSchemeSpecific || baseMalformedHost || relativeMalformedHost || baseMalformedScheme || relativeMalformedScheme) {
27083
27296
  throw new Error(baseParsed.error || relativeParsed.error || "URI is malformed.");
27084
27297
  }
27085
27298
  const resolved = resolveComponent(baseParsed, relativeParsed, schemelessOptions, true);
27299
+ const resolvedSchemeHandler = getSchemeHandler(options && options.scheme || resolved.scheme);
27300
+ const resolvedHost = resolved.host;
27301
+ const resolvedHostIsIP = resolvedHost !== void 0 && resolvedHost !== "" && (isIPv4(resolvedHost) || normalizeIPv6(resolvedHost).isIPV6);
27302
+ canonicalizeHost(resolved, options || {}, resolvedSchemeHandler, resolvedHostIsIP);
27303
+ const encodedASCIIHost = resolvedHost && resolvedHost.indexOf("%") !== -1 && !/\P{ASCII}/u.test(resolvedHost);
27304
+ if (resolved.error && !encodedASCIIHost) {
27305
+ throw new Error(resolved.error);
27306
+ }
27086
27307
  schemelessOptions.skipEscape = true;
27087
27308
  return serialize(resolved, schemelessOptions);
27088
27309
  }
@@ -27142,7 +27363,7 @@ var require_fast_uri = __commonJS({
27142
27363
  function equal(uriA, uriB, options) {
27143
27364
  const normalizedA = normalizeComparableURI(uriA, options);
27144
27365
  const normalizedB = normalizeComparableURI(uriB, options);
27145
- return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase();
27366
+ return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA === normalizedB;
27146
27367
  }
27147
27368
  function serialize(cmpts, opts) {
27148
27369
  const component = {
@@ -27163,19 +27384,22 @@ var require_fast_uri = __commonJS({
27163
27384
  };
27164
27385
  const options = Object.assign({}, opts);
27165
27386
  const uriTokens = [];
27387
+ if (component.scheme) {
27388
+ component.scheme = decodeValidScheme(component.scheme);
27389
+ }
27166
27390
  const schemeHandler = getSchemeHandler(options.scheme || component.scheme);
27167
27391
  if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
27392
+ const hasAuthority = component.userinfo !== void 0 || component.host !== void 0 || component.port !== void 0;
27393
+ const pathNoScheme = !options.skipEscape && component.scheme === void 0 && !hasAuthority;
27168
27394
  if (component.path !== void 0) {
27169
27395
  if (!options.skipEscape) {
27170
- component.path = escapePreservingEscapes(component.path);
27171
- if (component.scheme !== void 0) {
27172
- component.path = component.path.split("%3A").join(":");
27173
- }
27396
+ component.path = serializePathEncoding(component.path, pathNoScheme);
27174
27397
  } else {
27175
27398
  component.path = normalizePercentEncoding(component.path);
27176
27399
  }
27177
27400
  }
27178
27401
  if (options.reference !== "suffix" && component.scheme) {
27402
+ component.scheme = decodeValidScheme(component.scheme);
27179
27403
  uriTokens.push(component.scheme, ":");
27180
27404
  }
27181
27405
  const authority = recomposeAuthority(component);
@@ -27193,16 +27417,19 @@ var require_fast_uri = __commonJS({
27193
27417
  if (!options.absolutePath && (!schemeHandler || !schemeHandler.absolutePath)) {
27194
27418
  s = removeDotSegments(s);
27195
27419
  }
27420
+ if (pathNoScheme) {
27421
+ s = serializePathEncoding(s, true);
27422
+ }
27196
27423
  if (authority === void 0 && s[0] === "/" && s[1] === "/") {
27197
27424
  s = "/%2F" + s.slice(2);
27198
27425
  }
27199
27426
  uriTokens.push(s);
27200
27427
  }
27201
27428
  if (component.query !== void 0) {
27202
- uriTokens.push("?", component.query);
27429
+ uriTokens.push("?", encodeQuery(component.query));
27203
27430
  }
27204
27431
  if (component.fragment !== void 0) {
27205
- uriTokens.push("#", component.fragment);
27432
+ uriTokens.push("#", encodeFragment(component.fragment));
27206
27433
  }
27207
27434
  return uriTokens.join("");
27208
27435
  }
@@ -27218,6 +27445,35 @@ var require_fast_uri = __commonJS({
27218
27445
  }
27219
27446
  return void 0;
27220
27447
  }
27448
+ function hasMalformedPercentEncoding(component) {
27449
+ if (component === void 0) return false;
27450
+ let percent = component.indexOf("%");
27451
+ while (percent !== -1) {
27452
+ if (percent + 2 >= component.length || !/^[\da-f]{2}$/iu.test(component.slice(percent + 1, percent + 3))) {
27453
+ return true;
27454
+ }
27455
+ percent = component.indexOf("%", percent + 3);
27456
+ }
27457
+ return false;
27458
+ }
27459
+ function isIPLiteral(host) {
27460
+ return host[0] === "[" && host[host.length - 1] === "]";
27461
+ }
27462
+ function hasMalformedComponentPercentEncoding(matches) {
27463
+ const host = matches[4];
27464
+ return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
27465
+ }
27466
+ function canonicalizeHost(parsed, options, schemeHandler, isIP) {
27467
+ if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
27468
+ try {
27469
+ parsed.host = new URL("http://" + parsed.host).hostname;
27470
+ } catch (e) {
27471
+ parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
27472
+ return true;
27473
+ }
27474
+ }
27475
+ return false;
27476
+ }
27221
27477
  function parseWithStatus(uri, opts) {
27222
27478
  const options = Object.assign({}, opts);
27223
27479
  const parsed = {
@@ -27230,6 +27486,11 @@ var require_fast_uri = __commonJS({
27230
27486
  fragment: void 0
27231
27487
  };
27232
27488
  let malformedAuthorityOrPort = false;
27489
+ let malformedPercentEncoding = false;
27490
+ let malformedSchemeSpecific = false;
27491
+ let malformedHost = false;
27492
+ let malformedIPLiteral = false;
27493
+ let malformedScheme = false;
27233
27494
  let isIP = false;
27234
27495
  if (options.reference === "suffix") {
27235
27496
  if (options.scheme) {
@@ -27266,6 +27527,19 @@ var require_fast_uri = __commonJS({
27266
27527
  parsed.path = matches[6] || "";
27267
27528
  parsed.query = matches[7];
27268
27529
  parsed.fragment = matches[8];
27530
+ if (parsed.scheme !== void 0) {
27531
+ const decodedScheme = unescape(parsed.scheme);
27532
+ if (VALID_SCHEME.test(decodedScheme)) {
27533
+ parsed.scheme = decodedScheme.toLowerCase();
27534
+ } else {
27535
+ parsed.error = parsed.error || MALFORMED_SCHEME_ERROR;
27536
+ malformedScheme = true;
27537
+ }
27538
+ }
27539
+ malformedPercentEncoding = hasMalformedComponentPercentEncoding(matches);
27540
+ if (malformedPercentEncoding) {
27541
+ parsed.error = parsed.error || "URI contains malformed percent-encoding.";
27542
+ }
27269
27543
  if (isNaN(parsed.port)) {
27270
27544
  parsed.port = matches[5];
27271
27545
  }
@@ -27277,9 +27551,16 @@ var require_fast_uri = __commonJS({
27277
27551
  if (parsed.host) {
27278
27552
  const ipv4result = isIPv4(parsed.host);
27279
27553
  if (ipv4result === false) {
27554
+ const bracketedIPLiteral = isIPLiteral(parsed.host);
27555
+ const hasIPLiteralBracket = parsed.host.indexOf("[") !== -1 || parsed.host.indexOf("]") !== -1;
27280
27556
  const ipv6result = normalizeIPv6(parsed.host);
27281
- parsed.host = ipv6result.host.toLowerCase();
27282
- isIP = ipv6result.isIPV6;
27557
+ isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
27558
+ malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
27559
+ parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
27560
+ if (malformedIPLiteral) {
27561
+ parsed.error = parsed.error || "URI host is malformed.";
27562
+ malformedAuthorityOrPort = true;
27563
+ }
27283
27564
  } else {
27284
27565
  isIP = true;
27285
27566
  }
@@ -27297,42 +27578,36 @@ var require_fast_uri = __commonJS({
27297
27578
  parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
27298
27579
  }
27299
27580
  const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
27300
- if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
27301
- if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
27302
- try {
27303
- parsed.host = new URL("http://" + parsed.host).hostname;
27304
- } catch (e) {
27305
- parsed.error = parsed.error || "Host's domain name can not be converted to ASCII: " + e;
27306
- }
27307
- }
27581
+ if (!malformedIPLiteral) {
27582
+ malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
27308
27583
  }
27309
27584
  if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
27310
27585
  if (uri.indexOf("%") !== -1) {
27311
- if (parsed.scheme !== void 0) {
27312
- parsed.scheme = unescape(parsed.scheme);
27313
- }
27314
- if (parsed.host !== void 0) {
27315
- parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
27586
+ if (parsed.host !== void 0 && !malformedIPLiteral) {
27587
+ const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
27588
+ parsed.host = reescapeHostDelimiters(host, isIP);
27316
27589
  }
27317
27590
  }
27318
27591
  if (parsed.path) {
27319
27592
  parsed.path = normalizePathEncoding(parsed.path);
27320
27593
  }
27594
+ if (parsed.query) {
27595
+ parsed.query = normalizeQueryFragmentEncoding(parsed.query);
27596
+ }
27321
27597
  if (parsed.fragment) {
27322
- try {
27323
- parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
27324
- } catch {
27325
- parsed.error = parsed.error || "URI malformed";
27326
- }
27598
+ parsed.fragment = normalizeQueryFragmentEncoding(parsed.fragment);
27327
27599
  }
27328
27600
  }
27329
27601
  if (schemeHandler && schemeHandler.parse) {
27330
27602
  schemeHandler.parse(parsed, options);
27603
+ if (schemeHandler === SCHEMES.urn && parsed.nid === void 0) {
27604
+ malformedSchemeSpecific = true;
27605
+ }
27331
27606
  }
27332
27607
  } else {
27333
27608
  parsed.error = parsed.error || "URI can not be parsed.";
27334
27609
  }
27335
- return { parsed, malformedAuthorityOrPort };
27610
+ return { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme };
27336
27611
  }
27337
27612
  function parse3(uri, opts) {
27338
27613
  return parseWithStatus(uri, opts).parsed;
@@ -27341,20 +27616,28 @@ var require_fast_uri = __commonJS({
27341
27616
  return normalizeStringWithStatus(uri, opts).normalized;
27342
27617
  }
27343
27618
  function normalizeStringWithStatus(uri, opts) {
27344
- const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
27619
+ const { parsed, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = parseWithStatus(uri, opts);
27345
27620
  return {
27346
- normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
27347
- malformedAuthorityOrPort
27621
+ normalized: malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? uri : serialize(parsed, opts),
27622
+ malformedAuthorityOrPort,
27623
+ malformedPercentEncoding,
27624
+ malformedSchemeSpecific,
27625
+ malformedHost,
27626
+ malformedScheme
27348
27627
  };
27349
27628
  }
27350
27629
  function normalizeComparableURI(uri, opts) {
27351
- if (typeof uri === "string") {
27352
- const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
27353
- return malformedAuthorityOrPort ? void 0 : normalized;
27630
+ if (typeof uri !== "string" && typeof uri !== "object") {
27631
+ return void 0;
27354
27632
  }
27355
- if (typeof uri === "object") {
27356
- return serialize(uri, opts);
27633
+ let value;
27634
+ try {
27635
+ value = typeof uri === "string" ? uri : serialize(uri, opts);
27636
+ } catch {
27637
+ return void 0;
27357
27638
  }
27639
+ const { normalized, malformedAuthorityOrPort, malformedPercentEncoding, malformedSchemeSpecific, malformedHost, malformedScheme } = normalizeStringWithStatus(value, opts);
27640
+ return malformedAuthorityOrPort || malformedPercentEncoding || malformedSchemeSpecific || malformedHost || malformedScheme ? void 0 : normalized;
27358
27641
  }
27359
27642
  var fastUri = {
27360
27643
  SCHEMES,
@@ -32110,6 +32393,11 @@ function truncateErrorMessage(text, max = DEFAULT_ERROR_MESSAGE_MAX) {
32110
32393
  return redacted;
32111
32394
  return `${redacted.slice(0, max)}\u2026 [truncated]`;
32112
32395
  }
32396
+ function messageOf(err) {
32397
+ if (err instanceof Error)
32398
+ return err.message;
32399
+ return String(err);
32400
+ }
32113
32401
  var DEFAULT_ERROR_MESSAGE_MAX, McpToolError, BEARER_RE, JWT_RE, BASIC_AUTH_RE, SET_COOKIE_RE, COOKIE_HEADER_RE, API_KEY_RE, QUERY_SECRET_RE, AWS_SIGV4_RE, JSON_SECRET_KEYS, JSON_SECRET_DQ_RE, JSON_SECRET_SQ_RE;
32114
32402
  var init_errors4 = __esm({
32115
32403
  "node_modules/@chrischall/mcp-utils/dist/errors/index.js"() {
@@ -32152,12 +32440,25 @@ var init_errors4 = __esm({
32152
32440
  }
32153
32441
  });
32154
32442
 
32155
- // node_modules/@chrischall/mcp-utils/dist/response/index.js
32156
- function textResult(data) {
32157
- return {
32158
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
32159
- };
32443
+ // node_modules/@chrischall/mcp-utils/dist/response/view.js
32444
+ function minifiedResult(data) {
32445
+ return { content: [{ type: "text", text: JSON.stringify(data) }] };
32160
32446
  }
32447
+ var init_view = __esm({
32448
+ "node_modules/@chrischall/mcp-utils/dist/response/view.js"() {
32449
+ }
32450
+ });
32451
+
32452
+ // node_modules/@chrischall/mcp-utils/dist/response/media.js
32453
+ var MEDIA_NOUN, MEDIA_KEY;
32454
+ var init_media = __esm({
32455
+ "node_modules/@chrischall/mcp-utils/dist/response/media.js"() {
32456
+ MEDIA_NOUN = "(?:avatar|tall_avatar|cover_photo|cover_image|picture|photo|thumbnail|thumb|image|icon|banner|profile_pic(?:ture)?|logo)";
32457
+ MEDIA_KEY = new RegExp(`^${MEDIA_NOUN}s?(?:(?:link|uri|url)s?)?$`, "i");
32458
+ }
32459
+ });
32460
+
32461
+ // node_modules/@chrischall/mcp-utils/dist/response/index.js
32161
32462
  function errorResult(message) {
32162
32463
  return {
32163
32464
  content: [{ type: "text", text: redactSecrets(message) }],
@@ -32167,6 +32468,8 @@ function errorResult(message) {
32167
32468
  var init_response = __esm({
32168
32469
  "node_modules/@chrischall/mcp-utils/dist/response/index.js"() {
32169
32470
  init_errors4();
32471
+ init_view();
32472
+ init_media();
32170
32473
  }
32171
32474
  });
32172
32475
 
@@ -32876,7 +33179,7 @@ async function loadStdioDotenv() {
32876
33179
  }
32877
33180
 
32878
33181
  // src/version.ts
32879
- var VERSION = "1.11.1";
33182
+ var VERSION = "1.13.0";
32880
33183
 
32881
33184
  // src/errors.ts
32882
33185
  init_dist();
@@ -32947,11 +33250,166 @@ function registerModelTools(server, client2) {
32947
33250
  },
32948
33251
  async () => {
32949
33252
  const models = await client2.listModels();
32950
- return textResult({ default: client2.defaultModel(), models });
33253
+ return minifiedResult({ default: client2.defaultModel(), models });
32951
33254
  }
32952
33255
  );
32953
33256
  }
32954
33257
 
33258
+ // node_modules/@chrischall/mcp-utils/dist/healthcheck/index.js
33259
+ init_errors4();
33260
+ function statusOf(err) {
33261
+ if (typeof err !== "object" || err === null)
33262
+ return void 0;
33263
+ const s = err.status ?? err.statusCode;
33264
+ return typeof s === "number" ? s : void 0;
33265
+ }
33266
+ var CREDENTIAL_ARMS = /* @__PURE__ */ new Set([
33267
+ "ok",
33268
+ "no_credential",
33269
+ "credential_rejected",
33270
+ "timeout",
33271
+ "http",
33272
+ "transport",
33273
+ "unknown"
33274
+ ]);
33275
+ function isArm(kind) {
33276
+ return kind !== void 0 && CREDENTIAL_ARMS.has(kind);
33277
+ }
33278
+ function credentialHint(arm, prefix, hostLabel, source) {
33279
+ switch (arm) {
33280
+ case "ok":
33281
+ return `Credential from '${source}' works: ${hostLabel} accepted an authenticated request. If a real tool still fails, the problem is that tool, not auth.`;
33282
+ case "no_credential":
33283
+ return `No credential resolved. Nothing was available to authenticate with \u2014 sign in and reconnect the connector so ${prefix} receives a token, or set the documented environment variable.`;
33284
+ case "credential_rejected":
33285
+ return `${hostLabel} rejected the credential from '${source}'. It is present but no longer valid \u2014 most often expired or revoked upstream. Re-authenticate and reconnect; retrying will not fix it.`;
33286
+ case "timeout":
33287
+ return `The credential from '${source}' resolved, but ${hostLabel} did not answer in time. Usually transient \u2014 retry. If it persists, ${hostLabel} is slow or unreachable from here.`;
33288
+ case "http":
33289
+ return `${hostLabel} answered with an error status that is not an auth rejection. That is USUALLY a ${hostLabel}-side problem rather than an auth one \u2014 but a 404 here more often means the probe path is wrong than that ${hostLabel} is broken, so check error.message and probe.url before concluding anything about the credential.`;
33290
+ case "transport":
33291
+ return `Could not reach ${hostLabel} at all. Check network egress; the credential itself was never judged.`;
33292
+ default:
33293
+ return `Unexpected failure \u2014 see error.message.`;
33294
+ }
33295
+ }
33296
+ function registerCredentialHealthcheckTool(args) {
33297
+ const { server, prefix, hostLabel, probePath, resolveCredential, probeFn, classifyThrown, hints } = args;
33298
+ const probeUrl = probePath ? `https://${hostLabel}${probePath}` : void 0;
33299
+ server.registerTool(`${prefix}_healthcheck`, {
33300
+ title: "Verify credentials and upstream reachability",
33301
+ description: `Resolves the credential the way real tools do, then makes one authenticated request to ${hostLabel}. Reports which source supplied the credential, whether ${hostLabel} accepted it, the round-trip time, and a plain-English hint distinguishing 'no credential' from 'credential rejected' from 'a ${hostLabel}-side problem'. Call this when a real tool fails and you want to know which hop broke. Read-only; never returns the credential itself.`,
33302
+ annotations: {
33303
+ title: "Verify credentials and upstream reachability",
33304
+ readOnlyHint: true,
33305
+ idempotentHint: true,
33306
+ openWorldHint: true
33307
+ },
33308
+ inputSchema: {}
33309
+ }, async () => {
33310
+ let probeStarted = 0;
33311
+ let state;
33312
+ try {
33313
+ state = await resolveCredential();
33314
+ } catch (e) {
33315
+ const classified = classifyThrown?.(e);
33316
+ const result2 = {
33317
+ ok: false,
33318
+ // Still false, and still no source: a classification explains WHY
33319
+ // nothing resolved, it does not invent a credential that did.
33320
+ credential: { source: null, resolved: false },
33321
+ // No `url`: nothing was probed, and naming one implies it was tried.
33322
+ probe: { elapsed_ms: 0 },
33323
+ error: {
33324
+ kind: classified?.kind ?? "no_credential",
33325
+ message: truncateErrorMessage(messageOf(e)),
33326
+ ...classified?.detail !== void 0 ? { detail: classified.detail } : {}
33327
+ },
33328
+ // The hint must follow the KIND beside it. Falling back to
33329
+ // `no_credential`'s copy under a classified kind would state a cause
33330
+ // the kind contradicts — the same disagreement this path exists to
33331
+ // remove. So: an inline hint wins; else the classified arm's own
33332
+ // copy (consumer override first); else, for a kind this module has
33333
+ // no copy for, the neutral `unknown` text rather than one that
33334
+ // asserts a cause; else the unclassified `no_credential` default.
33335
+ hint: classified?.hint ?? (isArm(classified?.kind) ? hints?.[classified.kind] ?? credentialHint(classified.kind, prefix, hostLabel, null) : classified !== void 0 ? credentialHint("unknown", prefix, hostLabel, null) : hints?.no_credential ?? credentialHint("no_credential", prefix, hostLabel, null))
33336
+ };
33337
+ return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
33338
+ }
33339
+ const credential = {
33340
+ source: state.source,
33341
+ resolved: state.source !== null,
33342
+ ...state.detail !== void 0 ? { detail: state.detail } : {}
33343
+ };
33344
+ if (!credential.resolved) {
33345
+ const result2 = {
33346
+ ok: false,
33347
+ credential,
33348
+ probe: { elapsed_ms: 0 },
33349
+ error: { kind: "no_credential", message: "no credential source resolved" },
33350
+ hint: hints?.no_credential ?? credentialHint("no_credential", prefix, hostLabel, null)
33351
+ };
33352
+ return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
33353
+ }
33354
+ let arm = "ok";
33355
+ let error51;
33356
+ let status;
33357
+ let customHint;
33358
+ probeStarted = Date.now();
33359
+ try {
33360
+ await probeFn();
33361
+ } catch (e) {
33362
+ status = statusOf(e);
33363
+ const aborted2 = e instanceof Error && e.name === "AbortError";
33364
+ arm = status === 401 || status === 403 ? "credential_rejected" : status !== void 0 ? "http" : aborted2 || /timeout|timed out|ETIMEDOUT/i.test(messageOf(e)) ? "timeout" : /fetch failed|ENOTFOUND|ECONNREFUSED|ECONNRESET|network/i.test(messageOf(e)) ? "transport" : "unknown";
33365
+ let kind = arm;
33366
+ let detail;
33367
+ const custom2 = classifyThrown?.(e);
33368
+ if (custom2) {
33369
+ kind = custom2.kind;
33370
+ customHint = custom2.hint;
33371
+ detail = custom2.detail;
33372
+ }
33373
+ error51 = {
33374
+ kind,
33375
+ // Redacted AND bounded before it reaches the result: an upstream
33376
+ // failure routinely quotes what it was sent, and a healthcheck is
33377
+ // the tool people paste into a chat when something is broken.
33378
+ message: truncateErrorMessage(messageOf(e)),
33379
+ ...detail !== void 0 ? { detail } : {}
33380
+ };
33381
+ }
33382
+ const result = {
33383
+ ok: error51 === void 0,
33384
+ credential,
33385
+ probe: {
33386
+ ...probeUrl ? { url: probeUrl } : {},
33387
+ elapsed_ms: Date.now() - probeStarted,
33388
+ ...status !== void 0 ? { status } : {}
33389
+ },
33390
+ ...error51 ? { error: error51 } : {},
33391
+ hint: customHint ?? hints?.[arm] ?? credentialHint(arm, prefix, hostLabel, state.source)
33392
+ };
33393
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33394
+ });
33395
+ }
33396
+
33397
+ // src/tools/healthcheck.ts
33398
+ function registerHealthcheckTools(server, client2) {
33399
+ registerCredentialHealthcheckTool({
33400
+ server,
33401
+ prefix: "gemini",
33402
+ hostLabel: "generativelanguage.googleapis.com",
33403
+ probePath: "/v1beta/models",
33404
+ resolveCredential: async () => client2.describeCredential(),
33405
+ probeFn: () => client2.listModels(),
33406
+ hints: {
33407
+ no_credential: "No Gemini API key resolved. Set GEMINI_API_KEY (https://aistudio.google.com/apikey), or reconnect the connector so it supplies one.",
33408
+ credential_rejected: "Google rejected the API key. It is present but no longer valid \u2014 most often revoked, or restricted to different APIs/referrers. Issue a new key at https://aistudio.google.com/apikey."
33409
+ }
33410
+ });
33411
+ }
33412
+
32955
33413
  // src/tools/generate.ts
32956
33414
  init_zod();
32957
33415
  init_dist();
@@ -33866,7 +34324,7 @@ async function emitMedia(named, kind, opts, meta3, onWritten) {
33866
34324
  }))
33867
34325
  } : {};
33868
34326
  const storage = sink.persistsFiles ? {} : { storage: sink.kind, storage_note: storageNote };
33869
- return textResult({ [`${kind}s`]: refs, ...media, ...unavailable, ...note, ...storage, ...meta3 });
34327
+ return minifiedResult({ [`${kind}s`]: refs, ...media, ...unavailable, ...note, ...storage, ...meta3 });
33870
34328
  }
33871
34329
  async function emit(named, opts, meta3, onWritten) {
33872
34330
  return emitMedia(named.map((n) => ({ media: n.image, base: n.base })), "image", opts, meta3, onWritten);
@@ -34161,7 +34619,7 @@ function annotateReused(result, jobId) {
34161
34619
  };
34162
34620
  }
34163
34621
  function jobHandle(jobId, status, durable = false) {
34164
- return textResult({
34622
+ return minifiedResult({
34165
34623
  job_id: jobId,
34166
34624
  status,
34167
34625
  hint: durable ? `Generation running in the background. Poll gemini_get_result with job_id "${jobId}" until status is "done". The job record is stored durably, so a poll still works if this connector restarts \u2014 but background work is NOT restarted, so a long generation is safer with max_wait_ms than with async.` : `Generation running in the background. Poll gemini_get_result with job_id "${jobId}" until status is "done" (results are per-process and expire ~10 min after completion).`
@@ -34650,7 +35108,7 @@ init_dist();
34650
35108
  init_images();
34651
35109
  function previewUnlessConfirmed(confirm, action, method, path, body) {
34652
35110
  if (confirm === true) return null;
34653
- return textResult({
35111
+ return minifiedResult({
34654
35112
  dryRun: true,
34655
35113
  action,
34656
35114
  method,
@@ -35551,6 +36009,16 @@ var GeminiClient = class {
35551
36009
  * That is an invisible, silent failure (the key just stops working); not
35552
36010
  * depending on the order removes the hazard instead of documenting it.
35553
36011
  */
36012
+ /**
36013
+ * Which source supplies the API key, for `gemini_healthcheck` — a LABEL or
36014
+ * `null`, never the key. Mirrors `requireKey`'s resolution order exactly, so
36015
+ * the healthcheck reports the same source the real tools will use, but does
36016
+ * NOT throw: "no key" is an answer here rather than an error.
36017
+ */
36018
+ describeCredential() {
36019
+ if (this.explicitApiKey) return { source: "connector-session" };
36020
+ return { source: readEnvVar("GEMINI_API_KEY") ? "env" : null };
36021
+ }
35554
36022
  requireKey() {
35555
36023
  const key = this.explicitApiKey || readEnvVar("GEMINI_API_KEY");
35556
36024
  if (!key) {
@@ -36780,7 +37248,7 @@ function recoveryNote(recordedError) {
36780
37248
  return `${cause} The generation had already completed upstream and its output was recovered \u2014 it was not re-run, and you were not billed twice.`;
36781
37249
  }
36782
37250
  function stillRunning(jobId, interactionId) {
36783
- return textResult({
37251
+ return minifiedResult({
36784
37252
  job_id: jobId,
36785
37253
  status: "running",
36786
37254
  interaction_id: interactionId,
@@ -36819,7 +37287,7 @@ function registerUsageTools(server, client2) {
36819
37287
  client2.session.costUsd = void 0;
36820
37288
  client2.session.pricedCalls = 0;
36821
37289
  }
36822
- return textResult({
37290
+ return minifiedResult({
36823
37291
  usage: usage ?? null,
36824
37292
  billed_calls: calls,
36825
37293
  estimated_cost_usd: costUsd ?? null,
@@ -36842,7 +37310,7 @@ var UPLOAD_URL_MAX_BYTES_HOSTED = 25 * 1024 * 1024;
36842
37310
  var UPLOAD_ACCEPT = ["image/", "video/", "audio/"];
36843
37311
  var RETENTION_NOTE = "Gemini retains uploaded files for ~48h. Until then this reference can be reused across any number of calls (images_file_uris on gemini_image_generate / _edit / _set / gemini_interact, or video_url) without re-sending the bytes.";
36844
37312
  function uploadResult(file2) {
36845
- return textResult({
37313
+ return minifiedResult({
36846
37314
  // The `files/<id>` form is what every tool parameter documents, so it leads.
36847
37315
  file_uri: file2.name,
36848
37316
  // The absolute uri, for callers that would rather pass it through verbatim.
@@ -36955,7 +37423,7 @@ function registerFileTools(server, client2) {
36955
37423
  },
36956
37424
  async (args) => {
36957
37425
  const files = await client2.listFiles(args.page_size ?? 100);
36958
- return textResult({
37426
+ return minifiedResult({
36959
37427
  count: files.length,
36960
37428
  files: files.map((f) => ({
36961
37429
  file_uri: f.name,
@@ -36995,7 +37463,7 @@ function registerFileTools(server, client2) {
36995
37463
  { hint: "Objects are swept on a retention schedule (MEDIA_TTL_DAYS, default 7 days)." }
36996
37464
  );
36997
37465
  }
36998
- return textResult({
37466
+ return minifiedResult({
36999
37467
  url: fresh.ref,
37000
37468
  r2_key: fresh.key,
37001
37469
  ...fresh.expiresAt ? { expires_at: fresh.expiresAt } : {},
@@ -37024,7 +37492,7 @@ function registerFileTools(server, client2) {
37024
37492
  const limit = args.limit ?? 20;
37025
37493
  const page = sink.listRecentPage ? await sink.listRecentPage({ limit, sinceDay: args.since_day }) : { media: await sink.listRecent({ limit, sinceDay: args.since_day }), truncated: false };
37026
37494
  const found = page.media;
37027
- return textResult({
37495
+ return minifiedResult({
37028
37496
  count: found.length,
37029
37497
  // Never let a bounded walk pass for the whole picture: concluding an
37030
37498
  // image is gone is what makes someone pay to generate it twice.
@@ -37056,7 +37524,7 @@ function registerFileTools(server, client2) {
37056
37524
  const gate = previewUnlessConfirmed(args.confirm, "Delete an uploaded Gemini file", "DELETE", `/v1beta/${args.file_uri}`);
37057
37525
  if (gate) return gate;
37058
37526
  await client2.deleteFile(args.file_uri);
37059
- return textResult({ deleted: args.file_uri });
37527
+ return minifiedResult({ deleted: args.file_uri });
37060
37528
  }
37061
37529
  );
37062
37530
  }
@@ -37082,7 +37550,7 @@ function registerUploadUrlTools(server, client2) {
37082
37550
  `minting a signed upload URL for ${args.filename} (${args.content_type})`,
37083
37551
  () => minter.mint(args.filename, args.content_type)
37084
37552
  );
37085
- return textResult({
37553
+ return minifiedResult({
37086
37554
  upload_url: minted.url,
37087
37555
  method: "PUT",
37088
37556
  r2_key: minted.key,
@@ -37153,7 +37621,7 @@ function registerLibraryTools(server, client2) {
37153
37621
  () => resolveLibraryImage(client2, args, true)
37154
37622
  );
37155
37623
  const record2 = await library.saveCharacter({ name: args.name, description: args.description, image });
37156
- return textResult({
37624
+ return minifiedResult({
37157
37625
  saved: "character",
37158
37626
  name: record2.name,
37159
37627
  description: record2.description,
@@ -37173,7 +37641,7 @@ function registerLibraryTools(server, client2) {
37173
37641
  },
37174
37642
  async () => {
37175
37643
  const characters = await library.listCharacters();
37176
- return textResult({
37644
+ return minifiedResult({
37177
37645
  count: characters.length,
37178
37646
  characters: characters.map((c) => ({
37179
37647
  name: c.name,
@@ -37200,7 +37668,7 @@ function registerLibraryTools(server, client2) {
37200
37668
  if (!existed) {
37201
37669
  throw new McpToolError(`No saved character "${args.name}". List what exists with gemini_list_characters.`);
37202
37670
  }
37203
- return textResult({ deleted: "character", name: args.name });
37671
+ return minifiedResult({ deleted: "character", name: args.name });
37204
37672
  }
37205
37673
  );
37206
37674
  server.registerTool(
@@ -37222,7 +37690,7 @@ function registerLibraryTools(server, client2) {
37222
37690
  () => resolveLibraryImage(client2, args, false)
37223
37691
  );
37224
37692
  const record2 = await library.saveStyle({ name: args.name, promptFragment: args.prompt_fragment, image });
37225
- return textResult({
37693
+ return minifiedResult({
37226
37694
  saved: "style",
37227
37695
  name: record2.name,
37228
37696
  prompt_fragment: record2.prompt_fragment,
@@ -37242,7 +37710,7 @@ function registerLibraryTools(server, client2) {
37242
37710
  },
37243
37711
  async () => {
37244
37712
  const styles = await library.listStyles();
37245
- return textResult({
37713
+ return minifiedResult({
37246
37714
  count: styles.length,
37247
37715
  styles: styles.map((s) => ({
37248
37716
  name: s.name,
@@ -37269,7 +37737,7 @@ function registerLibraryTools(server, client2) {
37269
37737
  if (!existed) {
37270
37738
  throw new McpToolError(`No saved style "${args.name}". List what exists with gemini_list_styles.`);
37271
37739
  }
37272
- return textResult({ deleted: "style", name: args.name });
37740
+ return minifiedResult({ deleted: "style", name: args.name });
37273
37741
  }
37274
37742
  );
37275
37743
  }
@@ -37278,6 +37746,7 @@ function registerLibraryTools(server, client2) {
37278
37746
  var reporting = (register) => (server, deps) => register(surfaceToolErrors(server), deps);
37279
37747
  var TOOL_REGISTRARS = [
37280
37748
  registerModelTools,
37749
+ registerHealthcheckTools,
37281
37750
  registerGenerateTools,
37282
37751
  registerSetTools,
37283
37752
  registerInteractTools,