mandala-computer-mcp 0.11.0 → 0.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.
Files changed (92) hide show
  1. package/README.md +159 -39
  2. package/dist/api.d.ts +9 -2
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +15 -4
  5. package/dist/api.js.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +3 -1
  8. package/dist/cli.js.map +1 -1
  9. package/dist/credits.d.ts +187 -0
  10. package/dist/credits.d.ts.map +1 -0
  11. package/dist/credits.js +119 -0
  12. package/dist/credits.js.map +1 -0
  13. package/dist/errors.d.ts +92 -26
  14. package/dist/errors.d.ts.map +1 -1
  15. package/dist/errors.js +206 -35
  16. package/dist/errors.js.map +1 -1
  17. package/dist/format.d.ts.map +1 -1
  18. package/dist/format.js +30 -8
  19. package/dist/format.js.map +1 -1
  20. package/dist/http.d.ts.map +1 -1
  21. package/dist/http.js +82 -8
  22. package/dist/http.js.map +1 -1
  23. package/dist/limits.d.ts +2 -0
  24. package/dist/limits.d.ts.map +1 -1
  25. package/dist/limits.js +2 -0
  26. package/dist/limits.js.map +1 -1
  27. package/dist/paths.d.ts +42 -1
  28. package/dist/paths.d.ts.map +1 -1
  29. package/dist/paths.js +46 -0
  30. package/dist/paths.js.map +1 -1
  31. package/dist/poll.d.ts +1 -1
  32. package/dist/poll.js +1 -1
  33. package/dist/server.d.ts +41 -0
  34. package/dist/server.d.ts.map +1 -1
  35. package/dist/server.js +129 -5
  36. package/dist/server.js.map +1 -1
  37. package/dist/session.d.ts +20 -4
  38. package/dist/session.d.ts.map +1 -1
  39. package/dist/session.js +5 -0
  40. package/dist/session.js.map +1 -1
  41. package/dist/stdio.d.ts.map +1 -1
  42. package/dist/stdio.js +11 -1
  43. package/dist/stdio.js.map +1 -1
  44. package/dist/tool-filters.d.ts +3 -2
  45. package/dist/tool-filters.d.ts.map +1 -1
  46. package/dist/tool-filters.js +3 -1
  47. package/dist/tool-filters.js.map +1 -1
  48. package/dist/tools/account.d.ts.map +1 -1
  49. package/dist/tools/account.js +10 -3
  50. package/dist/tools/account.js.map +1 -1
  51. package/dist/tools/activities.d.ts.map +1 -1
  52. package/dist/tools/activities.js +4 -0
  53. package/dist/tools/activities.js.map +1 -1
  54. package/dist/tools/agent.d.ts +12 -4
  55. package/dist/tools/agent.d.ts.map +1 -1
  56. package/dist/tools/agent.js +292 -132
  57. package/dist/tools/agent.js.map +1 -1
  58. package/dist/tools/chat.d.ts +11 -2
  59. package/dist/tools/chat.d.ts.map +1 -1
  60. package/dist/tools/chat.js +19 -9
  61. package/dist/tools/chat.js.map +1 -1
  62. package/dist/tools/computers.d.ts.map +1 -1
  63. package/dist/tools/computers.js +92 -11
  64. package/dist/tools/computers.js.map +1 -1
  65. package/dist/tools/credits.d.ts +9 -0
  66. package/dist/tools/credits.d.ts.map +1 -0
  67. package/dist/tools/credits.js +53 -0
  68. package/dist/tools/credits.js.map +1 -0
  69. package/dist/tools/guest.d.ts.map +1 -1
  70. package/dist/tools/guest.js +6 -7
  71. package/dist/tools/guest.js.map +1 -1
  72. package/dist/tools/input.d.ts.map +1 -1
  73. package/dist/tools/input.js +51 -18
  74. package/dist/tools/input.js.map +1 -1
  75. package/dist/tools/operations.js +2 -2
  76. package/dist/tools/operations.js.map +1 -1
  77. package/dist/tools/publicurls.d.ts +3 -0
  78. package/dist/tools/publicurls.d.ts.map +1 -0
  79. package/dist/tools/publicurls.js +287 -0
  80. package/dist/tools/publicurls.js.map +1 -0
  81. package/dist/tools/snapshots.d.ts.map +1 -1
  82. package/dist/tools/snapshots.js +1 -0
  83. package/dist/tools/snapshots.js.map +1 -1
  84. package/dist/tools/ssh.d.ts.map +1 -1
  85. package/dist/tools/ssh.js +4 -2
  86. package/dist/tools/ssh.js.map +1 -1
  87. package/dist/tools/webhooks.d.ts.map +1 -1
  88. package/dist/tools/webhooks.js +32 -23
  89. package/dist/tools/webhooks.js.map +1 -1
  90. package/dist/version.d.ts +1 -1
  91. package/dist/version.js +1 -1
  92. package/package.json +1 -1
package/README.md CHANGED
@@ -96,7 +96,9 @@ right answer at all, that it costs money until it is suspended or stopped, that
96
96
  which refusals are worth a second try. It is a description of *when and how*,
97
97
  not a second client; once the server is installed it stays out of the way.
98
98
  `MANDALA_MODEL_KEY`, if exported alongside, is passed through and turns on
99
- `run_agent` when the configured filters permit it.
99
+ `run_agent` when the configured filters permit it. Without it, `run_agent` runs
100
+ on the account's AI credits when they can pay (see [Agents on AI
101
+ credits](#agents-on-ai-credits)).
100
102
 
101
103
  To use an environment key instead of a saved profile:
102
104
 
@@ -170,9 +172,17 @@ Parameter and response-mode support remains a separate contract.
170
172
 
171
173
  **Lifecycle** — `create_computer`, `start_computer`, `stop_computer`,
172
174
  `suspend_computer`, `restart_computer`, `update_computer`, `clone_computer`,
173
- `delete_computer`, `move_computer`, `list_moves`, `get_operation`,
175
+ `delete_computer`, `move_computer_to_workspace`, `move_computer`, `list_moves`, `get_operation`,
174
176
  `list_operations`, `wait_for_operation` — see [Lifecycle operations](#lifecycle-operations)
175
177
 
178
+ `move_computer_to_workspace` changes workspace membership and who can access a computer.
179
+ It requires an account-wide member or owner credential and explicit `computer_id` and
180
+ `workspace_id` arguments (`null` means unassigned). The selected computer and default
181
+ workspace are not used. The computer must be stopped, with no saved session, snapshots
182
+ or snapshot history copies, secret bindings, or proxy credentials. Refusals leave
183
+ those resources intact; the tool never removes them to force a move. This is separate
184
+ from `move_computer`, which relocates a computer to different hardware.
185
+
176
186
  **Driving the desktop** — `screenshot`, `click`, `type_text`, `paste_text`,
177
187
  `press_key`, `scroll`, `drag`, `move_mouse`, `mouse_button`, `cursor_position`,
178
188
  `wait`
@@ -228,7 +238,18 @@ which says nothing about the path; `isTransient` is false for both.
228
238
  `rename_workspace`, `delete_workspace`. Minting and revoking API keys are
229
239
  deliberately not tools — see [Who you are, and API keys](#who-you-are-and-api-keys).
230
240
 
231
- **Spending** — `get_usage`
241
+ **Deliberately not tools** — five API operations, each because it would put a
242
+ credential in a model's context: minting and revoking API keys (above), and the
243
+ three browser-connection routes (create, renew and revoke). A browser
244
+ connection is a raw capability to drive the guest's browser; the TypeScript
245
+ and Python SDKs' browser drivers create, renew and revoke it and keep it to
246
+ themselves. Every other API operation has a tool.
247
+
248
+ **Every tool refuses an argument it does not declare.** A misspelt or unknown
249
+ key is an input error naming the key, and nothing is sent — so a misspelt flag
250
+ can never be dropped and the call go ahead without it.
251
+
252
+ **Spending** — `get_usage`, `get_credits`
232
253
 
233
254
  **Being told somewhere else** — `list_webhooks`, `create_webhook`,
234
255
  `get_webhook`, `update_webhook`, `rotate_webhook_secret`, `test_webhook`,
@@ -249,6 +270,25 @@ account) or bound to another account answers as if there were no such key, and
249
270
  the person removes it from the dashboard. A workspace-scoped key can read keys
250
271
  but not add or remove them.
251
272
 
273
+ **Showing an app on the internet** — `list_public_urls`, `create_public_url`,
274
+ `update_public_url`, `delete_public_url`. A port inside a computer served at
275
+ `https://<label>.<base_domain>` (the domain is in the `list_public_urls`
276
+ answer, e.g. `mandala.dev`), on 443 with no port in the address. **Public by
277
+ default: anyone with the link can open it**; `access: "private"` requires an API
278
+ key of this account as `Authorization: Bearer`, which never reaches the app. The
279
+ app must listen on `0.0.0.0`, not `127.0.0.1`. Labels that read as the
280
+ platform's or another company's address are refused. A deleted URL's label stays
281
+ with the account: no other account can ever take it, and the account may use it
282
+ again unless the platform has blocked it. A computer over its plan's limit
283
+ serves only its oldest URLs, and the listing marks the rest.
284
+
285
+ A browser opening a new account's URL may first see a one-time notice page. It
286
+ goes to any request that looks like a browser opening a page — a navigation by
287
+ its fetch metadata, or, without fetch metadata, `Accept: text/html` from a
288
+ `Mozilla/` user agent — so a program sending browser headers sees it too. A
289
+ client that sets headers skips it with `mandala-skip-warning: 1`; in the
290
+ computer's own browser, where `open_url` cannot send headers, click Continue.
291
+
252
292
  **Secrets** — `list_secrets`, `get_secret`, `create_secret`, `set_secret`,
253
293
  `replace_secret`, `delete_secret` for the account's secret store, and
254
294
  `get_computer_secrets`, `set_computer_secrets` and `create_computer`'s `secrets`
@@ -300,9 +340,11 @@ before a request is sent — replaces the setting whole, and `null` removes it.
300
340
  says "its egress proxy is waiting for credentials; connections are closed until
301
341
  they arrive".
302
342
 
303
- **Delegating** — `run_agent`, `run_agent_chat`, registered only when a model key is present:
343
+ **Delegating** — `run_agent`, `run_agent_chat`, registered when a model key is present:
304
344
  `MANDALA_MODEL_KEY` on stdio, or the caller's own `X-Model-Key` header over HTTP.
305
- Both must also survive the configured filters.
345
+ Without a key, `run_agent` alone is registered when the account's AI credits can
346
+ pay for a run (see [Agents on AI credits](#agents-on-ai-credits)). Both must also
347
+ survive the configured filters.
306
348
 
307
349
  ### Tool filters
308
350
 
@@ -325,7 +367,7 @@ with an error listing all valid tags.
325
367
  | --- | --- |
326
368
  | `account` | `get_account`, `whoami`, `list_api_keys`, `list_workspaces`, `get_workspace`, `list_workspace_members`, `create_workspace`, `rename_workspace`, `delete_workspace` |
327
369
  | `computers` | `list_computers`, `get_computer`, `use_computer`, `wait_for_computer`, `get_desktop_url`, `list_sizes` |
328
- | `lifecycle` | `create_computer`, `start_computer`, `stop_computer`, `suspend_computer`, `restart_computer`, `update_computer`, `clone_computer`, `delete_computer`, `move_computer`, `list_moves`, `get_operation`, `list_operations`, `wait_for_operation` |
370
+ | `lifecycle` | `create_computer`, `start_computer`, `stop_computer`, `suspend_computer`, `restart_computer`, `update_computer`, `clone_computer`, `delete_computer`, `move_computer_to_workspace`, `move_computer`, `list_moves`, `get_operation`, `list_operations`, `wait_for_operation` |
329
371
  | `input` | `screenshot`, `click`, `type_text`, `paste_text`, `press_key`, `scroll`, `drag`, `move_mouse`, `mouse_button`, `cursor_position`, `wait` |
330
372
  | `guest` | `exec`, `exec_poll`, `exec_kill`, `open_url`, `list_windows`, `window_action`, `read_clipboard`, `write_clipboard` |
331
373
  | `files` | `list_directory`, `read_file`, `write_file`, `wait_for_file_change` |
@@ -335,9 +377,10 @@ with an error listing all valid tags.
335
377
  | `snapshots` | All snapshot tools listed above, including `get_retention` |
336
378
  | `templates` | `list_templates`, all your-own-template tools and all build tools listed above |
337
379
  | `events` | `wait_for_event`, `poll_events`, `wait_for_file_change` |
338
- | `usage` | `get_usage` |
380
+ | `usage` | `get_usage`, `get_credits` |
339
381
  | `webhooks` | All webhook tools listed above |
340
382
  | `ssh` | All SSH tools listed above |
383
+ | `public_urls` | `list_public_urls`, `create_public_url`, `update_public_url`, `delete_public_url` |
341
384
  | `secrets` | `list_secrets`, `get_secret`, `create_secret`, `set_secret`, `replace_secret`, `delete_secret`, `get_computer_secrets`, `set_computer_secrets` |
342
385
  | `agent` | `run_agent`, `run_agent_chat` |
343
386
  | `activities` | `list_activities`, `get_activity`, `get_activity_results` |
@@ -346,7 +389,8 @@ with an error listing all valid tags.
346
389
  The selected tags form a union, then intersect with read-only and the existing
347
390
  lifecycle and model-key restrictions. `MANDALA_NO_LIFECYCLE=1` still withholds
348
391
  its five tools even when their tags are selected; selecting `agent` cannot
349
- enable either agent tool without a per-session model key. Both agent tools are
392
+ enable `run_agent_chat` without a per-session model key, nor `run_agent` without
393
+ one or credits that can pay. Both agent tools are
350
394
  withheld by read-only, but remain available with lifecycle disabled alone.
351
395
  `MANDALA_TAGS=files MANDALA_READ_ONLY=1` exposes only `list_directory`.
352
396
  An `agent` selection with read-only is a valid empty tool list.
@@ -364,7 +408,7 @@ does not read the environment itself.
364
408
  ### Lifecycle operations
365
409
 
366
410
  Every accepted create, clone, start, stop, suspend, restart, snapshot restore,
367
- resize, move and delete records a lifecycle operation, and the tool that made the call
411
+ resize, host move and delete records a lifecycle operation, and the tool that made the call
368
412
  says its `operation_id` — in its sentence, as `(operation op_…)`, and in the
369
413
  JSON. `move_computer` carries it onto the outcome it reports. It is absent where
370
414
  the platform could not record one; the call happened either way.
@@ -477,8 +521,10 @@ one is refused (403), so none of them can touch the workspace this server's own
477
521
  key stands in. `delete_workspace` needs `confirm: true` and REVOKES every API
478
522
  key confined to the workspace, whoever holds it — a person's CI or another agent
479
523
  may be using one — and answers how many. Only an empty workspace can be
480
- deleted: one that still holds computers is refused (409), saying how many, and
481
- nothing is deleted or revoked.
524
+ deleted: one that still holds computers or active secrets is refused (409),
525
+ saying how many, and nothing is deleted or revoked. Move its computers out with
526
+ `move_computer_to_workspace` (or delete them) and delete its secrets with
527
+ `delete_secret`, then send it again.
482
528
  None of the three is offered to a read-only session (`MANDALA_READ_ONLY`).
483
529
 
484
530
  An account-wide key can work in one workspace without a key confined to it:
@@ -552,18 +598,28 @@ refuses a suspended computer and names `start_computer`, where the SDKs'
552
598
  `waitForGuest` resumes it.
553
599
 
554
600
  **A screenshot need not be the whole screen.** `screenshot` takes `region` (a
555
- crop, in the screen pixels `click` takes, before any scaling), `scale` (0 to 1),
601
+ crop, in full-size capture pixels before any scaling), `scale` (0 to 1),
556
602
  `format` (`png` or `jpeg`) and `quality` (JPEG, 1-100). A cropped or scaled
557
603
  picture is in its own pixel space, so the tool says alongside it how to turn a
558
604
  position in it back into screen coordinates.
559
605
 
606
+ Live screenshots also return a `capture` name and the capture's original size,
607
+ before cropping or scaling. Use that size instead of the computer record's
608
+ `resolution`, which can differ. To crop a frame you already measured, send its
609
+ `capture` with `region`; omit `fresh` or set it to `false`. Without `capture`,
610
+ screenshots remain fresh by default. `fresh: true` cannot be combined with
611
+ `capture`. If the capture is no longer held (`stale_capture`), take a new
612
+ screenshot without `capture` or `region`, then remeasure the region and use the
613
+ new capture name. Saved frames of suspended computers cannot be pinned this way.
614
+
560
615
  **Ten clicks need not be ten screenshots.** Driving the desktop one tool at a
561
616
  time — `screenshot`, `click`, `screenshot` — puts an image in the calling
562
617
  model's context for every step. `run_agent` hands a task in plain language to
563
618
  the platform's own loop instead, which screenshots, decides and clicks inside
564
619
  the platform and answers with a sentence and the list of what it did. It is
565
- registered only when a model key is present (see [Configuration](#configuration))
566
- and bills that key for the run. `max_steps` bounds the WORK rather than the
620
+ registered when a model key is present (see [Configuration](#configuration)),
621
+ and bills that key for the run, or else when the account's AI credits can pay
622
+ (see [Agents on AI credits](#agents-on-ai-credits)). `max_steps` bounds the WORK rather than the
567
623
  bill: a step is one action on the desktop, one model reply can ask for several
568
624
  and spends a step on each, a paused turn costs tokens and no step, and not every
569
625
  step takes a screenshot. It defaults to 20 and is capped at 100 here.
@@ -919,12 +975,14 @@ does not.
919
975
  **screenshots deliberately do not**, so a loop that only watches can see its own
920
976
  machine go down under it.
921
977
 
922
- **A stop is a request, and can be refused.** `stop_computer` asks the guest to
923
- shut down and gives it time to do it. A hung X session, a modal "unsaved
924
- changes" dialog or a service that ignores its own shutdown will refuse that
925
- identically every time it is asked. `force: true` pulls the power instead — the
926
- equivalent of holding the button in — and whatever the guest had not written to
927
- disk goes with it, so it is the second attempt rather than the first.
978
+ **A stop asks first, then forces.** `stop_computer` asks the guest to shut
979
+ down and gives it up to 20 seconds; a guest still up after that — a hung X
980
+ session, a modal "unsaved changes" dialog, a service that ignores its own
981
+ shutdown — is forced off by the platform, so an ordinary stop ends stopped and
982
+ can take up to about a minute to answer. `force: true` skips the asking and the
983
+ wait and pulls the power at once — the equivalent of holding the button in — and
984
+ whatever the guest had not written to disk goes with it. It saves 20 seconds,
985
+ not a failed stop, so leave it out unless the computer must be off immediately.
928
986
 
929
987
  **Purging snapshots is bound to the set you were shown.** Deleting a computer
930
988
  keeps its snapshots by default. To destroy them too, read `snapshot_holdings`
@@ -984,8 +1042,13 @@ inside its boot window) clear, so the same call works in a moment;
984
1042
  `unavailable`, `running`, `unsupported`, `exists` and `revoked` do not. A 409
985
1043
  does not mean "wait": `exec`, input and the clipboard on a stopped computer
986
1044
  answer 409 `unavailable`, and `start_computer` is what fixes that, while
987
- `running` needs the computer stopped first. The platform's own error messages
988
- come through unedited, because they are written to be acted on.
1045
+ `running` needs the computer stopped first. A 409 with no `reason` is
1046
+ unclassified, and is treated as one that does not clear — a label that is taken,
1047
+ a computer at its public URL limit, the webhook cap, an SSH key already
1048
+ registered — unless its `code` is one the platform documents as passing
1049
+ (`idempotency_in_progress`, or `WORKSPACE_MOVING` while the move settles). The
1050
+ platform's own error messages come through unedited, because they are written to
1051
+ be acted on.
989
1052
 
990
1053
  HTTP failures preserve their actual response status. An unsupported method on a
991
1054
  known path is `MethodNotAllowedError` (405), with the received `Allow` value when
@@ -1000,7 +1063,10 @@ same way. So `isTransient` is false for it whatever `reason` it carries, the
1000
1063
  tool's answer says to read the current state first, and `error.method` records
1001
1064
  the method. A `reason` this version does not
1002
1065
  know, such as a new word, is treated as no classification. `reasonKind` returns
1003
- `undefined` for it, and the status decides.
1066
+ `undefined` for it, and the status decides — which, for a 409, is no: a 409 is
1067
+ transient only when its `reason` clears or its `code` is
1068
+ `idempotency_in_progress` or `WORKSPACE_MOVING` (with no `reason` saying
1069
+ otherwise). `APIError.code` carries the platform's code.
1004
1070
 
1005
1071
  The secret store has typed calls on `api.secrets`: `list`, `create`, `get`,
1006
1072
  `replace` and `delete`. Each answer is decoded strictly to the documented
@@ -1041,9 +1107,11 @@ intermediaries and connection failures may supply none of them. Existing
1041
1107
  constructor arguments retain their meanings; an optional trailing
1042
1108
  `APIErrorMetadata` object adds these three fields, and `method`.
1043
1109
 
1044
- MCP error results include supplied `reason`, `request_id`, `allow`,
1045
- `www_authenticate` and `retry_after_ms` as labelled JSON metadata. Diagnostic
1046
- strings are limited to 128, 256, 512 and 512 characters respectively; an
1110
+ MCP error results include supplied `code`, `reason`, `request_id`, `allow`,
1111
+ `www_authenticate` and `retry_after_ms` as labelled JSON metadata. `code` is the
1112
+ platform's machine-readable code (`LABEL_TAKEN`, `WORKSPACE_MOVING`, …), the
1113
+ word to switch on rather than the sentence. Diagnostic
1114
+ strings are limited to 128, 128, 256, 512 and 512 characters respectively; an
1047
1115
  oversized field is omitted with a notice, so a shortened Allow is never
1048
1116
  presented as complete. Tool-specific warnings about partial work, retained
1049
1117
  publication, execution reads and explicit template continuation still apply.
@@ -1372,7 +1440,7 @@ address.
1372
1440
  | `MANDALA_PROFILE` | Local saved profile; `--profile` overrides it. Otherwise the file default is selected. Ignored by HTTP. |
1373
1441
  | `MANDALA_BASE_URL` | With a saved profile, must match its stored base. Otherwise defaults to `https://app.mandala.computer/api/v1`. |
1374
1442
  | `MANDALA_COMPUTER_ID` | Bind a computer at startup, so `use_computer` is not needed. **stdio only** — under `--http` it is ignored rather than bound into every caller's session, since it names a machine on the operator's account. |
1375
- | `MANDALA_MODEL_KEY` | An Anthropic key. Enables `run_agent` and `run_agent_chat` when filters permit them, which runs the platform's own loop on that key. **stdio only** — under `--http` each caller sends their own as `X-Model-Key`, and this variable is ignored. |
1443
+ | `MANDALA_MODEL_KEY` | An Anthropic or OpenAI key. Enables `run_agent` and `run_agent_chat` when filters permit them, which runs the platform's own loop on that key. Without it, `run_agent` runs on the account's AI credits when they can pay. **stdio only** — under `--http` each caller sends their own as `X-Model-Key`, and this variable is ignored. |
1376
1444
  | `MANDALA_NO_LIFECYCLE` | `1`, `true`, `yes` or `on` withholds `create_computer`, `clone_computer`, `clone_snapshot`, `delete_computer` and `delete_snapshot` — every tool that makes a computer or destroys one. `0`, `false`, `no`, `off` or unset leaves them registered. Any other value is **refused at startup** rather than read as off: a typo here would otherwise leave those tools in place on a server whose operator believes they are gone. The `--no-lifecycle` flag reads the same vocabulary and refuses the same way, except that it has no spelling for *unset*: `--no-lifecycle=` is refused rather than ignored, so a launcher template whose variable did not expand stops instead of quietly leaving the tools registered. |
1377
1445
  | `PORT`, `HOST` | For `--http`. Default `3000`, `127.0.0.1`. |
1378
1446
  | `MANDALA_READ_ONLY` | Keep only tools annotated `readOnlyHint: true`; strict boolean parsing as described under Tool filters. |
@@ -1397,9 +1465,54 @@ none of which is true of `MANDALA_API_KEY`.
1397
1465
  `run_agent` deserves a note. It hands a task to the platform's own agent loop,
1398
1466
  which drives the computer inside the platform and answers with a sentence. Worth
1399
1467
  it when a stretch of pixel work would otherwise cost the calling model a
1400
- screenshot per step — ten clicks stop being ten images. It bills your Anthropic
1468
+ screenshot per step — ten clicks stop being ten images. It bills your selected provider
1401
1469
  key, and the platform never stores that key.
1402
1470
 
1471
+ Both `run_agent` and `run_agent_chat` accept `provider: "openai"` to use
1472
+ `gpt-6.1-sol` by default, or infer OpenAI from a recognized GPT model name.
1473
+ Set `MANDALA_MODEL_KEY` (stdio) or `X-Model-Key` (HTTP) to the matching provider
1474
+ key. Custom model names require an explicit `provider`; omitting model and
1475
+ provider preserves the Anthropic default. OpenAI is BYOK only and stores
1476
+ Responses continuations at OpenAI; tasks, screenshots and tool results go to
1477
+ that provider. A native OpenAI action batch must fit the remaining step and
1478
+ API budget before it begins. Partial failures stop the run without replaying input.
1479
+
1480
+ ### Agents on AI credits
1481
+
1482
+ Without a model key, `run_agent` can run on the account's Mandala AI credits.
1483
+ The server reads `GET /credits` on the session's own API key and registers
1484
+ `run_agent` only when the account is not frozen and has at least $0.25
1485
+ available, which is what a run's first model call reserves. On stdio that read
1486
+ happens once, at startup. Over HTTP it happens per session, at initialize, with
1487
+ that caller's bearer token; a caller who sends `X-Model-Key` is not asked, and no
1488
+ operator key or setting is ever used. Any failure of the read — a refusal (a
1489
+ workspace-scoped key cannot read the account-wide ledger), an error, a timeout or
1490
+ a record that does not parse — leaves `run_agent` out. A session started
1491
+ unfunded does not gain the tool when credits arrive later; reconnect, or restart
1492
+ a stdio server.
1493
+
1494
+ On credits `run_agent` takes `max_cost_usd` (0.25 to 20; the platform defaults
1495
+ to 2), the most a run may start spending. The last model call can go past it,
1496
+ and a run that reaches it ends with `stop: "max_cost"`. It does not take
1497
+ `system` or `provider`: a run on credits uses the platform's own prompt and
1498
+ Anthropic, with `claude-sonnet-5-5` by default and `claude-opus-5-5` on request.
1499
+ The result reports `cost_usd`, the run's charge so far, and
1500
+ `credits_remaining_usd`, the balance the last step reported. A run whose credits
1501
+ run out partway ends with `stop: "credits_exhausted"`, and a run that cannot
1502
+ reserve its first call is refused `402` with a `top_up_url`; the tool reports
1503
+ that as the account's credits running out, with the billing page, rather than as
1504
+ a plan limit or the model provider's billing error. The platform reports its
1505
+ AI service failing a run on credits as `Mandala AI is unavailable` over the
1506
+ provider's status. On such a run that sentence, at any status, and any other
1507
+ `402`, are worded as the service failing, not as the caller's credential, the
1508
+ computer, the request or a model key. `run_agent_chat` is never registered
1509
+ without a model key: the platform runs that route only on the caller's own key.
1510
+
1511
+ `get_credits` reads the ledger: available, balance, held, debt, whether the
1512
+ account is frozen, this period's plan grant, the unexpired lots and one page of
1513
+ the journal, newest first (`before` and `limit` page through it). Amounts are
1514
+ integer USD micros. It needs an account-wide key.
1515
+
1403
1516
  ### Passive directories, activity history and signals
1404
1517
 
1405
1518
  `list_directory` takes an exact absolute guest `path`. Unicode, spaces and
@@ -1441,14 +1554,14 @@ or that a task succeeded. Unsupported (501) and unavailable (503) responses
1441
1554
  remain errors, never empty history or new checkpoints. There is no watcher,
1442
1555
  guest action, retry loop or automatic checkpoint cache in this tool.
1443
1556
 
1444
- ### JSON chat with your own Anthropic key
1557
+ ### JSON chat with your own model key
1445
1558
 
1446
- `run_agent_chat` drives the selected computer using the same BYOK Anthropic loop
1559
+ `run_agent_chat` drives the selected computer using the same BYOK Anthropic or OpenAI loop
1447
1560
  as `run_agent`. It accepts a nonempty array of textual OpenAI-shaped `messages`,
1448
1561
  including string content or arrays of `{type:"text",text:"..."}` parts. The
1449
1562
  **last user message** supplies the task; system messages supply standing
1450
1563
  instructions. Earlier user/assistant conversation is not replayed. Optional
1451
- `model` is sent unchanged and must name an Anthropic model. `max_steps` is 1–100,
1564
+ `model` selects a computer-capable Anthropic or OpenAI model. `max_steps` is 1–100,
1452
1565
  default 20. This is computer control, not hosted general-purpose inference or a
1453
1566
  chat UI; it adds no key storage or model billing service.
1454
1567
 
@@ -1482,7 +1595,9 @@ caller is a `401` or `403` carrying `reason: "revoked"`, and only that gets
1482
1595
  account advice. A `402`, `504` or `529` is the model provider's own status for
1483
1596
  the configured model key (its billing, timeout or overloaded error), so the
1484
1597
  advice is to check the model-provider account, not the Mandala plan; a `403`
1485
- without `revoked` may be the provider's permission error for that key. The
1598
+ without `revoked` may be the provider's permission error for that key. The one
1599
+ `402` that is Mandala's own carries a `top_up_url`: a run on AI credits the
1600
+ account cannot cover, worded as such. The
1486
1601
  exception is a refusal `run_agent_chat` is given before any run started — a flat
1487
1602
  `{error: string}` body, from the role gate, a bad body, a suspension or the
1488
1603
  meter: nothing ran, and it keeps the usual role and plan advice every other tool
@@ -1511,8 +1626,13 @@ overall deadline and an 8 MiB body ceiling, then exercises the real MCP tools
1511
1626
  and requires request evidence for every published `/api/v1` operation. Every
1512
1627
  exercise variant must succeed and dispatch a request, including later variants
1513
1628
  of a tool that already dispatched successfully.
1514
- Non-v1 operations are explicitly excluded and reported. The check uses OpenAPI
1515
- server inheritance and literal-path precedence, not the local route allowlist.
1629
+ Non-v1 operations are explicitly excluded and reported. Protocol forms are
1630
+ reported but not required, since no tool sends them: `OPTIONS` (the CORS
1631
+ preflight) and a `HEAD` published beside a `GET` at the same URL (that `GET`
1632
+ without its body). A `HEAD` with no such `GET` is required like any other
1633
+ operation.
1634
+ The check uses OpenAPI server inheritance and literal-path precedence, not the
1635
+ local route allowlist.
1516
1636
  Each path is appended to its effective server base; repeated prefixes are not
1517
1637
  removed. Fully prefixed paths work with an absent or root server.
1518
1638
  It fails on a blocked fetch, redirect, invalid document or missing operation;
@@ -1520,11 +1640,10 @@ there is no fixture fallback, credential requirement or skip branch.
1520
1640
 
1521
1641
  The committed OpenAPI fixture is synthetic, assembled from the public MCP route
1522
1642
  inventory, and is never presented as a downloaded publication. Offline green
1523
- proves deterministic implementation coverage only. Anonymous CI at
1524
- [commit 1b04314](https://github.com/mandalacomputer/mcp/commit/1b04314e84f5701e2e15c65cbb1c44a0c14a4948)
1525
- returned HTTP 200 and matched all 56 operations in the fetched v1 contract using
1526
- 123 requests from 83 tools. That result applies to that commit and publication;
1527
- every subsequent head must pass the gate independently. These counts are
1643
+ proves deterministic implementation coverage only. Each `published-openapi` run
1644
+ logs the publication's digest and how many operations it matched with how many
1645
+ requests from how many tools; a result applies to that commit and that
1646
+ publication, and every head must pass the gate independently. Those counts are
1528
1647
  observations, never fixed thresholds or exemptions. A blocked or red public gate
1529
1648
  must not be merged. Parameters and response modes remain separate contracts,
1530
1649
  with documented parameter exceptions and JSON-only chat support.
@@ -1580,6 +1699,7 @@ several names. Where a client has no way to do it, the cell says so with —.
1580
1699
  | The usage window | `usage.read({ from, to })` | `usage.read(since=…, until=…)`, or `from_=` and `to=` | `get_usage` with `from` and `to` | `usage --from … --to …` | — |
1581
1700
  | Change a computer (`PATCH`) | `update({ … })` | `rename()`, `resize()`, `set_idle_suspend()`, `set_browser_proxy()`, `set_egress_proxy()` | `update_computer` | `computers rename`, `resize`, `idle-suspend`, `browser-proxy set`/`clear`, `egress-proxy set`/`clear` | `browser-proxy set`/`clear`, `egress-proxy set`/`clear` |
1582
1701
  | Wait until the computer is ready | `waitForGuest()`, `waitForDesktop()` | `wait_for_guest()`, `wait_for_desktop()` | `wait_for_computer` with `until: "guest"`, which on Linux also waits for the desktop session | `computers wait --until guest` or `--until desktop` | — |
1702
+ | A screenshot, fresh or cached | `screenshot(width, { fresh, capture })`: cached unless `fresh: true` | `screenshot(fresh=…, capture=…)`: cached unless `fresh=True` | `screenshot`: **fresh by default** unless `capture` is given; `fresh: false` for the cache | `computers screenshot --fresh` | — |
1583
1703
  | The windows after an input action | `{ context: true }` on an input method, e.g. `click(x, y, [], { context: true })` | `context=True` on an input method, e.g. `click(x, y, context=True)` | `context: true` on an input tool | — | — |
1584
1704
 
1585
1705
  ## Security
package/dist/api.d.ts CHANGED
@@ -2,7 +2,7 @@ import { Agent } from 'undici';
2
2
  import { type SecretStore } from './secret-store.js';
3
3
  export { isSecretStoreRoute } from './secret-errors.js';
4
4
  export declare const DEFAULT_BASE_URL = "https://app.mandala.computer/api/v1";
5
- /** Anthropic's own key, forwarded for the one route that runs a model. */
5
+ /** The caller's provider key, forwarded for the hosted agent routes. */
6
6
  export declare const MODEL_KEY_HEADER = "X-Model-Key";
7
7
  /**
8
8
  * The header every lifecycle call carries so that sending it again cannot do
@@ -90,6 +90,13 @@ export type Bytes = {
90
90
  * than a capture of its screen.
91
91
  */
92
92
  frame?: string;
93
+ /** X-GC-Capture: the live screenshot's reusable capture name. */
94
+ capture?: string;
95
+ /** X-GC-Capture-Size: the capture's own pixels, before cropping or scaling. */
96
+ captureSize?: {
97
+ width: number;
98
+ height: number;
99
+ };
93
100
  };
94
101
  /**
95
102
  * The longest foreground guest exec waits 600 seconds before it answers.
@@ -210,7 +217,7 @@ export declare class Api {
210
217
  * Routes where an empty body IS the answer use `send`.
211
218
  */
212
219
  json<T = unknown>(method: string, path: string, opts?: RequestOptions): Promise<T>;
213
- /** Existing exec decoding plus observed status, used only to confirm optional retention. */
220
+ /** JSON decoding plus observed status, for operations requiring a specific success status. */
214
221
  jsonWithStatus<T>(method: string, path: string, opts?: RequestOptions): Promise<{
215
222
  status: number;
216
223
  value: T;
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAmE,MAAM,QAAQ,CAAC;AAsBhG,OAAO,EAAsB,KAAK,WAAW,EAA0B,MAAM,mBAAmB,CAAC;AAGjG,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,eAAO,MAAM,gBAAgB,wCAAwC,CAAC;AAEtE,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAE9C;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,oBAAoB,CAAC;AAExD,mGAAmG;AACnG,eAAO,MAAM,uBAAuB,QAAyB,CAAC;AAE9D;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,KAAG,MAA+B,CAAC;AAEnF,kCAAkC;AAClC,eAAO,MAAM,kBAAkB,GAAI,KAAK,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAEpE,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,0BAA0B,CAAC;AA2BtD,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;IAC9D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0FAA0F;IAC1F,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD;;;;;;;OAOG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,WAAW,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACjD,CAAC;AA0CF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,SAAU,CAAC;AACnD,6EAA6E;AAC7E,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAC1C,eAAO,MAAM,mBAAmB,OAG9B,CAAC;AAWH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,aAAa,QAAO,OAAO,UAAU,CAAC,KAG7B,CAAC;AAEvB,iDAAiD;AACjD,MAAM,MAAM,QAAQ,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAExD;;;;;;;;;;;GAWG;AACH;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,QAAyE,CAAC;AAEjG,qBAAa,GAAG;;IACd,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAUvB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,MAAyB,EAClC,MAAM,CAAC,EAAE,WAAW,EACpB,OAAO,GAAE,UAAe;IAuD1B;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,GAAG;IAmW1C;;;;;;;;;;;;OAYG;IACG,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;IAe5F,8FAA8F;IACxF,cAAc,CAAC,CAAC,EACpB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,CAAC;IAmBxC,8FAA8F;IACxF,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,YAAY,CAAC;IA2DlB,WAAW,CACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,OAAO,CAAC;IAuBnB;;;;;;OAMG;IACG,IAAI,CAAC,CAAC,GAAG,OAAO,EACpB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAazB;;;;;;;;;;;;;;OAcG;IACG,OAAO,CAAC,CAAC,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC;QAAE,KAAK,EAAE,CAAC,GAAG,SAAS,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAmB/D,kFAAkF;IAC5E,KAAK,CACT,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,cAAmB,EACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,CAAC,GACpD,OAAO,CAAC,KAAK,CAAC;IAkGjB;;;;;;;;;;OAUG;IACH,IAAI,OAAO,IAAI,WAAW,CA6FzB;IAED;;;;;;OAMG;IACI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,cAAc,CAAC,QAAQ,CAAC;CAyG9F;AAyCD;;;;;;;;;GASG;AACH,wBAAiB,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,SAAI,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAQnF;AAkgBD,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAmD3E;AAED,MAAM,MAAM,YAAY,GAAG;IAAE,KAAK,EAAE,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC"}
package/dist/api.js CHANGED
@@ -7,7 +7,7 @@ import { DOCUMENTED_REASONS, secretListOf, secretOf } from './secret-store.js';
7
7
  import { SERVER_VERSION } from './version.js';
8
8
  export { isSecretStoreRoute } from './secret-errors.js';
9
9
  export const DEFAULT_BASE_URL = 'https://app.mandala.computer/api/v1';
10
- /** Anthropic's own key, forwarded for the one route that runs a model. */
10
+ /** The caller's provider key, forwarded for the hosted agent routes. */
11
11
  export const MODEL_KEY_HEADER = 'X-Model-Key';
12
12
  /**
13
13
  * The header every lifecycle call carries so that sending it again cannot do
@@ -66,6 +66,14 @@ function responseMetadata(resp) {
66
66
  wwwAuthenticate: resp.headers.get('www-authenticate') ?? undefined,
67
67
  };
68
68
  }
69
+ function captureSizeFrom(value) {
70
+ if (!value || !/^[1-9]\d*x[1-9]\d*$/.test(value))
71
+ return undefined;
72
+ const [width, height] = value.split('x').map(Number);
73
+ return Number.isSafeInteger(width) && Number.isSafeInteger(height)
74
+ ? { width, height }
75
+ : undefined;
76
+ }
69
77
  /**
70
78
  * How much of an event stream will be held while waiting for a boundary.
71
79
  *
@@ -574,15 +582,16 @@ export class Api {
574
582
  }
575
583
  return body;
576
584
  }
577
- /** Existing exec decoding plus observed status, used only to confirm optional retention. */
585
+ /** JSON decoding plus observed status, for operations requiring a specific success status. */
578
586
  async jsonWithStatus(method, path, opts = {}) {
579
587
  return this.#guard(method, path, opts, () => this.#jsonWithStatusRaw(method, path, opts));
580
588
  }
581
589
  async #jsonWithStatusRaw(method, path, opts = {}) {
582
590
  const resp = await this.#fetch(method, path, opts);
583
591
  const value = await this.#decode(resp, method, path, opts.signal ?? this.#signal);
584
- if (value === undefined || value === null)
585
- throw new MandalaError('Expected an exec response');
592
+ if (value === undefined || value === null) {
593
+ throw new MandalaError(`${method} ${path} answered ${resp.status} without the expected JSON response; the outcome could not be confirmed`);
594
+ }
586
595
  return { status: resp.status, value };
587
596
  }
588
597
  /** Complete bounded responses for immutable retained protocols; never a successful prefix. */
@@ -754,6 +763,8 @@ export class Api {
754
763
  unrangeable: (resp.headers.get('accept-ranges') ?? '').trim().toLowerCase() === 'none',
755
764
  window,
756
765
  frame: resp.headers.get('x-gc-frame')?.trim().toLowerCase() || undefined,
766
+ capture: resp.headers.get('x-gc-capture')?.match(/^[a-f0-9]{16}$/)?.[0],
767
+ captureSize: captureSizeFrom(resp.headers.get('x-gc-capture-size')),
757
768
  };
758
769
  }
759
770
  // --- the account's secret store (OPL-4984) ------------------------------