sql-preview 0.6.2 → 0.6.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/Changelog.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.6.3] - 2026-06-03
6
+
7
+ ### Added
8
+
9
+ - Added an MCP-accessible credential request flow that returns a short-lived local browser form so agents can ask users to store connection passwords without putting secrets in chat transcripts.
10
+ - Added local interactive Snowflake Browser SSO support for MCP/daemon connection tests, including analyst-style `user` and `authenticator=externalbrowser` aliases.
11
+
12
+ ### Fixed
13
+
14
+ - Fixed unconfigured VS Code workspaces showing a phantom built-in `Workspace Trino` connection beside saved Snowflake profiles.
15
+
16
+ ### Changed
17
+
18
+ - Simplified the Snowflake connection form by moving token caching and warehouse/database/schema/role defaults into optional settings, with SSO token caching enabled by default.
19
+
5
20
  ## [0.6.2] - 2026-06-03
6
21
 
7
22
  ### Added
package/dist/mcp-app.html CHANGED
@@ -74174,6 +74174,7 @@ const DynamicForm = ({
74174
74174
  submitFeedback
74175
74175
  }) => {
74176
74176
  const [formData, setFormData] = reactExports.useState({});
74177
+ const [isAdvancedOpen, setIsAdvancedOpen] = reactExports.useState(false);
74177
74178
  const lastResetKey = reactExports.useRef(void 0);
74178
74179
  const resetKey = reactExports.useMemo(
74179
74180
  () => JSON.stringify({
@@ -74239,12 +74240,104 @@ const DynamicForm = ({
74239
74240
  onTest(visibleFormData());
74240
74241
  }
74241
74242
  };
74243
+ const hasMeaningfulInitialValue = (key) => {
74244
+ const value = initialData[key];
74245
+ return value !== void 0 && value !== null && value !== "" && value !== false;
74246
+ };
74247
+ const advancedInitiallyOpen = Object.entries(schema.properties || {}).some(
74248
+ ([key, prop]) => {
74249
+ var _a3;
74250
+ return ((_a3 = prop.ui) == null ? void 0 : _a3.advanced) && hasMeaningfulInitialValue(key);
74251
+ }
74252
+ );
74253
+ reactExports.useEffect(() => {
74254
+ setIsAdvancedOpen(advancedInitiallyOpen);
74255
+ }, [advancedInitiallyOpen, resetKey]);
74242
74256
  const fieldClass = (key, baseClass) => {
74243
74257
  var _a3, _b2;
74244
74258
  const normalizedKey = key.replace(/[^a-z0-9_-]/gi, "-").toLowerCase();
74245
74259
  const fullWidth = ((_b2 = (_a3 = schema.properties[key]) == null ? void 0 : _a3.ui) == null ? void 0 : _b2.fullWidth) ? " sp-conn-form-field-full" : "";
74246
74260
  return `${baseClass} sp-conn-form-field sp-conn-form-field-${normalizedKey}${fullWidth}`;
74247
74261
  };
74262
+ const renderPropertyField = ([key, prop]) => {
74263
+ var _a3;
74264
+ const isRequired = (_a3 = schema.required) == null ? void 0 : _a3.includes(key);
74265
+ const value = formData[key];
74266
+ const fieldId = `form-${key}`;
74267
+ const field = (() => {
74268
+ var _a4;
74269
+ if (prop.type === "boolean") {
74270
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: fieldClass(key, "sp-conn-form-check-row"), children: [
74271
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
74272
+ "input",
74273
+ {
74274
+ type: "checkbox",
74275
+ id: fieldId,
74276
+ checked: !!value,
74277
+ onChange: (e2) => handleChange(key, e2.target.checked)
74278
+ }
74279
+ ),
74280
+ /* @__PURE__ */ jsxRuntimeExports.jsx("label", { htmlFor: fieldId, className: "sp-conn-form-label", style: { marginBottom: 0 }, children: prop.title || key }),
74281
+ prop.description && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-form-hint", children: prop.description })
74282
+ ] });
74283
+ }
74284
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: fieldClass(key, "sp-conn-form-group"), children: [
74285
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { htmlFor: fieldId, className: "sp-conn-form-label", children: [
74286
+ prop.title || key,
74287
+ isRequired && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "required", children: "*" })
74288
+ ] }),
74289
+ prop.description && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-form-hint", children: prop.description }),
74290
+ Array.isArray(prop.enum) ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74291
+ "select",
74292
+ {
74293
+ id: fieldId,
74294
+ required: isRequired,
74295
+ className: "sp-conn-form-input",
74296
+ value: value || "",
74297
+ onChange: (e2) => handleChange(key, e2.target.value),
74298
+ children: prop.enum.map((option, index2) => {
74299
+ var _a5;
74300
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: option, children: ((_a5 = prop.enumNames) == null ? void 0 : _a5[index2]) ?? option }, option);
74301
+ })
74302
+ }
74303
+ ) : prop.type === "number" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74304
+ "input",
74305
+ {
74306
+ id: fieldId,
74307
+ type: "number",
74308
+ required: isRequired,
74309
+ className: "sp-conn-form-input",
74310
+ value: value !== void 0 ? String(value) : "",
74311
+ onChange: (e2) => handleChange(key, e2.target.value !== "" ? Number(e2.target.value) : void 0)
74312
+ }
74313
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
74314
+ "input",
74315
+ {
74316
+ id: fieldId,
74317
+ type: ((_a4 = prop.ui) == null ? void 0 : _a4.widget) === "password" ? "password" : "text",
74318
+ required: isRequired,
74319
+ className: "sp-conn-form-input",
74320
+ value: value || "",
74321
+ onChange: (e2) => handleChange(key, e2.target.value)
74322
+ }
74323
+ )
74324
+ ] });
74325
+ })();
74326
+ const afterField = renderAfterField == null ? void 0 : renderAfterField(key);
74327
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(React$2.Fragment, { children: [
74328
+ field,
74329
+ afterField
74330
+ ] }, key);
74331
+ };
74332
+ const visibleEntries = visiblePropertyEntries();
74333
+ const primaryEntries = visibleEntries.filter(([, prop]) => {
74334
+ var _a3;
74335
+ return !((_a3 = prop.ui) == null ? void 0 : _a3.advanced);
74336
+ });
74337
+ const advancedEntries = visibleEntries.filter(([, prop]) => {
74338
+ var _a3;
74339
+ return (_a3 = prop.ui) == null ? void 0 : _a3.advanced;
74340
+ });
74248
74341
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("form", { onSubmit: handleSubmit, className: "sp-conn-form", role: "form", children: [
74249
74342
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-form-fields", children: [
74250
74343
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: fieldClass("name", "sp-conn-form-group"), children: [
@@ -74264,84 +74357,20 @@ const DynamicForm = ({
74264
74357
  }
74265
74358
  )
74266
74359
  ] }),
74267
- visiblePropertyEntries().map(([key, prop]) => {
74268
- var _a3;
74269
- const isRequired = (_a3 = schema.required) == null ? void 0 : _a3.includes(key);
74270
- const value = formData[key];
74271
- const fieldId = `form-${key}`;
74272
- const field = (() => {
74273
- var _a4;
74274
- if (prop.type === "boolean") {
74275
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: fieldClass(key, "sp-conn-form-check-row"), children: [
74276
- /* @__PURE__ */ jsxRuntimeExports.jsx(
74277
- "input",
74278
- {
74279
- type: "checkbox",
74280
- id: fieldId,
74281
- checked: !!value,
74282
- onChange: (e2) => handleChange(key, e2.target.checked)
74283
- }
74284
- ),
74285
- /* @__PURE__ */ jsxRuntimeExports.jsx(
74286
- "label",
74287
- {
74288
- htmlFor: fieldId,
74289
- className: "sp-conn-form-label",
74290
- style: { marginBottom: 0 },
74291
- children: prop.title || key
74292
- }
74293
- ),
74294
- prop.description && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-form-hint", children: prop.description })
74295
- ] });
74296
- }
74297
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: fieldClass(key, "sp-conn-form-group"), children: [
74298
- /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { htmlFor: fieldId, className: "sp-conn-form-label", children: [
74299
- prop.title || key,
74300
- isRequired && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "required", children: "*" })
74301
- ] }),
74302
- prop.description && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-form-hint", children: prop.description }),
74303
- Array.isArray(prop.enum) ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74304
- "select",
74305
- {
74306
- id: fieldId,
74307
- required: isRequired,
74308
- className: "sp-conn-form-input",
74309
- value: value || "",
74310
- onChange: (e2) => handleChange(key, e2.target.value),
74311
- children: prop.enum.map((option, index2) => {
74312
- var _a5;
74313
- return /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: option, children: ((_a5 = prop.enumNames) == null ? void 0 : _a5[index2]) ?? option }, option);
74314
- })
74315
- }
74316
- ) : prop.type === "number" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74317
- "input",
74318
- {
74319
- id: fieldId,
74320
- type: "number",
74321
- required: isRequired,
74322
- className: "sp-conn-form-input",
74323
- value: value !== void 0 ? String(value) : "",
74324
- onChange: (e2) => handleChange(key, e2.target.value !== "" ? Number(e2.target.value) : void 0)
74325
- }
74326
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx(
74327
- "input",
74328
- {
74329
- id: fieldId,
74330
- type: ((_a4 = prop.ui) == null ? void 0 : _a4.widget) === "password" ? "password" : "text",
74331
- required: isRequired,
74332
- className: "sp-conn-form-input",
74333
- value: value || "",
74334
- onChange: (e2) => handleChange(key, e2.target.value)
74335
- }
74336
- )
74337
- ] });
74338
- })();
74339
- const afterField = renderAfterField == null ? void 0 : renderAfterField(key);
74340
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(React$2.Fragment, { children: [
74341
- field,
74342
- afterField
74343
- ] }, key);
74344
- })
74360
+ primaryEntries.map(renderPropertyField),
74361
+ advancedEntries.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
74362
+ "details",
74363
+ {
74364
+ className: "sp-conn-form-advanced",
74365
+ open: isAdvancedOpen,
74366
+ onToggle: (event) => setIsAdvancedOpen(event.currentTarget.open),
74367
+ children: [
74368
+ /* @__PURE__ */ jsxRuntimeExports.jsx("summary", { className: "sp-conn-form-advanced-summary", children: "Optional settings" }),
74369
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-form-advanced-fields", children: advancedEntries.map(renderPropertyField) })
74370
+ ]
74371
+ },
74372
+ `advanced-${resetKey}`
74373
+ )
74345
74374
  ] }),
74346
74375
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-form-actions", children: [
74347
74376
  actionStatus && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-form-action-status", children: actionStatus }),
@@ -74477,7 +74506,7 @@ function schemaWithoutPasswordField(schema) {
74477
74506
  };
74478
74507
  }
74479
74508
  function schemaForConnectionMode(schema, connectorId, mode) {
74480
- if (connectorId !== "snowflake" || mode === "vscode") {
74509
+ if (connectorId !== "snowflake" || mode !== "headless") {
74481
74510
  return schema;
74482
74511
  }
74483
74512
  const authModeProperty = schema.properties["authMode"];
@@ -98867,6 +98896,31 @@ body.vscode-high-contrast .ag-theme-quartz {
98867
98896
  margin-top: 4px;
98868
98897
  }
98869
98898
 
98899
+ .sp-conn-form-advanced {
98900
+ grid-column: 1 / -1;
98901
+ padding-top: 2px;
98902
+ }
98903
+
98904
+ .sp-conn-form-advanced-summary {
98905
+ cursor: pointer;
98906
+ color: var(--sp-muted-fg);
98907
+ font-size: 12px;
98908
+ font-weight: 600;
98909
+ outline: none;
98910
+ }
98911
+
98912
+ .sp-conn-form-advanced-summary:hover,
98913
+ .sp-conn-form-advanced-summary:focus-visible {
98914
+ color: var(--sp-fg);
98915
+ }
98916
+
98917
+ .sp-conn-form-advanced-fields {
98918
+ display: grid;
98919
+ grid-template-columns: repeat(12, minmax(0, 1fr));
98920
+ gap: 12px 16px;
98921
+ margin-top: 10px;
98922
+ }
98923
+
98870
98924
  .sp-conn-credential-state {
98871
98925
  font-size: 11px;
98872
98926
  color: var(--sp-muted-fg);
@@ -99129,7 +99183,8 @@ body.vscode-high-contrast .ag-theme-quartz {
99129
99183
  grid-template-columns: minmax(0, 1fr);
99130
99184
  }
99131
99185
 
99132
- .sp-conn-form-fields {
99186
+ .sp-conn-form-fields,
99187
+ .sp-conn-form-advanced-fields {
99133
99188
  grid-template-columns: minmax(0, 1fr);
99134
99189
  }
99135
99190
 
@@ -22327,8 +22327,8 @@ var require_escape_html = __commonJS({
22327
22327
  "node_modules/escape-html/index.js"(exports, module2) {
22328
22328
  "use strict";
22329
22329
  var matchHtmlRegExp = /["'&<>]/;
22330
- module2.exports = escapeHtml;
22331
- function escapeHtml(string3) {
22330
+ module2.exports = escapeHtml2;
22331
+ function escapeHtml2(string3) {
22332
22332
  var str = "" + string3;
22333
22333
  var match = matchHtmlRegExp.exec(str);
22334
22334
  if (!match) {
@@ -22453,13 +22453,13 @@ var require_finalhandler = __commonJS({
22453
22453
  "use strict";
22454
22454
  var debug = require_src()("finalhandler");
22455
22455
  var encodeUrl = require_encodeurl();
22456
- var escapeHtml = require_escape_html();
22456
+ var escapeHtml2 = require_escape_html();
22457
22457
  var onFinished = require_on_finished();
22458
22458
  var parseUrl2 = require_parseurl();
22459
22459
  var statuses = require_statuses();
22460
22460
  var isFinished = onFinished.isFinished;
22461
22461
  function createHtmlDocument(message) {
22462
- var body = escapeHtml(message).replaceAll("\n", "<br>").replaceAll(" ", " &nbsp;");
22462
+ var body = escapeHtml2(message).replaceAll("\n", "<br>").replaceAll(" ", " &nbsp;");
22463
22463
  return '<!DOCTYPE html>\n<html lang="en">\n<head>\n<meta charset="utf-8">\n<title>Error</title>\n</head>\n<body>\n<pre>' + body + "</pre>\n</body>\n</html>\n";
22464
22464
  }
22465
22465
  module2.exports = finalhandler;
@@ -22673,14 +22673,14 @@ var require_etag = __commonJS({
22673
22673
  "node_modules/etag/index.js"(exports, module2) {
22674
22674
  "use strict";
22675
22675
  module2.exports = etag;
22676
- var crypto6 = require("crypto");
22676
+ var crypto7 = require("crypto");
22677
22677
  var Stats = require("fs").Stats;
22678
22678
  var toString3 = Object.prototype.toString;
22679
22679
  function entitytag(entity) {
22680
22680
  if (entity.length === 0) {
22681
22681
  return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"';
22682
22682
  }
22683
- var hash = crypto6.createHash("sha1").update(entity, "utf8").digest("base64").substring(0, 27);
22683
+ var hash = crypto7.createHash("sha1").update(entity, "utf8").digest("base64").substring(0, 27);
22684
22684
  var len = typeof entity === "string" ? Buffer.byteLength(entity, "utf8") : entity.length;
22685
22685
  return '"' + len.toString(16) + "-" + hash + '"';
22686
22686
  }
@@ -45141,13 +45141,13 @@ var require_content_disposition = __commonJS({
45141
45141
  // node_modules/cookie-signature/index.js
45142
45142
  var require_cookie_signature = __commonJS({
45143
45143
  "node_modules/cookie-signature/index.js"(exports) {
45144
- var crypto6 = require("crypto");
45144
+ var crypto7 = require("crypto");
45145
45145
  exports.sign = function(val, secret) {
45146
45146
  if ("string" != typeof val)
45147
45147
  throw new TypeError("Cookie value must be provided as a string.");
45148
45148
  if (null == secret)
45149
45149
  throw new TypeError("Secret key must be provided.");
45150
- return val + "." + crypto6.createHmac("sha256", secret).update(val).digest("base64").replace(/\=+$/, "");
45150
+ return val + "." + crypto7.createHmac("sha256", secret).update(val).digest("base64").replace(/\=+$/, "");
45151
45151
  };
45152
45152
  exports.unsign = function(input, secret) {
45153
45153
  if ("string" != typeof input)
@@ -45155,7 +45155,7 @@ var require_cookie_signature = __commonJS({
45155
45155
  if (null == secret)
45156
45156
  throw new TypeError("Secret key must be provided.");
45157
45157
  var tentativeValue = input.slice(0, input.lastIndexOf(".")), expectedInput = exports.sign(tentativeValue, secret), expectedBuffer = Buffer.from(expectedInput), inputBuffer = Buffer.from(input);
45158
- return expectedBuffer.length === inputBuffer.length && crypto6.timingSafeEqual(expectedBuffer, inputBuffer) ? tentativeValue : false;
45158
+ return expectedBuffer.length === inputBuffer.length && crypto7.timingSafeEqual(expectedBuffer, inputBuffer) ? tentativeValue : false;
45159
45159
  };
45160
45160
  }
45161
45161
  });
@@ -54844,7 +54844,7 @@ var require_send = __commonJS({
54844
54844
  var createError = require_http_errors();
54845
54845
  var debug = require_src()("send");
54846
54846
  var encodeUrl = require_encodeurl();
54847
- var escapeHtml = require_escape_html();
54847
+ var escapeHtml2 = require_escape_html();
54848
54848
  var etag = require_etag();
54849
54849
  var fresh = require_fresh();
54850
54850
  var fs11 = require("fs");
@@ -54897,7 +54897,7 @@ var require_send = __commonJS({
54897
54897
  }
54898
54898
  var res = this.res;
54899
54899
  var msg = statuses.message[status] || String(status);
54900
- var doc = createHtmlDocument("Error", escapeHtml(msg));
54900
+ var doc = createHtmlDocument("Error", escapeHtml2(msg));
54901
54901
  clearHeaders(res);
54902
54902
  if (err && err.headers) {
54903
54903
  setHeaders(res, err.headers);
@@ -54997,7 +54997,7 @@ var require_send = __commonJS({
54997
54997
  return;
54998
54998
  }
54999
54999
  var loc = encodeUrl(collapseLeadingSlashes(this.path + "/"));
55000
- var doc = createHtmlDocument("Redirecting", "Redirecting to " + escapeHtml(loc));
55000
+ var doc = createHtmlDocument("Redirecting", "Redirecting to " + escapeHtml2(loc));
55001
55001
  res.statusCode = 301;
55002
55002
  res.setHeader("Content-Type", "text/html; charset=UTF-8");
55003
55003
  res.setHeader("Content-Length", Buffer.byteLength(doc));
@@ -55411,7 +55411,7 @@ var require_response = __commonJS({
55411
55411
  var createError = require_http_errors();
55412
55412
  var deprecate = require_depd()("express");
55413
55413
  var encodeUrl = require_encodeurl();
55414
- var escapeHtml = require_escape_html();
55414
+ var escapeHtml2 = require_escape_html();
55415
55415
  var http4 = require("node:http");
55416
55416
  var onFinished = require_on_finished();
55417
55417
  var mime = require_mime_types2();
@@ -55753,7 +55753,7 @@ var require_response = __commonJS({
55753
55753
  body = statuses.message[status] + ". Redirecting to " + address;
55754
55754
  },
55755
55755
  html: function() {
55756
- var u = escapeHtml(address);
55756
+ var u = escapeHtml2(address);
55757
55757
  body = "<p>" + statuses.message[status] + ". Redirecting to " + u + "</p>";
55758
55758
  },
55759
55759
  default: function() {
@@ -55889,7 +55889,7 @@ var require_serve_static = __commonJS({
55889
55889
  "node_modules/serve-static/index.js"(exports, module2) {
55890
55890
  "use strict";
55891
55891
  var encodeUrl = require_encodeurl();
55892
- var escapeHtml = require_escape_html();
55892
+ var escapeHtml2 = require_escape_html();
55893
55893
  var parseUrl2 = require_parseurl();
55894
55894
  var resolve2 = require("path").resolve;
55895
55895
  var send = require_send();
@@ -55975,7 +55975,7 @@ var require_serve_static = __commonJS({
55975
55975
  originalUrl.path = null;
55976
55976
  originalUrl.pathname = collapseLeadingSlashes(originalUrl.pathname + "/");
55977
55977
  var loc = encodeUrl(url2.format(originalUrl));
55978
- var doc = createHtmlDocument("Redirecting", "Redirecting to " + escapeHtml(loc));
55978
+ var doc = createHtmlDocument("Redirecting", "Redirecting to " + escapeHtml2(loc));
55979
55979
  res.statusCode = 301;
55980
55980
  res.setHeader("Content-Type", "text/html; charset=UTF-8");
55981
55981
  res.setHeader("Content-Length", Buffer.byteLength(doc));
@@ -66555,7 +66555,7 @@ var require_form_data = __commonJS({
66555
66555
  var parseUrl2 = require("url").parse;
66556
66556
  var fs11 = require("fs");
66557
66557
  var Stream = require("stream").Stream;
66558
- var crypto6 = require("crypto");
66558
+ var crypto7 = require("crypto");
66559
66559
  var mime = require_mime_types5();
66560
66560
  var asynckit = require_asynckit();
66561
66561
  var setToStringTag = require_es_set_tostringtag();
@@ -66761,7 +66761,7 @@ var require_form_data = __commonJS({
66761
66761
  return Buffer.concat([dataBuffer, Buffer.from(this._lastBoundary())]);
66762
66762
  };
66763
66763
  FormData3.prototype._generateBoundary = function() {
66764
- this._boundary = "--------------------------" + crypto6.randomBytes(12).toString("hex");
66764
+ this._boundary = "--------------------------" + crypto7.randomBytes(12).toString("hex");
66765
66765
  };
66766
66766
  FormData3.prototype.getLengthSync = function() {
66767
66767
  var knownLength = this._overheadLength + this._valueLength;
@@ -74916,7 +74916,7 @@ var init_src8 = __esm({
74916
74916
  if (!cfg.account) {
74917
74917
  return "account is required";
74918
74918
  }
74919
- if (!cfg.username) {
74919
+ if (!this.resolveUsername(cfg)) {
74920
74920
  return "username is required";
74921
74921
  }
74922
74922
  const authMode = this.resolveAuthMode(cfg);
@@ -74930,14 +74930,20 @@ var init_src8 = __esm({
74930
74930
  }
74931
74931
  // ── Private: build connection options ───────────────────────────────────
74932
74932
  resolveAuthMode(cfg) {
74933
+ if (cfg.authenticator?.trim().toLowerCase() === "externalbrowser") {
74934
+ return "externalbrowser";
74935
+ }
74933
74936
  return cfg.authMode ?? (cfg.privateKeyPath ? "keypair" : "password");
74934
74937
  }
74938
+ resolveUsername(cfg) {
74939
+ return cfg.username || cfg.user;
74940
+ }
74935
74941
  buildConnectionOptions(cfg) {
74936
74942
  const account = normaliseAccount(cfg.account);
74937
74943
  const authMode = this.resolveAuthMode(cfg);
74938
74944
  const opts = {
74939
74945
  account,
74940
- username: cfg.username,
74946
+ username: this.resolveUsername(cfg),
74941
74947
  warehouse: cfg.warehouse,
74942
74948
  database: cfg.database,
74943
74949
  schema: cfg.schema,
@@ -75169,21 +75175,33 @@ var init_descriptor7 = __esm({
75169
75175
  type: "boolean",
75170
75176
  title: "Cache browser SSO token",
75171
75177
  description: "Requests Snowflake driver token caching when the account allows ID-token caching",
75172
- default: false,
75173
- ui: { visibleWhen: { field: "authMode", equals: "externalbrowser" } }
75178
+ default: true,
75179
+ ui: { visibleWhen: { field: "authMode", equals: "externalbrowser" }, advanced: true }
75174
75180
  },
75175
75181
  warehouse: {
75176
75182
  type: "string",
75177
75183
  title: "Warehouse",
75178
- description: "Virtual warehouse to use (optional)"
75184
+ description: "Virtual warehouse to use (optional)",
75185
+ ui: { advanced: true }
75179
75186
  },
75180
75187
  database: {
75181
75188
  type: "string",
75182
75189
  title: "Database",
75183
- description: "Default database (optional)"
75190
+ description: "Default database (optional)",
75191
+ ui: { advanced: true }
75192
+ },
75193
+ schema: {
75194
+ type: "string",
75195
+ title: "Schema",
75196
+ description: "Default schema (optional)",
75197
+ ui: { advanced: true }
75184
75198
  },
75185
- schema: { type: "string", title: "Schema", description: "Default schema (optional)" },
75186
- role: { type: "string", title: "Role", description: "Role to assume (optional)" }
75199
+ role: {
75200
+ type: "string",
75201
+ title: "Role",
75202
+ description: "Role to assume (optional)",
75203
+ ui: { advanced: true }
75204
+ }
75187
75205
  },
75188
75206
  required: ["account", "username"]
75189
75207
  };
@@ -76760,7 +76778,16 @@ function isSnowflakeBrowserSsoProfile(value) {
76760
76778
  return false;
76761
76779
  }
76762
76780
  const profile = value;
76763
- return profile["type"] === "snowflake" && profile["authMode"] === "externalbrowser";
76781
+ return profile["type"] === "snowflake" && (profile["authMode"] === "externalbrowser" || typeof profile["authenticator"] === "string" && profile["authenticator"].toLowerCase() === "externalbrowser");
76782
+ }
76783
+ function normalizeConnectionProfileForSave(profile) {
76784
+ const profileToSave = { ...profile };
76785
+ if (isSnowflakeBrowserSsoProfile(profileToSave)) {
76786
+ profileToSave["password"] = "";
76787
+ delete profileToSave["privateKeyPath"];
76788
+ delete profileToSave["privateKeyPassphrase"];
76789
+ }
76790
+ return profileToSave;
76764
76791
  }
76765
76792
  function stripCommentsAndStrings(sql) {
76766
76793
  let result = "";
@@ -76834,7 +76861,7 @@ function isReadOnlySql(sql) {
76834
76861
  }
76835
76862
  return !WRITE_KEYWORDS.test(normalized);
76836
76863
  }
76837
- var WRITE_KEYWORDS, READ_ONLY_START_KEYWORDS, SNOWFLAKE_BROWSER_SSO_UNSUPPORTED_MESSAGE, DaemonMcpToolManager;
76864
+ var WRITE_KEYWORDS, READ_ONLY_START_KEYWORDS, DaemonMcpToolManager;
76838
76865
  var init_DaemonMcpToolManager = __esm({
76839
76866
  "src/server/DaemonMcpToolManager.ts"() {
76840
76867
  "use strict";
@@ -76844,13 +76871,13 @@ var init_DaemonMcpToolManager = __esm({
76844
76871
  init_querySplitter();
76845
76872
  WRITE_KEYWORDS = /\b(ALTER|CALL|COPY|CREATE|DELETE|DROP|EXEC|EXECUTE|GRANT|INSERT|INSTALL|LOAD|MERGE|REPLACE|REVOKE|SET|TRUNCATE|UPDATE|VACUUM)\b/i;
76846
76873
  READ_ONLY_START_KEYWORDS = /* @__PURE__ */ new Set(["SELECT", "SHOW", "DESCRIBE", "EXPLAIN", "WITH"]);
76847
- SNOWFLAKE_BROWSER_SSO_UNSUPPORTED_MESSAGE = "Snowflake browser SSO is only supported from the local VS Code extension because it requires opening a browser on the user's machine.";
76848
76874
  DaemonMcpToolManager = class {
76849
76875
  constructor(sessionManager, queryExecutor, connectionManager, connectorRegistry, queryOperationRunner, options = {}) {
76850
76876
  this.sessionManager = sessionManager;
76851
76877
  this.queryExecutor = queryExecutor;
76852
76878
  this.connectionManager = connectionManager;
76853
76879
  this.connectorRegistry = connectorRegistry;
76880
+ this.options = options;
76854
76881
  this.safeMode = options.safeMode ?? true;
76855
76882
  this.queryOperationRunner = queryOperationRunner ?? new QueryOperationRunner(sessionManager, queryExecutor);
76856
76883
  }
@@ -76973,6 +77000,20 @@ var init_DaemonMcpToolManager = __esm({
76973
77000
  required: ["connectionProfile"]
76974
77001
  }
76975
77002
  },
77003
+ {
77004
+ name: "request_connection_credentials",
77005
+ description: "Create a short-lived local browser form where the user can enter credentials for a saved connection without exposing the secret in the MCP transcript. Share only the returned URL with the user; never ask them to paste credentials into chat.",
77006
+ inputSchema: {
77007
+ type: "object",
77008
+ properties: {
77009
+ connectionId: {
77010
+ type: "string",
77011
+ description: "Connection ID that should receive the safely submitted password."
77012
+ }
77013
+ },
77014
+ required: ["connectionId"]
77015
+ }
77016
+ },
76976
77017
  {
76977
77018
  name: "test_connection",
76978
77019
  description: "Test connectivity for a specific connection profile.",
@@ -77091,6 +77132,8 @@ var init_DaemonMcpToolManager = __esm({
77091
77132
  return this.handleListConnections();
77092
77133
  case "save_connection":
77093
77134
  return this.handleSaveConnection(args);
77135
+ case "request_connection_credentials":
77136
+ return this.handleRequestConnectionCredentials(args);
77094
77137
  case "test_connection":
77095
77138
  return this.handleTestConnection(args);
77096
77139
  case "delete_connection":
@@ -77262,14 +77305,45 @@ var init_DaemonMcpToolManager = __esm({
77262
77305
  if (!profile || !profile.id || !profile.name || !profile.type) {
77263
77306
  throw new Error("Invalid connection profile: missing id, name, or type");
77264
77307
  }
77265
- if (isSnowflakeBrowserSsoProfile(profile)) {
77266
- throw new Error(SNOWFLAKE_BROWSER_SSO_UNSUPPORTED_MESSAGE);
77267
- }
77268
- await this.connectionManager.saveProfile(profile);
77308
+ const profileToSave = normalizeConnectionProfileForSave(
77309
+ profile
77310
+ );
77311
+ await this.connectionManager.saveProfile(profileToSave);
77269
77312
  return {
77270
77313
  content: [{ type: "text", text: `Connection '${profile.id}' saved.` }]
77271
77314
  };
77272
77315
  }
77316
+ async handleRequestConnectionCredentials(args) {
77317
+ const service = this.options.credentialRequestService;
77318
+ if (!service) {
77319
+ throw new Error("Credential request UI is not available for this SQL Preview daemon.");
77320
+ }
77321
+ const connectionId = args?.connectionId;
77322
+ if (!connectionId) {
77323
+ throw new Error("connectionId is required");
77324
+ }
77325
+ const request = await service.create(connectionId);
77326
+ return {
77327
+ structuredContent: {
77328
+ connectionId: request.connectionId,
77329
+ connectionName: request.connectionName,
77330
+ url: request.url,
77331
+ expiresAt: new Date(request.expiresAt).toISOString()
77332
+ },
77333
+ content: [
77334
+ {
77335
+ type: "text",
77336
+ text: `Open this one-time SQL Preview credential form for '${request.connectionName}' and enter the password there; do not paste the password into chat.
77337
+
77338
+ ${request.url}
77339
+
77340
+ This link expires at ${new Date(
77341
+ request.expiresAt
77342
+ ).toISOString()}.`
77343
+ }
77344
+ ]
77345
+ };
77346
+ }
77273
77347
  async handleTestConnection(args) {
77274
77348
  const typedArgs = args;
77275
77349
  let typeToTest;
@@ -77295,9 +77369,6 @@ var init_DaemonMcpToolManager = __esm({
77295
77369
  } else {
77296
77370
  throw new Error("Must provide either connectionId or (type, connectionProfile)");
77297
77371
  }
77298
- if (typeToTest === "snowflake" && isSnowflakeBrowserSsoProfile(configToTest)) {
77299
- throw new Error(SNOWFLAKE_BROWSER_SSO_UNSUPPORTED_MESSAGE);
77300
- }
77301
77372
  const result = await this.queryExecutor.testConnection(
77302
77373
  typeToTest,
77303
77374
  configToTest,
@@ -77873,6 +77944,79 @@ var init_DaemonQueryExecutor = __esm({
77873
77944
  }
77874
77945
  });
77875
77946
 
77947
+ // src/server/CredentialRequestService.ts
77948
+ var import_crypto3, DEFAULT_TTL_MS, CredentialRequestService;
77949
+ var init_CredentialRequestService = __esm({
77950
+ "src/server/CredentialRequestService.ts"() {
77951
+ "use strict";
77952
+ import_crypto3 = __toESM(require("crypto"));
77953
+ DEFAULT_TTL_MS = 10 * 60 * 1e3;
77954
+ CredentialRequestService = class {
77955
+ constructor(connectionManager, baseUrl, ttlMs = DEFAULT_TTL_MS) {
77956
+ this.connectionManager = connectionManager;
77957
+ this.baseUrl = baseUrl;
77958
+ this.ttlMs = ttlMs;
77959
+ this.requests = /* @__PURE__ */ new Map();
77960
+ }
77961
+ async create(connectionId) {
77962
+ this.pruneExpired();
77963
+ const profile = await this.connectionManager.getProfile(connectionId);
77964
+ if (!profile) {
77965
+ throw new Error(`Connection profile '${connectionId}' not found`);
77966
+ }
77967
+ const id = import_crypto3.default.randomUUID();
77968
+ const token = import_crypto3.default.randomBytes(24).toString("base64url");
77969
+ const request = {
77970
+ id,
77971
+ token,
77972
+ connectionId,
77973
+ connectionName: profile.name,
77974
+ expiresAt: Date.now() + this.ttlMs,
77975
+ url: `${this.baseUrl}/credential-requests/${encodeURIComponent(id)}?token=${encodeURIComponent(
77976
+ token
77977
+ )}`
77978
+ };
77979
+ this.requests.set(id, request);
77980
+ return request;
77981
+ }
77982
+ get(id, token) {
77983
+ this.pruneExpired();
77984
+ const request = this.requests.get(id);
77985
+ if (!request || request.token !== token) {
77986
+ return void 0;
77987
+ }
77988
+ return request;
77989
+ }
77990
+ async fulfill(id, token, password) {
77991
+ const request = this.get(id, token);
77992
+ if (!request) {
77993
+ throw new Error("Credential request is invalid or expired.");
77994
+ }
77995
+ if (!password) {
77996
+ throw new Error("Password is required.");
77997
+ }
77998
+ const profile = await this.connectionManager.getProfile(request.connectionId);
77999
+ if (!profile) {
78000
+ throw new Error(`Connection profile '${request.connectionId}' not found`);
78001
+ }
78002
+ await this.connectionManager.saveProfile({
78003
+ ...profile,
78004
+ password
78005
+ });
78006
+ this.requests.delete(id);
78007
+ return request;
78008
+ }
78009
+ pruneExpired(now = Date.now()) {
78010
+ for (const [id, request] of this.requests.entries()) {
78011
+ if (request.expiresAt <= now) {
78012
+ this.requests.delete(id);
78013
+ }
78014
+ }
78015
+ }
78016
+ };
78017
+ }
78018
+ });
78019
+
77876
78020
  // src/server/SessionManager.ts
77877
78021
  var import_events2, SessionManager;
77878
78022
  var init_SessionManager = __esm({
@@ -78070,6 +78214,42 @@ function registerDaemonHttpRoutes(context2, mcpHttpSurface) {
78070
78214
  configPath: context2.resolvedConfig.configPath
78071
78215
  });
78072
78216
  });
78217
+ app.get("/credential-requests/:id", (req, res) => {
78218
+ setCredentialPageHeaders(res);
78219
+ const id = req.params.id;
78220
+ const token = typeof req.query["token"] === "string" ? req.query["token"] : "";
78221
+ const request = id ? context2.credentialRequestService.get(id, token) : void 0;
78222
+ if (!request) {
78223
+ res.status(404).send(renderCredentialPage({ error: "This credential request is invalid or expired." }));
78224
+ return;
78225
+ }
78226
+ res.send(renderCredentialPage({ request }));
78227
+ });
78228
+ app.post(
78229
+ "/credential-requests/:id",
78230
+ import_express.default.urlencoded({ extended: false }),
78231
+ async (req, res) => {
78232
+ setCredentialPageHeaders(res);
78233
+ const id = req.params.id;
78234
+ const body = req.body;
78235
+ const token = typeof body.token === "string" ? body.token : "";
78236
+ const password = typeof body.password === "string" ? body.password : "";
78237
+ try {
78238
+ if (!id) {
78239
+ throw new Error("Credential request is invalid or expired.");
78240
+ }
78241
+ const request = await context2.credentialRequestService.fulfill(id, token, password);
78242
+ res.send(
78243
+ renderCredentialPage({
78244
+ success: `Password saved for '${request.connectionName}'. You can close this tab and ask your tool to retry the query.`
78245
+ })
78246
+ );
78247
+ } catch (err) {
78248
+ logger.warn("[Daemon] Credential request failed:", err);
78249
+ res.status(400).send(renderCredentialPage({ error: err instanceof Error ? err.message : String(err) }));
78250
+ }
78251
+ }
78252
+ );
78073
78253
  app.get("/embedded-app", async (_req, res) => {
78074
78254
  serveHtmlFile(res, "mcp-app.html", 'UI bundle not found. Please run "npm run build" first.');
78075
78255
  });
@@ -78253,7 +78433,7 @@ async function handleQueryRoute(context2, req, res, options) {
78253
78433
  res.status(400).json({ error: options.missingQueryMessage });
78254
78434
  return;
78255
78435
  }
78256
- const sessionId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : `${options.sessionPrefix}-${import_crypto3.default.randomUUID()}`;
78436
+ const sessionId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : `${options.sessionPrefix}-${import_crypto4.default.randomUUID()}`;
78257
78437
  const controller = new AbortController();
78258
78438
  const cleanupDisconnectAbort = attachAbortOnHttpDisconnect(
78259
78439
  req,
@@ -78332,11 +78512,77 @@ function findDistFile(fileName) {
78332
78512
  ];
78333
78513
  return candidates.find((candidate) => fs6.existsSync(candidate)) || candidates[0] || fileName;
78334
78514
  }
78335
- var import_crypto3, import_express, fs6, path4;
78515
+ function setCredentialPageHeaders(res) {
78516
+ res.setHeader("Cache-Control", "no-store");
78517
+ res.setHeader("Referrer-Policy", "no-referrer");
78518
+ res.setHeader("X-Content-Type-Options", "nosniff");
78519
+ }
78520
+ function renderCredentialPage(input) {
78521
+ const title = "SQL Preview Credential Request";
78522
+ const message = input.success || input.error || "";
78523
+ const escapedMessage = escapeHtml(message);
78524
+ const request = input.request;
78525
+ const form = request ? `<p>Enter the password for <strong>${escapeHtml(request.connectionName)}</strong>.</p>
78526
+ <p class="hint">The password is sent directly to the local SQL Preview daemon and is not shown in the MCP/chat transcript.</p>
78527
+ <form method="post" autocomplete="off">
78528
+ <input type="hidden" name="token" value="${escapeHtml(request.token)}" />
78529
+ <label for="password">Password</label>
78530
+ <input id="password" name="password" type="password" autocomplete="current-password" autofocus required />
78531
+ <button type="submit">Save password</button>
78532
+ </form>
78533
+ <p class="hint">This request expires at ${escapeHtml(new Date(request.expiresAt).toLocaleString())}.</p>` : "";
78534
+ return `<!doctype html>
78535
+ <html lang="en">
78536
+ <head>
78537
+ <meta charset="utf-8" />
78538
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
78539
+ <title>${title}</title>
78540
+ <style>
78541
+ :root { color-scheme: light dark; font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
78542
+ body { margin: 0; min-height: 100vh; display: grid; place-items: center; background: Canvas; color: CanvasText; }
78543
+ main { width: min(92vw, 32rem); padding: 2rem; border: 1px solid color-mix(in srgb, CanvasText 18%, transparent); border-radius: 12px; box-shadow: 0 12px 40px color-mix(in srgb, CanvasText 12%, transparent); }
78544
+ h1 { margin-top: 0; font-size: 1.35rem; }
78545
+ label { display: block; margin-bottom: 0.4rem; font-weight: 600; }
78546
+ input[type="password"] { box-sizing: border-box; width: 100%; padding: 0.75rem; border: 1px solid color-mix(in srgb, CanvasText 30%, transparent); border-radius: 8px; font: inherit; }
78547
+ button { margin-top: 1rem; padding: 0.7rem 1rem; border: 0; border-radius: 8px; background: #2563eb; color: white; font: inherit; font-weight: 700; cursor: pointer; }
78548
+ .hint { color: color-mix(in srgb, CanvasText 72%, transparent); }
78549
+ .success { color: #15803d; }
78550
+ .error { color: #b91c1c; }
78551
+ </style>
78552
+ </head>
78553
+ <body>
78554
+ <main>
78555
+ <h1>${title}</h1>
78556
+ ${input.success ? `<p class="success">${escapedMessage}</p>` : ""}
78557
+ ${input.error ? `<p class="error">${escapedMessage}</p>` : ""}
78558
+ ${form}
78559
+ </main>
78560
+ </body>
78561
+ </html>`;
78562
+ }
78563
+ function escapeHtml(value) {
78564
+ return value.replace(/[&<>'"]/g, (char) => {
78565
+ switch (char) {
78566
+ case "&":
78567
+ return "&amp;";
78568
+ case "<":
78569
+ return "&lt;";
78570
+ case ">":
78571
+ return "&gt;";
78572
+ case "'":
78573
+ return "&#39;";
78574
+ case '"':
78575
+ return "&quot;";
78576
+ default:
78577
+ return char;
78578
+ }
78579
+ });
78580
+ }
78581
+ var import_crypto4, import_express, fs6, path4;
78336
78582
  var init_DaemonHttpRoutes = __esm({
78337
78583
  "src/server/surfaces/DaemonHttpRoutes.ts"() {
78338
78584
  "use strict";
78339
- import_crypto3 = __toESM(require("crypto"));
78585
+ import_crypto4 = __toESM(require("crypto"));
78340
78586
  import_express = __toESM(require_express2());
78341
78587
  fs6 = __toESM(require("fs"));
78342
78588
  path4 = __toESM(require("path"));
@@ -78391,13 +78637,13 @@ function writeFromReadableStream(stream4, writable) {
78391
78637
  }
78392
78638
  return writeFromReadableStreamDefaultReader(stream4.getReader(), writable);
78393
78639
  }
78394
- var import_http22, import_http23, import_stream5, import_crypto4, RequestError, toRequestError, GlobalRequest, Request, newHeadersFromIncoming, wrapBodyStream, newRequestFromIncoming, getRequestCache, requestCache, incomingKey, urlKey, headersKey, abortControllerKey, getAbortController, requestPrototype, newRequest, responseCache, getResponseCache, cacheKey, GlobalResponse, Response2, buildOutgoingHttpHeaders, X_ALREADY_SENT, outgoingEnded, incomingDraining, DRAIN_TIMEOUT_MS, MAX_DRAIN_BYTES, drainIncoming, handleRequestError, handleFetchError, handleResponseError, flushHeaders, responseViaCache, isPromise, responseViaResponseObject, getRequestListener;
78640
+ var import_http22, import_http23, import_stream5, import_crypto5, RequestError, toRequestError, GlobalRequest, Request, newHeadersFromIncoming, wrapBodyStream, newRequestFromIncoming, getRequestCache, requestCache, incomingKey, urlKey, headersKey, abortControllerKey, getAbortController, requestPrototype, newRequest, responseCache, getResponseCache, cacheKey, GlobalResponse, Response2, buildOutgoingHttpHeaders, X_ALREADY_SENT, outgoingEnded, incomingDraining, DRAIN_TIMEOUT_MS, MAX_DRAIN_BYTES, drainIncoming, handleRequestError, handleFetchError, handleResponseError, flushHeaders, responseViaCache, isPromise, responseViaResponseObject, getRequestListener;
78395
78641
  var init_dist = __esm({
78396
78642
  "node_modules/@hono/node-server/dist/index.mjs"() {
78397
78643
  import_http22 = require("http2");
78398
78644
  import_http23 = require("http2");
78399
78645
  import_stream5 = require("stream");
78400
- import_crypto4 = __toESM(require("crypto"), 1);
78646
+ import_crypto5 = __toESM(require("crypto"), 1);
78401
78647
  RequestError = class extends Error {
78402
78648
  constructor(message, options) {
78403
78649
  super(message, options);
@@ -78691,7 +78937,7 @@ var init_dist = __esm({
78691
78937
  };
78692
78938
  X_ALREADY_SENT = "x-hono-already-sent";
78693
78939
  if (typeof global.crypto === "undefined") {
78694
- global.crypto = import_crypto4.default;
78940
+ global.crypto = import_crypto5.default;
78695
78941
  }
78696
78942
  outgoingEnded = Symbol("outgoingEnded");
78697
78943
  incomingDraining = Symbol("incomingDraining");
@@ -126766,11 +127012,11 @@ var init_McpServerFactory = __esm({
126766
127012
  });
126767
127013
 
126768
127014
  // src/server/surfaces/DaemonMcpHttpSurface.ts
126769
- var import_crypto5, DaemonMcpHttpSurface;
127015
+ var import_crypto6, DaemonMcpHttpSurface;
126770
127016
  var init_DaemonMcpHttpSurface = __esm({
126771
127017
  "src/server/surfaces/DaemonMcpHttpSurface.ts"() {
126772
127018
  "use strict";
126773
- import_crypto5 = __toESM(require("crypto"));
127019
+ import_crypto6 = __toESM(require("crypto"));
126774
127020
  init_streamableHttp();
126775
127021
  init_ConsoleLogger();
126776
127022
  init_logRedaction();
@@ -126850,7 +127096,7 @@ var init_DaemonMcpHttpSurface = __esm({
126850
127096
  if (typeof headerSessionId === "string" && headerSessionId.length > 0) {
126851
127097
  return headerSessionId;
126852
127098
  }
126853
- return `session-${import_crypto5.default.randomUUID()}`;
127099
+ return `session-${import_crypto6.default.randomUUID()}`;
126854
127100
  }
126855
127101
  async getOrCreateSession(sessionId) {
126856
127102
  const existingSession = this.sessions.get(sessionId);
@@ -131212,7 +131458,8 @@ var init_DaemonSurfaceManager = __esm({
131212
131458
  refreshActivity: this.options.refreshActivity,
131213
131459
  resolvedConfig: this.options.resolvedConfig,
131214
131460
  sessionManager: this.options.sessionManager,
131215
- getSurfaceStatus: () => this.getStatus()
131461
+ getSurfaceStatus: () => this.getStatus(),
131462
+ credentialRequestService: this.options.credentialRequestService
131216
131463
  },
131217
131464
  this.mcpHttpSurface
131218
131465
  );
@@ -131311,6 +131558,7 @@ var init_Daemon = __esm({
131311
131558
  init_DaemonMcpToolManager();
131312
131559
  init_DaemonQueryExecutor();
131313
131560
  init_QueryOperationRunner();
131561
+ init_CredentialRequestService();
131314
131562
  init_SessionManager();
131315
131563
  init_DaemonSurfaceManager();
131316
131564
  Daemon = class {
@@ -131347,13 +131595,20 @@ var init_Daemon = __esm({
131347
131595
  this.config.query
131348
131596
  );
131349
131597
  this.queryOperationRunner = new QueryOperationRunner(this.sessionManager, this.queryExecutor);
131598
+ this.credentialRequestService = new CredentialRequestService(
131599
+ this.connectionManager,
131600
+ this.getHttpBaseUrl()
131601
+ );
131350
131602
  this.toolManager = new DaemonMcpToolManager(
131351
131603
  this.sessionManager,
131352
131604
  this.queryExecutor,
131353
131605
  this.connectionManager,
131354
131606
  this.connectorRegistry,
131355
131607
  this.queryOperationRunner,
131356
- { safeMode: this.config.mcp.safeMode }
131608
+ {
131609
+ safeMode: this.config.mcp.safeMode,
131610
+ credentialRequestService: this.credentialRequestService
131611
+ }
131357
131612
  );
131358
131613
  this.surfaceManager = new DaemonSurfaceManager({
131359
131614
  app: this.app,
@@ -131366,7 +131621,8 @@ var init_Daemon = __esm({
131366
131621
  resolvedConfig: this.resolvedConfig,
131367
131622
  sessionManager: this.sessionManager,
131368
131623
  socketPath: this.SOCKET_PATH,
131369
- toolManager: this.toolManager
131624
+ toolManager: this.toolManager,
131625
+ credentialRequestService: this.credentialRequestService
131370
131626
  });
131371
131627
  this.surfaceManager.registerHttpRoutes();
131372
131628
  this.setupLifecycle();
@@ -131375,6 +131631,10 @@ var init_Daemon = __esm({
131375
131631
  (e) => logger.warn("[Daemon] Failed to create built-in connections:", e)
131376
131632
  );
131377
131633
  }
131634
+ getHttpBaseUrl() {
131635
+ const host = ["0.0.0.0", "::", ""].includes(this.config.server.host) ? "127.0.0.1" : this.config.server.host;
131636
+ return `http://${host}:${this.HTTP_PORT}`;
131637
+ }
131378
131638
  /**
131379
131639
  * Auto-provisions built-in connections that should always be available.
131380
131640
  * DuckDB :memory: allows CSV/Parquet queries without any manual setup.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sql-preview",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "mcpName": "io.github.fadnavismehul/sql-preview",
5
5
  "description": "Standalone SQL Preview MCP database server for VS Code, Claude Desktop, Cursor, and other MCP clients.",
6
6
  "main": "out/server/standalone.js",
package/server.json CHANGED
@@ -8,14 +8,14 @@
8
8
  "source": "github",
9
9
  "id": "1025027765"
10
10
  },
11
- "version": "0.6.2",
11
+ "version": "0.6.3",
12
12
  "websiteUrl": "https://github.com/fadnavismehul/sql-preview#readme",
13
13
  "packages": [
14
14
  {
15
15
  "registryType": "npm",
16
16
  "registryBaseUrl": "https://registry.npmjs.org",
17
17
  "identifier": "sql-preview",
18
- "version": "0.6.2",
18
+ "version": "0.6.3",
19
19
  "runtimeHint": "npx",
20
20
  "runtimeArguments": [
21
21
  {