@solarisdk/mcp 0.3.4 → 0.4.1

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
@@ -156,6 +156,8 @@ export function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
156
156
  captcha: z.boolean().optional(),
157
157
  recording: z.boolean().optional(),
158
158
  profileId: z.string().optional(),
159
+ /** Defaults to ON. Pass false to never auto-sign-in on this session. */
160
+ autoLogin: z.boolean().optional(),
159
161
  },
160
162
  handler: async (a) => {
161
163
  // STEALTH IS THE DEFAULT. Models consistently declined to opt in when it
@@ -203,6 +205,13 @@ export function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
203
205
  body.proxy = a.proxy;
204
206
  if (a.profileId)
205
207
  body.profileId = a.profileId;
208
+ // Auto-login is ON by default. If the account has connected a password
209
+ // manager and configured this site, the gateway signs the session in on
210
+ // its own — the agent never sees or handles the credential. Costs
211
+ // nothing when nothing is configured: the gateway finds no connection
212
+ // and the flow is exactly as before.
213
+ if (a.autoLogin !== false)
214
+ body.autoLogin = true;
206
215
  const res = await api(cfg, "POST", "/sessions", body);
207
216
  if (res.status !== 201)
208
217
  await apiError(res, "session create");
@@ -286,7 +295,12 @@ export function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
286
295
  },
287
296
  },
288
297
  solari_browser_login: {
289
- description: "Ask a HUMAN to sign in, so you never handle credentials yourself. Two ways to call it:\n" +
298
+ description: "Get this session signed in. Call it the moment you hit a login form, a 2FA prompt, or "
299
+ + "anything asking for a password — you must never handle credentials yourself.\n"
300
+ + "It tries the account's connected password manager FIRST: if one is set up for this "
301
+ + "site, you are signed in automatically and NO human is involved — the reply says "
302
+ + 'signedIn:true and you simply carry on. Otherwise it falls back to asking a human.\n'
303
+ + "Two ways to call it:\n" +
290
304
  "HOT — pass `sessionId` when you are ALREADY on a login wall mid-task. The user gets a " +
291
305
  "live view of the exact page you are on and types into it; you resume on that same page.\n" +
292
306
  "COLD — pass `profileName` when you know a task will need a login and no session is open " +
@@ -350,6 +364,29 @@ export function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
350
364
  }
351
365
  // ── HOT: rescue the live session ─────────────────────────────────
352
366
  const e = need(sessionId);
367
+ // Try the account's password manager FIRST. If a vault is connected and
368
+ // this site is configured, the gateway signs in on its own and no human
369
+ // is involved at all — we never see the credential either way. Only
370
+ // escalate to a human when that cannot work. Best-effort: any failure
371
+ // here just falls through to the handoff below, which is the behaviour
372
+ // that existed before.
373
+ try {
374
+ const auto = await api(cfg, "POST", `/sessions/${encodeURIComponent(sessionId)}/autologin`, {});
375
+ if (auto.status === 200) {
376
+ const r = (await auto.json());
377
+ if (r.outcome === "already_authenticated" || r.outcome === "vault_login") {
378
+ return text({
379
+ mode: "auto",
380
+ signedIn: true,
381
+ via: r.outcome === "vault_login" ? "password manager" : "saved session",
382
+ next: "You are signed in — carry on. No human was needed.",
383
+ });
384
+ }
385
+ }
386
+ }
387
+ catch {
388
+ /* fall through to the human handoff */
389
+ }
353
390
  const res = await api(cfg, "POST", `/sessions/${encodeURIComponent(sessionId)}/handoff`, { reason: a.reason });
354
391
  if (res.status !== 200)
355
392
  await apiError(res, "handoff request");
@@ -112358,7 +112358,7 @@ var SolariClient = class {
112358
112358
  };
112359
112359
 
112360
112360
  // src/version.ts
112361
- var VERSION = "0.3.4";
112361
+ var VERSION = "0.4.1";
112362
112362
 
112363
112363
  // node_modules/puppeteer-core/lib/esm/puppeteer/index.js
112364
112364
  init_index_browser();
@@ -113781,7 +113781,9 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
113781
113781
  /** Defaults to ON (following the pool). Pass false to opt out. */
113782
113782
  captcha: external_exports.boolean().optional(),
113783
113783
  recording: external_exports.boolean().optional(),
113784
- profileId: external_exports.string().optional()
113784
+ profileId: external_exports.string().optional(),
113785
+ /** Defaults to ON. Pass false to never auto-sign-in on this session. */
113786
+ autoLogin: external_exports.boolean().optional()
113785
113787
  },
113786
113788
  handler: async (a2) => {
113787
113789
  const stealth = a2.mode !== void 0 ? a2.mode === "stealth" : a2.stealth ?? true;
@@ -113800,6 +113802,7 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
113800
113802
  if (a2.recording) body.recording = true;
113801
113803
  if (a2.proxy) body.proxy = a2.proxy;
113802
113804
  if (a2.profileId) body.profileId = a2.profileId;
113805
+ if (a2.autoLogin !== false) body.autoLogin = true;
113803
113806
  const res = await api2(cfg, "POST", "/sessions", body);
113804
113807
  if (res.status !== 201) await apiError(res, "session create");
113805
113808
  const s = await res.json();
@@ -113863,7 +113866,7 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
113863
113866
  }
113864
113867
  },
113865
113868
  solari_browser_login: {
113866
- description: "Ask a HUMAN to sign in, so you never handle credentials yourself. Two 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.",
113869
+ 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.",
113867
113870
  inputSchema: {
113868
113871
  sessionId: external_exports.string().optional(),
113869
113872
  profileName: external_exports.string().optional(),
@@ -113910,6 +113913,26 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
113910
113913
  });
113911
113914
  }
113912
113915
  const e = need(sessionId);
113916
+ try {
113917
+ const auto = await api2(
113918
+ cfg,
113919
+ "POST",
113920
+ `/sessions/${encodeURIComponent(sessionId)}/autologin`,
113921
+ {}
113922
+ );
113923
+ if (auto.status === 200) {
113924
+ const r = await auto.json();
113925
+ if (r.outcome === "already_authenticated" || r.outcome === "vault_login") {
113926
+ return text({
113927
+ mode: "auto",
113928
+ signedIn: true,
113929
+ via: r.outcome === "vault_login" ? "password manager" : "saved session",
113930
+ next: "You are signed in \u2014 carry on. No human was needed."
113931
+ });
113932
+ }
113933
+ }
113934
+ } catch {
113935
+ }
113913
113936
  const res = await api2(
113914
113937
  cfg,
113915
113938
  "POST",
@@ -111027,7 +111027,7 @@ var SolariClient = class {
111027
111027
  };
111028
111028
 
111029
111029
  // src/version.ts
111030
- var VERSION = "0.3.4";
111030
+ var VERSION = "0.4.1";
111031
111031
 
111032
111032
  // node_modules/puppeteer-core/lib/esm/puppeteer/index.js
111033
111033
  init_index_browser();
@@ -112450,7 +112450,9 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
112450
112450
  /** Defaults to ON (following the pool). Pass false to opt out. */
112451
112451
  captcha: external_exports.boolean().optional(),
112452
112452
  recording: external_exports.boolean().optional(),
112453
- profileId: external_exports.string().optional()
112453
+ profileId: external_exports.string().optional(),
112454
+ /** Defaults to ON. Pass false to never auto-sign-in on this session. */
112455
+ autoLogin: external_exports.boolean().optional()
112454
112456
  },
112455
112457
  handler: async (a2) => {
112456
112458
  const stealth = a2.mode !== void 0 ? a2.mode === "stealth" : a2.stealth ?? true;
@@ -112469,6 +112471,7 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
112469
112471
  if (a2.recording) body.recording = true;
112470
112472
  if (a2.proxy) body.proxy = a2.proxy;
112471
112473
  if (a2.profileId) body.profileId = a2.profileId;
112474
+ if (a2.autoLogin !== false) body.autoLogin = true;
112472
112475
  const res = await api2(cfg, "POST", "/sessions", body);
112473
112476
  if (res.status !== 201) await apiError(res, "session create");
112474
112477
  const s = await res.json();
@@ -112532,7 +112535,7 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
112532
112535
  }
112533
112536
  },
112534
112537
  solari_browser_login: {
112535
- description: "Ask a HUMAN to sign in, so you never handle credentials yourself. Two 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.",
112538
+ 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.",
112536
112539
  inputSchema: {
112537
112540
  sessionId: external_exports.string().optional(),
112538
112541
  profileName: external_exports.string().optional(),
@@ -112579,6 +112582,26 @@ function makeBrowserToolset(cfg, reg, deps = defaultDeps) {
112579
112582
  });
112580
112583
  }
112581
112584
  const e = need(sessionId);
112585
+ try {
112586
+ const auto = await api2(
112587
+ cfg,
112588
+ "POST",
112589
+ `/sessions/${encodeURIComponent(sessionId)}/autologin`,
112590
+ {}
112591
+ );
112592
+ if (auto.status === 200) {
112593
+ const r = await auto.json();
112594
+ if (r.outcome === "already_authenticated" || r.outcome === "vault_login") {
112595
+ return text({
112596
+ mode: "auto",
112597
+ signedIn: true,
112598
+ via: r.outcome === "vault_login" ? "password manager" : "saved session",
112599
+ next: "You are signed in \u2014 carry on. No human was needed."
112600
+ });
112601
+ }
112602
+ }
112603
+ } catch {
112604
+ }
112582
112605
  const res = await api2(
112583
112606
  cfg,
112584
112607
  "POST",
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.3.4";
1
+ export declare const VERSION = "0.4.1";
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.3.4";
11
+ export const VERSION = "0.4.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solarisdk/mcp",
3
- "version": "0.3.4",
3
+ "version": "0.4.1",
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": {