@solarisdk/mcp 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/browser.js CHANGED
@@ -294,6 +294,76 @@ export function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
294
294
  });
295
295
  },
296
296
  },
297
+ solari_browser_autologin_status: {
298
+ description: "Check whether this account can sign in to websites automatically, and get a direct " +
299
+ "setup link if it cannot.\n" +
300
+ "Call this when a task will clearly need a login, BEFORE you start — if nothing is set " +
301
+ "up you can tell the user once, up front, with a link, instead of interrupting them " +
302
+ "mid-run. Also worth calling if a login keeps needing a human.\n" +
303
+ "Returns the connected password managers, the sites already configured, and `setupUrl`. " +
304
+ "If `configured` is false, SHOW setupUrl TO THE USER: it opens the page where they " +
305
+ "connect a password manager. You cannot do that step for them — it needs a credential " +
306
+ "that must never pass through you — but the link removes all the guesswork.",
307
+ inputSchema: {},
308
+ handler: async () => {
309
+ const res = await api(cfg, "GET", "/vault/status");
310
+ if (res.status === 501) {
311
+ return text({
312
+ configured: false,
313
+ available: false,
314
+ note: "Automatic sign-in is not available on this deployment.",
315
+ });
316
+ }
317
+ if (res.status !== 200)
318
+ await apiError(res, "auto-login status");
319
+ const d = (await res.json());
320
+ const managers = d.managers ?? [];
321
+ const sites = d.sites ?? [];
322
+ return text({
323
+ configured: managers.length > 0,
324
+ available: true,
325
+ managers: managers.map((m) => ({ name: m.name, provider: m.provider, vaults: m.vaults })),
326
+ sites,
327
+ setupUrl: d.setupUrl ?? null,
328
+ next: managers.length === 0
329
+ ? "No password manager is connected. Show setupUrl to the user — it takes them " +
330
+ "straight to the page where they connect one, after which logins happen with no " +
331
+ "human involved."
332
+ : sites.length === 0
333
+ ? "A password manager is connected but no sites use it yet. Add one with " +
334
+ "solari_browser_autologin_site, or the user can do it at setupUrl."
335
+ : "Automatic sign-in is set up. Sessions will log in to these sites on their own.",
336
+ });
337
+ },
338
+ },
339
+ solari_browser_autologin_site: {
340
+ description: "Tell Solari to sign in to a site automatically using a connected password manager.\n" +
341
+ "`domain` is the site, e.g. 'github.com'. `manager` is the NAME of a connected password " +
342
+ "manager (see solari_browser_autologin_status) — omit it to mean 'remember the session " +
343
+ "but ask a human for a fresh login'. `item` is an optional 'Vault/Item' path for when " +
344
+ "one site has several logins; omit it to match by site.\n" +
345
+ "This only says WHICH credential to use — it never handles the credential itself.",
346
+ inputSchema: {
347
+ domain: z.string(),
348
+ manager: z.string().optional(),
349
+ item: z.string().optional(),
350
+ },
351
+ handler: async (a) => {
352
+ const res = await api(cfg, "POST", "/vault/sites", {
353
+ domain: a.domain,
354
+ ...(typeof a.manager === "string" ? { manager: a.manager } : {}),
355
+ ...(typeof a.item === "string" ? { item: a.item } : {}),
356
+ });
357
+ if (res.status !== 200)
358
+ await apiError(res, "configure auto-login site");
359
+ const d = (await res.json());
360
+ return text({
361
+ ...d,
362
+ next: "Set. The next session that hits a login wall on this site signs in automatically " +
363
+ "if the credential is found; otherwise a human is asked, as before.",
364
+ });
365
+ },
366
+ },
297
367
  solari_browser_login: {
298
368
  description: "Get this session signed in. Call it the moment you hit a login form, a 2FA prompt, or "
299
369
  + "anything asking for a password — you must never handle credentials yourself.\n"
@@ -370,6 +440,7 @@ export function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
370
440
  // escalate to a human when that cannot work. Best-effort: any failure
371
441
  // here just falls through to the handoff below, which is the behaviour
372
442
  // that existed before.
443
+ let setupUrl = null;
373
444
  try {
374
445
  const auto = await api(cfg, "POST", `/sessions/${encodeURIComponent(sessionId)}/autologin`, {});
375
446
  if (auto.status === 200) {
@@ -382,6 +453,12 @@ export function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
382
453
  next: "You are signed in — carry on. No human was needed.",
383
454
  });
384
455
  }
456
+ // Nothing is configured for this site. Remember the setup link so
457
+ // it can be offered alongside the handoff below — the user is
458
+ // already being interrupted, so this is the cheapest possible
459
+ // moment to tell them how to stop being interrupted next time.
460
+ if (r.setupRequired && r.setupUrl)
461
+ setupUrl = r.setupUrl;
385
462
  }
386
463
  }
387
464
  catch {
@@ -410,6 +487,17 @@ export function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
410
487
  url: showUrl,
411
488
  fullUrl: h.url,
412
489
  expiresAt: h.expiresAt,
490
+ // Offered only when the account has NOTHING configured for this site.
491
+ // The user is already being interrupted, so this is the cheapest
492
+ // moment to show them how to stop being interrupted next time.
493
+ ...(setupUrl
494
+ ? {
495
+ setupUrl,
496
+ tip: "This account has no password manager connected for this site, so a human is " +
497
+ "needed every time. Connecting one at the setupUrl lets future logins happen " +
498
+ "automatically. MENTION THIS TO THE USER along with the sign-in link.",
499
+ }
500
+ : {}),
413
501
  next: "Show the url to the user, then call solari_browser_await_login.",
414
502
  });
415
503
  },
@@ -112358,7 +112358,7 @@ var SolariClient = class {
112358
112358
  };
112359
112359
 
112360
112360
  // src/version.ts
112361
- var VERSION = "0.4.1";
112361
+ var VERSION = "0.4.2";
112362
112362
 
112363
112363
  // node_modules/puppeteer-core/lib/esm/puppeteer/index.js
112364
112364
  init_index_browser();
@@ -113865,6 +113865,53 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
113865
113865
  });
113866
113866
  }
113867
113867
  },
113868
+ solari_browser_autologin_status: {
113869
+ description: "Check whether this account can sign in to websites automatically, and get a direct setup link if it cannot.\nCall this when a task will clearly need a login, BEFORE you start \u2014 if nothing is set up you can tell the user once, up front, with a link, instead of interrupting them mid-run. Also worth calling if a login keeps needing a human.\nReturns the connected password managers, the sites already configured, and `setupUrl`. If `configured` is false, SHOW setupUrl TO THE USER: it opens the page where they connect a password manager. You cannot do that step for them \u2014 it needs a credential that must never pass through you \u2014 but the link removes all the guesswork.",
113870
+ inputSchema: {},
113871
+ handler: async () => {
113872
+ const res = await api2(cfg, "GET", "/vault/status");
113873
+ if (res.status === 501) {
113874
+ return text({
113875
+ configured: false,
113876
+ available: false,
113877
+ note: "Automatic sign-in is not available on this deployment."
113878
+ });
113879
+ }
113880
+ if (res.status !== 200) await apiError(res, "auto-login status");
113881
+ const d = await res.json();
113882
+ const managers = d.managers ?? [];
113883
+ const sites = d.sites ?? [];
113884
+ return text({
113885
+ configured: managers.length > 0,
113886
+ available: true,
113887
+ managers: managers.map((m) => ({ name: m.name, provider: m.provider, vaults: m.vaults })),
113888
+ sites,
113889
+ setupUrl: d.setupUrl ?? null,
113890
+ next: managers.length === 0 ? "No password manager is connected. Show setupUrl to the user \u2014 it takes them straight to the page where they connect one, after which logins happen with no human involved." : sites.length === 0 ? "A password manager is connected but no sites use it yet. Add one with solari_browser_autologin_site, or the user can do it at setupUrl." : "Automatic sign-in is set up. Sessions will log in to these sites on their own."
113891
+ });
113892
+ }
113893
+ },
113894
+ solari_browser_autologin_site: {
113895
+ description: "Tell Solari to sign in to a site automatically using a connected password manager.\n`domain` is the site, e.g. 'github.com'. `manager` is the NAME of a connected password manager (see solari_browser_autologin_status) \u2014 omit it to mean 'remember the session but ask a human for a fresh login'. `item` is an optional 'Vault/Item' path for when one site has several logins; omit it to match by site.\nThis only says WHICH credential to use \u2014 it never handles the credential itself.",
113896
+ inputSchema: {
113897
+ domain: external_exports.string(),
113898
+ manager: external_exports.string().optional(),
113899
+ item: external_exports.string().optional()
113900
+ },
113901
+ handler: async (a2) => {
113902
+ const res = await api2(cfg, "POST", "/vault/sites", {
113903
+ domain: a2.domain,
113904
+ ...typeof a2.manager === "string" ? { manager: a2.manager } : {},
113905
+ ...typeof a2.item === "string" ? { item: a2.item } : {}
113906
+ });
113907
+ if (res.status !== 200) await apiError(res, "configure auto-login site");
113908
+ const d = await res.json();
113909
+ return text({
113910
+ ...d,
113911
+ next: "Set. The next session that hits a login wall on this site signs in automatically if the credential is found; otherwise a human is asked, as before."
113912
+ });
113913
+ }
113914
+ },
113868
113915
  solari_browser_login: {
113869
113916
  description: "Get this session signed in. Call it the moment you hit a login form, a 2FA prompt, or anything asking for a password \u2014 you must never handle credentials yourself.\nIt tries the account's connected password manager FIRST: if one is set up for this site, you are signed in automatically and NO human is involved \u2014 the reply says signedIn:true and you simply carry on. Otherwise it falls back to asking a human.\nTwo ways to call it:\nHOT \u2014 pass `sessionId` when you are ALREADY on a login wall mid-task. The user gets a live view of the exact page you are on and types into it; you resume on that same page.\nCOLD \u2014 pass `profileName` when you know a task will need a login and no session is open yet. The user signs in once in a profile editor, and every later solari_browser_create({profileId}) starts already authenticated. Prefer this when you can: nobody has to be watching mid-run. The profile is created if it does not exist.\nPass exactly one of the two. Either way, SHOW THE RETURNED URL TO THE USER, then call solari_browser_await_login.\nIn the HOT case your access to that session is REVOKED while the handoff is open \u2014 deliberately, so you cannot observe what they type \u2014 and the link expires in 5 minutes. Cold links last longer and revoke nothing, because there is no session yet.\n`reason` is required and is shown to the user \u2014 say plainly which site is asking and what for, because they are being asked to type a password on your say-so.",
113870
113917
  inputSchema: {
@@ -113913,6 +113960,7 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
113913
113960
  });
113914
113961
  }
113915
113962
  const e = need(sessionId);
113963
+ let setupUrl = null;
113916
113964
  try {
113917
113965
  const auto = await api2(
113918
113966
  cfg,
@@ -113930,6 +113978,7 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
113930
113978
  next: "You are signed in \u2014 carry on. No human was needed."
113931
113979
  });
113932
113980
  }
113981
+ if (r.setupRequired && r.setupUrl) setupUrl = r.setupUrl;
113933
113982
  }
113934
113983
  } catch {
113935
113984
  }
@@ -113952,6 +114001,13 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
113952
114001
  url: showUrl,
113953
114002
  fullUrl: h.url,
113954
114003
  expiresAt: h.expiresAt,
114004
+ // Offered only when the account has NOTHING configured for this site.
114005
+ // The user is already being interrupted, so this is the cheapest
114006
+ // moment to show them how to stop being interrupted next time.
114007
+ ...setupUrl ? {
114008
+ setupUrl,
114009
+ tip: "This account has no password manager connected for this site, so a human is needed every time. Connecting one at the setupUrl lets future logins happen automatically. MENTION THIS TO THE USER along with the sign-in link."
114010
+ } : {},
113955
114011
  next: "Show the url to the user, then call solari_browser_await_login."
113956
114012
  });
113957
114013
  }
@@ -111027,7 +111027,7 @@ var SolariClient = class {
111027
111027
  };
111028
111028
 
111029
111029
  // src/version.ts
111030
- var VERSION = "0.4.1";
111030
+ var VERSION = "0.4.2";
111031
111031
 
111032
111032
  // node_modules/puppeteer-core/lib/esm/puppeteer/index.js
111033
111033
  init_index_browser();
@@ -112534,6 +112534,53 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
112534
112534
  });
112535
112535
  }
112536
112536
  },
112537
+ solari_browser_autologin_status: {
112538
+ description: "Check whether this account can sign in to websites automatically, and get a direct setup link if it cannot.\nCall this when a task will clearly need a login, BEFORE you start \u2014 if nothing is set up you can tell the user once, up front, with a link, instead of interrupting them mid-run. Also worth calling if a login keeps needing a human.\nReturns the connected password managers, the sites already configured, and `setupUrl`. If `configured` is false, SHOW setupUrl TO THE USER: it opens the page where they connect a password manager. You cannot do that step for them \u2014 it needs a credential that must never pass through you \u2014 but the link removes all the guesswork.",
112539
+ inputSchema: {},
112540
+ handler: async () => {
112541
+ const res = await api2(cfg, "GET", "/vault/status");
112542
+ if (res.status === 501) {
112543
+ return text({
112544
+ configured: false,
112545
+ available: false,
112546
+ note: "Automatic sign-in is not available on this deployment."
112547
+ });
112548
+ }
112549
+ if (res.status !== 200) await apiError(res, "auto-login status");
112550
+ const d = await res.json();
112551
+ const managers = d.managers ?? [];
112552
+ const sites = d.sites ?? [];
112553
+ return text({
112554
+ configured: managers.length > 0,
112555
+ available: true,
112556
+ managers: managers.map((m) => ({ name: m.name, provider: m.provider, vaults: m.vaults })),
112557
+ sites,
112558
+ setupUrl: d.setupUrl ?? null,
112559
+ next: managers.length === 0 ? "No password manager is connected. Show setupUrl to the user \u2014 it takes them straight to the page where they connect one, after which logins happen with no human involved." : sites.length === 0 ? "A password manager is connected but no sites use it yet. Add one with solari_browser_autologin_site, or the user can do it at setupUrl." : "Automatic sign-in is set up. Sessions will log in to these sites on their own."
112560
+ });
112561
+ }
112562
+ },
112563
+ solari_browser_autologin_site: {
112564
+ description: "Tell Solari to sign in to a site automatically using a connected password manager.\n`domain` is the site, e.g. 'github.com'. `manager` is the NAME of a connected password manager (see solari_browser_autologin_status) \u2014 omit it to mean 'remember the session but ask a human for a fresh login'. `item` is an optional 'Vault/Item' path for when one site has several logins; omit it to match by site.\nThis only says WHICH credential to use \u2014 it never handles the credential itself.",
112565
+ inputSchema: {
112566
+ domain: external_exports.string(),
112567
+ manager: external_exports.string().optional(),
112568
+ item: external_exports.string().optional()
112569
+ },
112570
+ handler: async (a2) => {
112571
+ const res = await api2(cfg, "POST", "/vault/sites", {
112572
+ domain: a2.domain,
112573
+ ...typeof a2.manager === "string" ? { manager: a2.manager } : {},
112574
+ ...typeof a2.item === "string" ? { item: a2.item } : {}
112575
+ });
112576
+ if (res.status !== 200) await apiError(res, "configure auto-login site");
112577
+ const d = await res.json();
112578
+ return text({
112579
+ ...d,
112580
+ next: "Set. The next session that hits a login wall on this site signs in automatically if the credential is found; otherwise a human is asked, as before."
112581
+ });
112582
+ }
112583
+ },
112537
112584
  solari_browser_login: {
112538
112585
  description: "Get this session signed in. Call it the moment you hit a login form, a 2FA prompt, or anything asking for a password \u2014 you must never handle credentials yourself.\nIt tries the account's connected password manager FIRST: if one is set up for this site, you are signed in automatically and NO human is involved \u2014 the reply says signedIn:true and you simply carry on. Otherwise it falls back to asking a human.\nTwo ways to call it:\nHOT \u2014 pass `sessionId` when you are ALREADY on a login wall mid-task. The user gets a live view of the exact page you are on and types into it; you resume on that same page.\nCOLD \u2014 pass `profileName` when you know a task will need a login and no session is open yet. The user signs in once in a profile editor, and every later solari_browser_create({profileId}) starts already authenticated. Prefer this when you can: nobody has to be watching mid-run. The profile is created if it does not exist.\nPass exactly one of the two. Either way, SHOW THE RETURNED URL TO THE USER, then call solari_browser_await_login.\nIn the HOT case your access to that session is REVOKED while the handoff is open \u2014 deliberately, so you cannot observe what they type \u2014 and the link expires in 5 minutes. Cold links last longer and revoke nothing, because there is no session yet.\n`reason` is required and is shown to the user \u2014 say plainly which site is asking and what for, because they are being asked to type a password on your say-so.",
112539
112586
  inputSchema: {
@@ -112582,6 +112629,7 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
112582
112629
  });
112583
112630
  }
112584
112631
  const e = need(sessionId);
112632
+ let setupUrl = null;
112585
112633
  try {
112586
112634
  const auto = await api2(
112587
112635
  cfg,
@@ -112599,6 +112647,7 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
112599
112647
  next: "You are signed in \u2014 carry on. No human was needed."
112600
112648
  });
112601
112649
  }
112650
+ if (r.setupRequired && r.setupUrl) setupUrl = r.setupUrl;
112602
112651
  }
112603
112652
  } catch {
112604
112653
  }
@@ -112621,6 +112670,13 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
112621
112670
  url: showUrl,
112622
112671
  fullUrl: h.url,
112623
112672
  expiresAt: h.expiresAt,
112673
+ // Offered only when the account has NOTHING configured for this site.
112674
+ // The user is already being interrupted, so this is the cheapest
112675
+ // moment to show them how to stop being interrupted next time.
112676
+ ...setupUrl ? {
112677
+ setupUrl,
112678
+ tip: "This account has no password manager connected for this site, so a human is needed every time. Connecting one at the setupUrl lets future logins happen automatically. MENTION THIS TO THE USER along with the sign-in link."
112679
+ } : {},
112624
112680
  next: "Show the url to the user, then call solari_browser_await_login."
112625
112681
  });
112626
112682
  }
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.4.1";
1
+ export declare const VERSION = "0.4.2";
package/dist/version.js CHANGED
@@ -8,4 +8,4 @@
8
8
  // `test/version.test.mjs` FAILS the build if it ever drifts from package.json.
9
9
  //
10
10
  // KEEP IN SYNC WITH sdk/mcp/package.json "version".
11
- export const VERSION = "0.4.1";
11
+ export const VERSION = "0.4.2";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solarisdk/mcp",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Model Context Protocol server for the Solari cloud browser, sandboxes + desktops \u2014 drive them from Claude Desktop/Cowork, Claude Code, Cursor, etc.",
5
5
  "type": "module",
6
6
  "bin": {