@rebind.gg/mcp-server 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/index.ts +5 -6
- package/src/rebind.d.luau +73 -18
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@ Connects, takes a capture, and reports the display — the fastest way to catch
|
|
|
55
55
|
| `type` | Type text into the focused element. |
|
|
56
56
|
| `key` | Press a key or combo, e.g. `Enter`, `LCtrl+L`, `LAlt+Tab`. |
|
|
57
57
|
| `scroll` | Scroll at the cursor. Positive scrolls down, negative up. `unit` is `wheel` (default, fine wheel clicks) or `page` (one PageDown or PageUp per unit, capped at 10). |
|
|
58
|
-
| `read_page` | Extract the focused browser's current page as structured text (URL, forms, interactive elements, plain text) via an address-bar bookmarklet; the full dump, including cleaned HTML, lands in the clipboard. The result is read back through AppleScript (`URL of active tab of front window`), so the relay host
|
|
58
|
+
| `read_page` | Extract the focused browser's current page as structured text (URL, forms, interactive elements, plain text) via an address-bar bookmarklet; the full dump, including cleaned HTML, lands in the clipboard. The result is read back through AppleScript (`URL of active tab of front window`), so the tool is registered only when the relay host is macOS, and the front browser must answer that query. Safari is detected but blocks the bookmarklet path. |
|
|
59
59
|
| `meditate` | Research a problem page until a reasoning model has the data to solve it: fetches the URL directly, pulls the script bundles behind a JS shell so its API endpoints are visible, fetches those endpoints and assets, and reads the live page with vision. The browser steps (rendering a JS shell, same-origin fetches through the page, and the vision pass) need a macOS relay; elsewhere it reads pages over HTTP only. Returns a markdown dossier plus JSON `{error, problem, requirements, plan, submittable, form, live_captcha_hint, confidence, sources, assets, pending_fetch, notes, cost_usd}`. `error` is non-null when no problem could be identified or the page could not be read; partial data is still returned. Gated behind `REBIND_ALLOW_DELEGATION=1` (spends OpenRouter credits). See the pipeline below. |
|
|
60
60
|
| `run_lua` | Run a Luau script on the connected machine and return its `return` value as JSON — the fast path for any deterministic sequence (launch apps, place windows, shell commands, pixel search). |
|
|
61
61
|
| `lua_docs` | Full Luau SDK type definitions for `run_lua`. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebind.gg/mcp-server",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "MCP server exposing Rebind as computer-use tools: screenshot, verified click, type, key, scroll, and window control over the Remote Control protocol.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/index.ts
CHANGED
|
@@ -98,8 +98,6 @@ function versusMessages(
|
|
|
98
98
|
// asked to re-emit the whole growing dossier blows the model's output cap and
|
|
99
99
|
// truncates the JSON; splitting keeps every response small and bounds cost.
|
|
100
100
|
|
|
101
|
-
/** stop the loop once the model reports at least this much confidence */
|
|
102
|
-
const MEDITATE_CONFIDENT = 0.8;
|
|
103
101
|
/** max distinct pages read (problem page + follows) before the loop must stop */
|
|
104
102
|
const MEDITATE_MAX_PAGES = 10;
|
|
105
103
|
// Budgets sized for a 1M-token context, not a 4k one. These were tight enough
|
|
@@ -980,9 +978,10 @@ return { ok = true, proc = proc }
|
|
|
980
978
|
},
|
|
981
979
|
async ({ handle }) => {
|
|
982
980
|
// handle-based activation can raise without focusing on macOS; fall back
|
|
983
|
-
// to app-name activation (App.Activate,
|
|
984
|
-
//
|
|
985
|
-
// machine than the relay, so process.platform is
|
|
981
|
+
// to app-name activation (App.Activate, pcall-guarded because it raises
|
|
982
|
+
// where the relay has no App backend). Decided relay-side: this process
|
|
983
|
+
// may run on a different machine than the relay, so process.platform is
|
|
984
|
+
// the wrong signal.
|
|
986
985
|
const r = (await client.luaExec(`
|
|
987
986
|
local h = ${handle}
|
|
988
987
|
Window.Activate(h)
|
|
@@ -1289,7 +1288,7 @@ return { ok = Window.IsActive(h), name = name }
|
|
|
1289
1288
|
"meditate",
|
|
1290
1289
|
{
|
|
1291
1290
|
description:
|
|
1292
|
-
"Research a problem page until enough data is collected to solve it. Fetches `url` directly (relay-side curl) and, when the response is a JS shell, pulls its script bundles so the API endpoints behind the page are visible; falls back to extracting the rendered page in a browser when a fetch cannot see the content. A reasoning model then iterates: identify the problem, fetch the URLs and API endpoints that close information gaps, download required assets, until it
|
|
1291
|
+
"Research a problem page until enough data is collected to solve it. Fetches `url` directly (relay-side curl) and, when the response is a JS shell, pulls its script bundles so the API endpoints behind the page are visible; falls back to extracting the rendered page in a browser when a fetch cannot see the content. A reasoning model then iterates: identify the problem, fetch the URLs and API endpoints that close information gaps, download required assets, until it has nothing left to fetch or hits max_rounds. A final pass renders everything into a solving dossier. " +
|
|
1293
1292
|
"Returns the dossier as markdown plus a JSON plan {error, problem, requirements, plan, confidence, sources, assets, pending_fetch, notes, cost_usd}. `error` is non-null (with the partial data still returned, never thrown) when no clear problem is identifiable or the browser could not be driven. Downloaded `assets` paths are on the RELAY host. " +
|
|
1294
1293
|
"On a macOS relay it also drives the real browser (takes over keyboard/clipboard for the duration) to render a JS shell, fetch same-origin URLs through the page, and read the live captcha; elsewhere it reads pages over HTTP only. Spends OpenRouter credits. Refuses non-public URLs (loopback/private/link-local). Safari cannot be driven — pass `browser` to name another.",
|
|
1295
1294
|
inputSchema: {
|
package/src/rebind.d.luau
CHANGED
|
@@ -35,6 +35,14 @@ export type ServerHandle = {
|
|
|
35
35
|
Stop: (self: ServerHandle) -> (),
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
-- UDP: socket handle returned by Net.UDPListen. SendTo sends from the bound
|
|
39
|
+
-- address and returns false when the send fails or the socket is stopped.
|
|
40
|
+
export type UdpHandle = {
|
|
41
|
+
port: number,
|
|
42
|
+
SendTo: (self: UdpHandle, ip: string, port: number, bytes: string) -> boolean,
|
|
43
|
+
Stop: (self: UdpHandle) -> (),
|
|
44
|
+
}
|
|
45
|
+
|
|
38
46
|
-- WebSocket: server-side per-connection handle passed to OnConnect/OnMessage/OnClose.
|
|
39
47
|
-- `id` is a monotonic identifier unique to this connection.
|
|
40
48
|
export type WsClient = {
|
|
@@ -112,6 +120,19 @@ export type WindowPos = {
|
|
|
112
120
|
height: number,
|
|
113
121
|
}
|
|
114
122
|
|
|
123
|
+
-- the input device a key, button, move or scroll came from. hooks get nil
|
|
124
|
+
-- where the source cannot tell devices apart (Windows and macOS software mode)
|
|
125
|
+
export type InputDevice = {
|
|
126
|
+
id: string,
|
|
127
|
+
name: string,
|
|
128
|
+
nickname: string?,
|
|
129
|
+
kind: "keyboard" | "mouse" | "other",
|
|
130
|
+
vid: string,
|
|
131
|
+
pid: string,
|
|
132
|
+
source: "vm" | "host",
|
|
133
|
+
exact: boolean,
|
|
134
|
+
}
|
|
135
|
+
|
|
115
136
|
export type MousePos = {
|
|
116
137
|
x: number,
|
|
117
138
|
y: number,
|
|
@@ -224,9 +245,10 @@ export type UiProxy = { [string]: any }
|
|
|
224
245
|
|
|
225
246
|
-- bind config for table-style binding
|
|
226
247
|
export type BindConfig = {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
248
|
+
device: string?, -- nickname or id: the bind answers only to that device
|
|
249
|
+
when: ((device: InputDevice?) -> boolean)?,
|
|
250
|
+
action: ((device: InputDevice?) -> boolean?)?,
|
|
251
|
+
release: ((device: InputDevice?) -> ())?,
|
|
230
252
|
}
|
|
231
253
|
|
|
232
254
|
-- runtime identity table
|
|
@@ -300,6 +322,20 @@ declare System: {
|
|
|
300
322
|
|
|
301
323
|
-- hid namespace
|
|
302
324
|
|
|
325
|
+
-- a joypad state; every field is optional and defaults to neutral. buttons
|
|
326
|
+
-- lists pressed buttons 1-32, hat is 0 (up) to 7 clockwise (nil = centered),
|
|
327
|
+
-- x/y/z/rz are -1..1 (0 = center), slider and dial are 0..1.
|
|
328
|
+
export type JoypadState = {
|
|
329
|
+
buttons: { number }?,
|
|
330
|
+
hat: number?,
|
|
331
|
+
x: number?,
|
|
332
|
+
y: number?,
|
|
333
|
+
z: number?,
|
|
334
|
+
rz: number?,
|
|
335
|
+
slider: number?,
|
|
336
|
+
dial: number?,
|
|
337
|
+
}
|
|
338
|
+
|
|
303
339
|
declare HID: {
|
|
304
340
|
Down: (code: string) -> (),
|
|
305
341
|
Up: (code: string) -> (),
|
|
@@ -319,6 +355,15 @@ declare HID: {
|
|
|
319
355
|
Scroll: (amount: number) -> (),
|
|
320
356
|
SetMouseMode: (mode: string) -> (),
|
|
321
357
|
GetMouseMode: () -> string,
|
|
358
|
+
-- keyboard HID usage for a key name, or nil (media keys return nil). Down,
|
|
359
|
+
-- Up, Press and Combo also accept "usage:N" (decimal or 0x hex, 0x04-0xE7).
|
|
360
|
+
Usage: (name: string) -> number?,
|
|
361
|
+
-- set the whole joypad state (last write wins across scripts). Needs a
|
|
362
|
+
-- Rebind Link whose USB profile has a joypad; raises otherwise. Keyboard
|
|
363
|
+
-- and mouse calls raise the same way when the profile leaves them out.
|
|
364
|
+
Joypad: (state: JoypadState?) -> (),
|
|
365
|
+
-- back to neutral; the relay also does this when a script stops or errors
|
|
366
|
+
JoypadReset: () -> (),
|
|
322
367
|
}
|
|
323
368
|
|
|
324
369
|
-- input namespace
|
|
@@ -354,7 +399,7 @@ declare Bind: typeof(setmetatable({} :: {
|
|
|
354
399
|
Toggle: (key: string, uiId: string) -> BindHandle,
|
|
355
400
|
Remap: (from: string, to: string) -> BindHandle,
|
|
356
401
|
}, {} :: {
|
|
357
|
-
__call: (self: any, key: string, config: (() -> boolean?) | BindConfig) -> BindHandle,
|
|
402
|
+
__call: (self: any, key: string, config: ((device: InputDevice?) -> boolean?) | BindConfig) -> BindHandle,
|
|
358
403
|
}))
|
|
359
404
|
|
|
360
405
|
-- timer namespace
|
|
@@ -374,7 +419,8 @@ declare Macro: {
|
|
|
374
419
|
StopAll: () -> (),
|
|
375
420
|
Record: (options: RecordOpts?) -> (),
|
|
376
421
|
Finish: () -> { MacroAction },
|
|
377
|
-
-- the saved-macro format: modeline,
|
|
422
|
+
-- the saved-macro format: a `macro=true` modeline, then `return` of the
|
|
423
|
+
-- actions. require() of a saved macro returns the actions.
|
|
378
424
|
ToScript: (macro: { MacroAction }, name: string) -> string,
|
|
379
425
|
Stream: (macro: { MacroAction }) -> (),
|
|
380
426
|
Abort: () -> (),
|
|
@@ -471,6 +517,8 @@ export type ImageMatch = {
|
|
|
471
517
|
height: number,
|
|
472
518
|
}
|
|
473
519
|
|
|
520
|
+
-- pixel reads are limited by a screen:target or screen:none permission entry
|
|
521
|
+
|
|
474
522
|
declare Screen: {
|
|
475
523
|
GetPixelColor: (x: number?, y: number?) -> string,
|
|
476
524
|
-- reads the published frame. regions up to 200k physical pixels answer on the
|
|
@@ -519,9 +567,12 @@ declare Window: {
|
|
|
519
567
|
}
|
|
520
568
|
|
|
521
569
|
-- app namespace: application-level control (Keyboard Maestro's Application
|
|
522
|
-
-- Control). names match case-insensitively by app display name
|
|
523
|
-
-- Activate are permission-free; Hide/Quit/IsHidden drive an
|
|
524
|
-
-- prompt for macOS Automation permission on first use.
|
|
570
|
+
-- Control). macOS: names match case-insensitively by app display name;
|
|
571
|
+
-- Front/IsRunning/Activate are permission-free; Hide/Quit/IsHidden drive an
|
|
572
|
+
-- AppleEvent and prompt for macOS Automation permission on first use.
|
|
573
|
+
-- Windows: names are executable names (case-insensitive, ".exe" optional);
|
|
574
|
+
-- Activate focuses a running app and does not launch one; Quit closes its
|
|
575
|
+
-- windows; Hide/IsHidden raise. Linux: every call raises.
|
|
525
576
|
|
|
526
577
|
export type AppInfo = {
|
|
527
578
|
name: string,
|
|
@@ -538,7 +589,7 @@ declare App: {
|
|
|
538
589
|
Quit: (name: string) -> (),
|
|
539
590
|
}
|
|
540
591
|
|
|
541
|
-
-- net namespace
|
|
592
|
+
-- net namespace (permission: net, or net:<host> for the client calls and WSConnect)
|
|
542
593
|
|
|
543
594
|
declare Net: {
|
|
544
595
|
Get: (url: string, headers: { [string]: string }?, options: HttpOptions?) -> HttpResponse,
|
|
@@ -551,6 +602,10 @@ declare Net: {
|
|
|
551
602
|
Listen: (port: number, handler: (request: HttpRequest) -> HttpResponseSpec | string) -> ServerHandle,
|
|
552
603
|
WSListen: (port: number, handlers: WsListenHandlers) -> WsServerHandle,
|
|
553
604
|
WSConnect: (url: string, handlers: WsConnectHandlers) -> WsConnectHandle,
|
|
605
|
+
-- bind a UDP socket; handler receives each datagram's raw bytes and sender.
|
|
606
|
+
UDPListen: (bindIp: string, port: number, handler: (data: string, ip: string, port: number) -> ()) -> UdpHandle,
|
|
607
|
+
-- this computer's IPv4 address on its default route, or nil when there is none.
|
|
608
|
+
LocalIP: () -> string?,
|
|
554
609
|
}
|
|
555
610
|
|
|
556
611
|
-- pipe namespace
|
|
@@ -637,7 +692,7 @@ declare Dialog: {
|
|
|
637
692
|
SaveFile: (options: DialogFileOptions?) -> string?,
|
|
638
693
|
}
|
|
639
694
|
|
|
640
|
-
-- clipboard namespace
|
|
695
|
+
-- clipboard namespace (limited by clipboard:read, clipboard:write, clipboard:none)
|
|
641
696
|
|
|
642
697
|
declare Clipboard: {
|
|
643
698
|
Get: () -> string?,
|
|
@@ -752,14 +807,14 @@ declare Registry: {
|
|
|
752
807
|
-- declare function OnFocus(window: WindowInfo): ()
|
|
753
808
|
-- declare function OnBlur(window: WindowInfo): ()
|
|
754
809
|
-- declare function OnTick(dtMs: number): () -- ms elapsed since the previous OnTick (0 on the first)
|
|
755
|
-
-- declare function OnDown(key: string): boolean?
|
|
756
|
-
-- declare function OnUp(key: string, durationMs: number): boolean?
|
|
757
|
-
-- declare function OnMove(dx: number, dy: number): boolean? -- return value only used with mouse_block=true (hardware mode only)
|
|
758
|
-
-- declare function OnScroll(delta: number): boolean?
|
|
810
|
+
-- declare function OnDown(key: string, device: InputDevice?): boolean?
|
|
811
|
+
-- declare function OnUp(key: string, durationMs: number, device: InputDevice?): boolean?
|
|
812
|
+
-- declare function OnMove(dx: number, dy: number, device: InputDevice?): boolean? -- return value only used with mouse_block=true (hardware mode only)
|
|
813
|
+
-- declare function OnScroll(delta: number, device: InputDevice?): boolean?
|
|
759
814
|
-- declare function OnScrollH(delta: number): boolean?
|
|
760
|
-
-- declare function OnInputDown(key: string): ()
|
|
761
|
-
-- declare function OnInputUp(key: string, durationMs: number): ()
|
|
762
|
-
-- declare function OnInputMove(dx: number, dy: number): ()
|
|
763
|
-
-- declare function OnInputScroll(delta: number): ()
|
|
815
|
+
-- declare function OnInputDown(key: string, device: InputDevice?): ()
|
|
816
|
+
-- declare function OnInputUp(key: string, durationMs: number, device: InputDevice?): ()
|
|
817
|
+
-- declare function OnInputMove(dx: number, dy: number, device: InputDevice?): ()
|
|
818
|
+
-- declare function OnInputScroll(delta: number, device: InputDevice?): ()
|
|
764
819
|
-- declare function OnError(message: string): ()
|
|
765
820
|
-- declare function OnReload(): ()
|