mandala-computer-mcp 0.1.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +544 -0
  3. package/dist/api.d.ts +186 -0
  4. package/dist/api.d.ts.map +1 -0
  5. package/dist/api.js +932 -0
  6. package/dist/api.js.map +1 -0
  7. package/dist/cli.d.ts +55 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +292 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/errors.d.ts +560 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +873 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/events.d.ts +406 -0
  16. package/dist/events.d.ts.map +1 -0
  17. package/dist/events.js +1679 -0
  18. package/dist/events.js.map +1 -0
  19. package/dist/format.d.ts +125 -0
  20. package/dist/format.d.ts.map +1 -0
  21. package/dist/format.js +180 -0
  22. package/dist/format.js.map +1 -0
  23. package/dist/http.d.ts +46 -0
  24. package/dist/http.d.ts.map +1 -0
  25. package/dist/http.js +792 -0
  26. package/dist/http.js.map +1 -0
  27. package/dist/index.d.ts +13 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +12 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/paths.d.ts +394 -0
  32. package/dist/paths.d.ts.map +1 -0
  33. package/dist/paths.js +677 -0
  34. package/dist/paths.js.map +1 -0
  35. package/dist/server.d.ts +18 -0
  36. package/dist/server.d.ts.map +1 -0
  37. package/dist/server.js +97 -0
  38. package/dist/server.js.map +1 -0
  39. package/dist/session.d.ts +78 -0
  40. package/dist/session.d.ts.map +1 -0
  41. package/dist/session.js +166 -0
  42. package/dist/session.js.map +1 -0
  43. package/dist/stdio.d.ts +11 -0
  44. package/dist/stdio.d.ts.map +1 -0
  45. package/dist/stdio.js +43 -0
  46. package/dist/stdio.js.map +1 -0
  47. package/dist/tools/agent.d.ts +16 -0
  48. package/dist/tools/agent.d.ts.map +1 -0
  49. package/dist/tools/agent.js +147 -0
  50. package/dist/tools/agent.js.map +1 -0
  51. package/dist/tools/computers.d.ts +3 -0
  52. package/dist/tools/computers.d.ts.map +1 -0
  53. package/dist/tools/computers.js +1037 -0
  54. package/dist/tools/computers.js.map +1 -0
  55. package/dist/tools/events.d.ts +3 -0
  56. package/dist/tools/events.d.ts.map +1 -0
  57. package/dist/tools/events.js +1077 -0
  58. package/dist/tools/events.js.map +1 -0
  59. package/dist/tools/guest.d.ts +3 -0
  60. package/dist/tools/guest.d.ts.map +1 -0
  61. package/dist/tools/guest.js +761 -0
  62. package/dist/tools/guest.js.map +1 -0
  63. package/dist/tools/input.d.ts +3 -0
  64. package/dist/tools/input.d.ts.map +1 -0
  65. package/dist/tools/input.js +240 -0
  66. package/dist/tools/input.js.map +1 -0
  67. package/dist/tools/snapshots.d.ts +3 -0
  68. package/dist/tools/snapshots.d.ts.map +1 -0
  69. package/dist/tools/snapshots.js +333 -0
  70. package/dist/tools/snapshots.js.map +1 -0
  71. package/dist/tools/templates.d.ts +3 -0
  72. package/dist/tools/templates.d.ts.map +1 -0
  73. package/dist/tools/templates.js +492 -0
  74. package/dist/tools/templates.js.map +1 -0
  75. package/dist/tools/types.d.ts +18 -0
  76. package/dist/tools/types.d.ts.map +1 -0
  77. package/dist/tools/types.js +2 -0
  78. package/dist/tools/types.js.map +1 -0
  79. package/dist/tools/webhooks.d.ts +3 -0
  80. package/dist/tools/webhooks.d.ts.map +1 -0
  81. package/dist/tools/webhooks.js +260 -0
  82. package/dist/tools/webhooks.js.map +1 -0
  83. package/package.json +59 -0
@@ -0,0 +1,260 @@
1
+ import { z } from 'zod';
2
+ import { NotFoundError } from '../errors.js';
3
+ import { guarded, refused, said } from '../format.js';
4
+ import * as P from '../paths.js';
5
+ /**
6
+ * The webhooks resource (platform OPL-4300), mirrored as the CRUD and nothing
7
+ * more (OPL-4306). This server never RECEIVES a webhook — it has no endpoint
8
+ * for the platform to POST to, and a model taking turns has nowhere to be
9
+ * woken — so there is no `verify` here, and deliberately so: the design says in
10
+ * as many words that the MCP server and the CLI get the CRUD only. What a
11
+ * model does with these is set up the endpoint a CI job or a queue worker will
12
+ * be woken at, read whether deliveries are reaching it, and hand the secret
13
+ * over to whoever runs it.
14
+ *
15
+ * Every tool here is account-scoped, like `get_usage` and `get_retention`: a
16
+ * subscription belongs to the account and receives events from many computers,
17
+ * so none of them takes a `computer_id` and none of them consults the session's
18
+ * selected computer. A `computers` FILTER is a different thing and is a body
19
+ * field.
20
+ */
21
+ const webhookIdArg = {
22
+ webhook_id: z.string().describe('The subscription id — `whk-` and sixteen hex characters.'),
23
+ };
24
+ /**
25
+ * The types a webhook can subscribe to, for the tool descriptions only.
26
+ *
27
+ * The socket's vocabulary less `file.changed`, which a webhook never carries:
28
+ * a file watch is a connection parameter on the socket, and a webhook has no
29
+ * connection to set one on. Not an enum on the argument, for the reason
30
+ * `wait_for_event` gives about its own list: the platform refuses an unknown
31
+ * type with a 400 that lists the current vocabulary, so a closed enum here
32
+ * would refuse a type the platform had started accepting.
33
+ */
34
+ const EVENT_TYPES = [
35
+ 'window.opened',
36
+ 'window.closed',
37
+ 'window.focused',
38
+ 'window.blurred',
39
+ 'clipboard.changed',
40
+ 'process.exited',
41
+ 'computer.idle',
42
+ 'computer.ready',
43
+ 'computer.started',
44
+ 'computer.stopped',
45
+ 'computer.suspended',
46
+ ];
47
+ /**
48
+ * The four fields a create and an update share, described for the one being
49
+ * built. Omission means two different things on the two routes — "every
50
+ * type" on a create, "leave the filter as it is" on an update — and a model
51
+ * fills a field from ITS description, not from the tool's, so each has to say
52
+ * which it means. One shared copy said the create meaning on both.
53
+ */
54
+ const filterArgs = (on) => {
55
+ const omit = on === 'create'
56
+ ? 'Omit or send [] for every'
57
+ : 'Omit to keep the current filter; send [] to clear it to every';
58
+ return {
59
+ description: z.string().optional().describe('Free text for the listing, up to 200 characters.'),
60
+ events: z
61
+ .array(z.string())
62
+ .optional()
63
+ .describe(`Event types to deliver: ${EVENT_TYPES.join(', ')}. ${omit} type. file.changed is never delivered to a webhook. An unknown type is refused by the platform with the current list.`),
64
+ computers: z
65
+ .array(z.string())
66
+ .optional()
67
+ .describe(`Computer ids to deliver for, up to 64. ${omit} computer the key can see. Not checked against your computers — a subscription may name a computer you are about to create.`),
68
+ enabled: z.boolean().optional().describe('Whether deliveries are made.'),
69
+ };
70
+ };
71
+ const asRecord = (v) => v !== null && typeof v === 'object' && !Array.isArray(v) ? v : {};
72
+ /**
73
+ * One subscription's health in a clause, for the sentence in front of a
74
+ * listing or a read. Says the thing a model acts on — whether deliveries are
75
+ * being made, and if not, whose decision that was — rather than restating the
76
+ * timestamps underneath it.
77
+ */
78
+ function health(w) {
79
+ if (w.enabled === false) {
80
+ return w.disabled_reason === 'failing'
81
+ ? 'DISABLED BY THE PLATFORM after a day of failures — update_webhook with enabled: true to start it again'
82
+ : 'disabled by you';
83
+ }
84
+ const success = instant(w.last_success_at);
85
+ const failure = instant(w.last_failure_at);
86
+ if (success !== undefined && failure === undefined)
87
+ return 'healthy';
88
+ if (failure !== undefined && success === undefined) {
89
+ return `no delivery has ever been accepted (newest attempt: ${attempt(w.last_status)})`;
90
+ }
91
+ if (failure !== undefined && success !== undefined && failure > success) {
92
+ return `failing since its last success (newest attempt: ${attempt(w.last_status)})`;
93
+ }
94
+ if (success !== undefined)
95
+ return 'healthy';
96
+ return 'nothing delivered yet';
97
+ }
98
+ /**
99
+ * A timestamp as a number, or undefined for anything that is not one. Parsed
100
+ * rather than compared as strings: two RFC 3339 spellings of nearby instants —
101
+ * one with fractional seconds and one without — do not sort by the clock, and
102
+ * a "healthy" read off that would be wrong about the newest attempt.
103
+ */
104
+ function instant(v) {
105
+ if (typeof v !== 'string' || !v)
106
+ return undefined;
107
+ const t = Date.parse(v);
108
+ return Number.isNaN(t) ? undefined : t;
109
+ }
110
+ const attempt = (status) => typeof status === 'number' ? `HTTP ${status}` : 'no answer';
111
+ /**
112
+ * The sentence in front of a create or a rotate — the two answers that carry
113
+ * the secret, and the only two that ever will. Said in the first line rather
114
+ * than left to the schema, because a model that files the JSON away and reads
115
+ * it back later has, by then, lost the one thing that cannot be re-read.
116
+ */
117
+ const shownOnce = (verb, w) => `${verb} ${w.id ?? 'the subscription'}. THE SECRET IN THIS ANSWER IS SHOWN ONCE and cannot be read back: store it now, or hand it to whoever runs ${w.url ?? 'the endpoint'}. Every delivery is signed with it (Standard Webhooks v1: webhook-id, webhook-timestamp, webhook-signature over the raw body). rotate_webhook_secret is the only way to get another.`;
118
+ /** The states of a delivery listing, counted, so the line says what is stuck. */
119
+ function deliveriesLine(id, list) {
120
+ if (!list.length) {
121
+ return `No deliveries recorded for ${id}. Either nothing it subscribes to has happened, or it was created too recently — test_webhook queues one you can watch for here.`;
122
+ }
123
+ const counts = new Map();
124
+ for (const d of list)
125
+ counts.set(d.state ?? 'unknown', (counts.get(d.state ?? 'unknown') ?? 0) + 1);
126
+ const summary = [...counts].map(([state, n]) => `${n} ${state}`).join(', ');
127
+ const newest = list[0];
128
+ const outcome = newest.state === 'delivered'
129
+ ? 'accepted'
130
+ : `${newest.state}${newest.last_error ? ` (${newest.last_error})` : ''}`;
131
+ return (`${list.length} deliveries for ${id}, newest first: ${summary}. The newest is a ${newest.event_type ?? 'unknown'} event, ${outcome} after ${newest.attempts ?? 0} attempt(s). ` +
132
+ 'exhausted means eight attempts failed over about fourteen hours and it will not be retried; pending and in_flight are still being tried.');
133
+ }
134
+ export const registerWebhooks = (server, session) => {
135
+ server.registerTool('list_webhooks', {
136
+ title: 'List webhook subscriptions',
137
+ description: 'Every webhook subscription on the account, with its health: whether it is enabled, when its endpoint last accepted a delivery and when one last failed. A webhook is an HTTPS endpoint the platform POSTs events to — the other transport for the same events wait_for_event reads, for a CI job or a queue worker that wants to be woken rather than to wait. Never carries a secret: that is shown once, by create_webhook or rotate_webhook_secret. A workspace-scoped key sees only the subscriptions confined to that workspace.',
138
+ inputSchema: {},
139
+ annotations: { readOnlyHint: true },
140
+ }, (_args, extra) => guarded(async () => {
141
+ const body = await session.api.with(extra.signal).json('GET', P.WEBHOOKS);
142
+ const list = Array.isArray(body) ? body : [];
143
+ if (!list.length) {
144
+ return said('No webhook subscriptions on this account. create_webhook makes one.', body);
145
+ }
146
+ const lines = list.map((w) => `${w.id ?? '?'} → ${w.url ?? '?'}: ${health(w)}`);
147
+ return said(`${list.length} webhook subscription${list.length === 1 ? '' : 's'}, oldest first:\n${lines.join('\n')}`, body);
148
+ }));
149
+ server.registerTool('create_webhook', {
150
+ title: 'Subscribe an endpoint to this account’s events',
151
+ description: 'Subscribe an HTTPS endpoint to this account’s events. THE ANSWER CARRIES THE SIGNING SECRET ONCE — it is not readable again, so store it or hand it over before doing anything else. Each event is POSTed as the same JSON object wait_for_event hands you, byte for byte, signed with Standard Webhooks v1 headers (webhook-id, webhook-timestamp, webhook-signature); the receiver should verify the raw body, acknowledge with a 2xx before doing the work, and refuse a timestamp more than 300 seconds off. Failed deliveries are retried eight times over about fourteen hours; an endpoint that keeps failing for a day is disabled. The url must be https, must not carry a username or password, and must resolve to a public address — a private or loopback address is refused. Paid plans allow ten subscriptions; an account with no plan allows none.',
152
+ inputSchema: {
153
+ url: z
154
+ .string()
155
+ .describe('Where to POST. https:// only, no username or password, resolving to a public address. A port other than 443 is fine.'),
156
+ ...filterArgs('create'),
157
+ },
158
+ }, (args, extra) => guarded(async () => {
159
+ const w = asRecord(await session.api
160
+ .with(extra.signal)
161
+ .json('POST', P.WEBHOOKS, { body: P.webhookBody(args) }));
162
+ return said(shownOnce('Created', w), w);
163
+ }));
164
+ server.registerTool('get_webhook', {
165
+ title: 'Read a webhook subscription',
166
+ description: 'One subscription with its health: whether it is enabled and why not if not, when the endpoint last accepted a delivery, when one last failed, and the status of the newest attempt. Never the secret. For the individual deliveries and what became of each, list_webhook_deliveries.',
167
+ inputSchema: webhookIdArg,
168
+ annotations: { readOnlyHint: true },
169
+ }, ({ webhook_id }, extra) => guarded(async () => {
170
+ const w = asRecord(await session.api.with(extra.signal).json('GET', P.webhook(webhook_id)));
171
+ return said(`${w.id ?? webhook_id} → ${w.url ?? '?'}: ${health(w)}.`, w);
172
+ }));
173
+ server.registerTool('update_webhook', {
174
+ title: 'Change a webhook subscription',
175
+ description: 'Change the endpoint, the description, the filters, or whether it is enabled. Fields you leave out are kept as they are; name at least one. A new url is checked exactly as on create. enabled: true clears a disable the platform imposed for failures and starts fresh; enabled: false stops deliveries and records that you chose to. The secret does not change — rotate_webhook_secret is for that.',
176
+ inputSchema: {
177
+ ...webhookIdArg,
178
+ url: z
179
+ .string()
180
+ .optional()
181
+ .describe('A new endpoint, checked exactly as on create: https, no credentials, public address.'),
182
+ ...filterArgs('update'),
183
+ },
184
+ annotations: { idempotentHint: true },
185
+ }, ({ webhook_id, ...fields }, extra) => guarded(async () => {
186
+ const body = P.webhookBody(fields);
187
+ if (!Object.keys(body).length) {
188
+ return refused('Nothing to change: name at least one of url, description, events, computers or enabled. The platform refuses an empty update, so nothing was sent.');
189
+ }
190
+ const w = asRecord(await session.api
191
+ .with(extra.signal)
192
+ .json('PATCH', P.webhook(webhook_id), { body }));
193
+ return said(`Updated ${w.id ?? webhook_id} → ${w.url ?? '?'}: ${health(w)}.`, w);
194
+ }));
195
+ server.registerTool('rotate_webhook_secret', {
196
+ title: 'Rotate a webhook’s signing secret',
197
+ description: 'Mint a new signing secret for a subscription. THE ANSWER CARRIES IT ONCE, like create_webhook. The old secret goes on being honoured for 24 hours — every delivery in that window carries two signatures on the one webhook-signature header, new first, so a receiver that accepts either passes throughout — which is the window to get the new one deployed. Rotating again inside it replaces the previous secret rather than keeping three. Do this when a secret has leaked or when whoever held it has moved on.',
198
+ inputSchema: webhookIdArg,
199
+ }, ({ webhook_id }, extra) => guarded(async () => {
200
+ const w = asRecord(await session.api
201
+ .with(extra.signal)
202
+ .json('POST', P.webhookAction(webhook_id, 'rotate')));
203
+ return said(shownOnce('Rotated the secret on', w), w);
204
+ }));
205
+ server.registerTool('test_webhook', {
206
+ title: 'Send a test delivery',
207
+ description: 'Queue one signed delivery of a synthetic webhook.test event through the ordinary path, so it is signed, retried and recorded exactly as a real one. The answer is the delivery record, ACCEPTED rather than finished: the endpoint has not been called yet when this returns. Read what it said back with list_webhook_deliveries a little later — a first attempt goes out within seconds, and a failed one is retried after 30 seconds. A disabled subscription is refused; enable it first with update_webhook.',
208
+ inputSchema: webhookIdArg,
209
+ }, ({ webhook_id }, extra) => guarded(async () => {
210
+ const d = asRecord(await session.api
211
+ .with(extra.signal)
212
+ .json('POST', P.webhookAction(webhook_id, 'test')));
213
+ return said(`Queued test delivery ${d.id ?? ''} to ${webhook_id}. It is ${d.state ?? 'pending'}: the endpoint has not been called yet. Call list_webhook_deliveries for ${webhook_id} in a few seconds to read what it answered.`, d);
214
+ }));
215
+ server.registerTool('list_webhook_deliveries', {
216
+ title: 'List a webhook’s deliveries',
217
+ description: 'The newest hundred deliveries to one subscription, newest first, each with its state (pending, in_flight, delivered, exhausted or dropped), its attempt count, and the HTTP status or one-line error of its newest attempt. This is where a delivery that ran out of attempts shows up — nothing is dropped silently. Finished deliveries are kept for seven days. Each carries the event’s cursor, which is what to pass as since to the socket to read on from that point.',
218
+ inputSchema: webhookIdArg,
219
+ annotations: { readOnlyHint: true },
220
+ }, ({ webhook_id }, extra) => guarded(async () => {
221
+ const body = await session.api
222
+ .with(extra.signal)
223
+ .json('GET', P.webhookAction(webhook_id, 'deliveries'));
224
+ const list = Array.isArray(body) ? body : [];
225
+ return said(deliveriesLine(webhook_id, list), body);
226
+ }));
227
+ server.registerTool('delete_webhook', {
228
+ title: 'Delete a webhook subscription',
229
+ description: 'Remove a subscription and every delivery record it holds, pending ones included. Nothing more is sent to the endpoint. Irreversible: a new subscription to the same url gets a new id and a new secret. To stop deliveries without losing the record, update_webhook with enabled: false instead.',
230
+ inputSchema: {
231
+ ...webhookIdArg,
232
+ confirm: z
233
+ .literal(true)
234
+ .describe('Must be true. This removes the subscription and its delivery history.'),
235
+ },
236
+ annotations: { destructiveHint: true, idempotentHint: true },
237
+ }, ({ webhook_id }, extra) => guarded(async () => {
238
+ let res;
239
+ try {
240
+ res = await session.api.with(extra.signal).send('DELETE', P.webhook(webhook_id));
241
+ }
242
+ catch (err) {
243
+ // A 404 is the state this call asked for, and this tool is annotated
244
+ // `idempotentHint`, so the retry after a lost 2xx is one a client is
245
+ // invited to make. Said as a success but not as "Deleted": the same
246
+ // 404 answers an id that was never on this account — the platform
247
+ // will not say whether a subscription exists outside your scope —
248
+ // and "deleted" over a mistyped id leaves a real subscription
249
+ // delivering. delete_computer and delete_snapshot answer the same way.
250
+ if (!(err instanceof NotFoundError))
251
+ throw err;
252
+ return said(`Nothing was deleted: the platform has no webhook with the id ${webhook_id} on this account. ` +
253
+ 'Either it was already removed — if this is a retry, the first call is the one that did it — or ' +
254
+ 'the id is not one of yours, in which case NO subscription has been touched and a real one may ' +
255
+ 'still be delivering under the id you meant. list_webhooks says which of the two this is.');
256
+ }
257
+ return said(`Deleted ${webhook_id}. Nothing more will be sent to its endpoint, and its delivery history is gone with it.`, res);
258
+ }));
259
+ };
260
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/tools/webhooks.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "mandala-computer-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Mandala Computer — cloud desktops for AI agents",
5
+ "keywords": [
6
+ "mcp",
7
+ "model-context-protocol",
8
+ "mandala",
9
+ "computer-use",
10
+ "cloud-desktop",
11
+ "ai-agents"
12
+ ],
13
+ "license": "MIT",
14
+ "homepage": "https://mandala.computer",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/mandalacomputer/mcp.git"
18
+ },
19
+ "bugs": "https://github.com/mandalacomputer/mcp/issues",
20
+ "type": "module",
21
+ "bin": {
22
+ "mandala-computer-mcp": "dist/cli.js"
23
+ },
24
+ "exports": {
25
+ ".": "./dist/index.js"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md",
30
+ "LICENSE"
31
+ ],
32
+ "engines": {
33
+ "node": ">=20.3.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.build.json",
37
+ "dev": "tsc -p tsconfig.build.json --watch",
38
+ "test": "vitest run && node scripts/check-surface.mjs",
39
+ "test:watch": "vitest",
40
+ "typecheck": "tsc --noEmit",
41
+ "lint": "biome check .",
42
+ "format": "biome check --write .",
43
+ "prepublishOnly": "npm run build",
44
+ "check:surface": "node scripts/check-surface.mjs"
45
+ },
46
+ "dependencies": {
47
+ "@modelcontextprotocol/sdk": "^1.30.0",
48
+ "express": "^5.1.0",
49
+ "undici": "^6.28.0",
50
+ "zod": "^3.25.76"
51
+ },
52
+ "devDependencies": {
53
+ "@biomejs/biome": "^2.3.0",
54
+ "@types/express": "^5.0.0",
55
+ "@types/node": "^22.10.0",
56
+ "typescript": "^5.7.0",
57
+ "vitest": "^3.2.0"
58
+ }
59
+ }