@remcp/runtime 0.2.0 → 0.2.4
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/CHANGELOG.md +23 -0
- package/README.md +96 -41
- package/package.json +3 -2
- package/src/catalog.mjs +341 -11
- package/src/config.mjs +43 -3
- package/src/diff.mjs +86 -0
- package/src/index.mjs +39 -6
- package/src/invoke.mjs +5 -2
- package/src/policy.mjs +71 -20
- package/src/sessions.mjs +58 -10
- package/src/telemetry.mjs +16 -2
- package/src/tools/files.mjs +651 -32
- package/src/tools/search.mjs +12 -5
- package/src/tools/system.mjs +58 -1
- package/src/tools/terminal.mjs +85 -32
- package/src/util.mjs +34 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.3
|
|
4
|
+
|
|
5
|
+
Full surface and review-aligned annotations. (0.2.0 was published from an earlier snapshot that
|
|
6
|
+
carried 23 tools; 0.2.1 is the release that matches this repository.)
|
|
7
|
+
|
|
8
|
+
- 37 tools: bulk reads and writes (`read_files` by glob, `write_files` for many files at once), binary transfer in both directions (`read_binary`, `write_binary`, base64 chunks),
|
|
9
|
+
archives (`create_archive`, `extract_archive` for tar, tar.gz, tar.bz2, tar.xz, zip), screenshots
|
|
10
|
+
(`take_screenshot`), `read_image`, `hash_file`, `diff_files`, `replace_lines`, `replace_in_files`,
|
|
11
|
+
`move_to_trash`, `get_system_info`, `wait_for_process_output`, runtime introspection, and a glob
|
|
12
|
+
filter on `list_directory`;
|
|
13
|
+
- no approval step anywhere: writes replace by default, moves and copies replace the destination,
|
|
14
|
+
`replace_in_files` applies immediately, and `dry_run` is opt-in for callers who want a preview;
|
|
15
|
+
- `dangerousCommands` defaults to `warn`: a catastrophic command runs and the result carries a note,
|
|
16
|
+
with `allow` for silence and `block` to refuse;
|
|
17
|
+
- annotations say what the tools do: 19 read-only, 14 destructive (including the tools that replace a
|
|
18
|
+
destination by default), 2 open-world;
|
|
19
|
+
- crash-resistance: a bad shell, a closed stdin, a stream with no newlines, a dead parent, or an
|
|
20
|
+
unparseable `runtime.json` cannot leave a device silently offline;
|
|
21
|
+
- `read_process_output` offsets are documented and implemented as zero-based line numbers, ranged
|
|
22
|
+
reads no longer consume the new-output cursor, and reads never sleep over buffered data;
|
|
23
|
+
- the contract commands work with no dependencies installed, so CI can diff the advertised tool
|
|
24
|
+
surface against the published tarball.
|
|
25
|
+
|
|
3
26
|
## 0.2.0
|
|
4
27
|
|
|
5
28
|
First feature-complete first-party release. ReMCP no longer needs to install an upstream MCP server
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# ReMCP local runtime
|
|
2
2
|
|
|
3
3
|
`@remcp/runtime` is the local device runtime for [ReMCP](https://remcp.delio24.com). It is an MCP
|
|
4
|
-
server that runs on a computer you paired with ReMCP and executes the file, search, terminal,
|
|
5
|
-
process tools that the hosted ReMCP MCP endpoint exposes to ChatGPT and Codex.
|
|
4
|
+
server that runs on a computer you paired with ReMCP and executes the file, image, search, terminal,
|
|
5
|
+
and process tools that the hosted ReMCP MCP endpoint exposes to ChatGPT and Codex.
|
|
6
6
|
|
|
7
7
|
The ReMCP device agent starts this runtime as a child process and talks to it over stdio. The runtime
|
|
8
8
|
never talks to the network on its own: it only answers the paired agent, which holds the device
|
|
@@ -27,25 +27,52 @@ npx @remcp/runtime # MCP server over stdio
|
|
|
27
27
|
|
|
28
28
|
## Tools
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
35 tools, all implemented in this repository. Nothing is gated behind an approval step: a tool call
|
|
31
|
+
executes.
|
|
31
32
|
|
|
32
|
-
|
|
|
33
|
+
| Area | Tools |
|
|
33
34
|
| --- | --- |
|
|
34
|
-
| `read_file`, `read_multiple_files`
|
|
35
|
-
| `
|
|
36
|
-
| `
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
|
40
|
-
| `
|
|
41
|
-
| `get_runtime_info`, `get_runtime_stats` |
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
| Read | `read_file`, `read_multiple_files`, `read_image`, `read_binary`, `list_directory` (glob filter), `get_file_info`, `hash_file`, `diff_files` |
|
|
36
|
+
| Write | `write_file`, `write_binary`, `edit_block` (whitespace-tolerant fallback, optional `dry_run`), `replace_lines`, `replace_in_files` |
|
|
37
|
+
| Organise | `create_directory`, `move_file`, `copy_file`, `move_to_trash`, `create_archive`, `extract_archive` |
|
|
38
|
+
| Transfer | `read_binary` / `write_binary` stream any file as base64 chunks in both directions; `create_archive` / `extract_archive` move whole trees |
|
|
39
|
+
| Screen | `take_screenshot` returns the desktop as an image on Linux, macOS, and Windows |
|
|
40
|
+
| Search | `start_search`, `get_more_search_results`, `stop_search`, `list_searches` |
|
|
41
|
+
| Processes | `start_process`, `read_process_output`, `wait_for_process_output`, `interact_with_process`, `force_terminate`, `list_sessions`, `list_processes`, `kill_process` |
|
|
42
|
+
| Introspection | `get_system_info`, `get_runtime_info`, `get_runtime_stats` |
|
|
43
|
+
|
|
44
|
+
The hosted ReMCP endpoint adds `list_devices` so a model can pick a machine. Everything else the
|
|
45
|
+
agent may need — service management, package installs, git, docker, `sudo` — runs through
|
|
46
|
+
`start_process`, which is an unrestricted shell for the account running the agent.
|
|
47
|
+
|
|
48
|
+
There is deliberately no `set_config_value` (a model must not rewrite its own device limits; use the
|
|
49
|
+
file) and no `write_pdf`/spreadsheet/DOCX tooling (that is what drags Puppeteer, `sharp`, and
|
|
50
|
+
`exceljs` onto your computer — use `start_process` with whatever tool you already have).
|
|
45
51
|
|
|
46
52
|
`--print-tools` prints the exact JSON contract (schemas and annotations) the runtime advertises, and
|
|
47
53
|
`src/catalog.mjs` is the single source of truth for it.
|
|
48
54
|
|
|
55
|
+
## No approval staircase
|
|
56
|
+
|
|
57
|
+
ReMCP is a remote control for computers you own, with the same trust model as SSH: the tool call runs,
|
|
58
|
+
and the user's request is the authorization. There is no approval prompt, no "are you sure", and no
|
|
59
|
+
dry-run detour unless you ask for one.
|
|
60
|
+
|
|
61
|
+
- file writes replace by default (`mode: "append"` to add), moves and copies replace the destination
|
|
62
|
+
(`overwrite: false` refuses instead), `replace_in_files` applies immediately (`dry_run: true`
|
|
63
|
+
previews), and `move_to_trash` is there when you want an undo;
|
|
64
|
+
- the destructive-command guardrail defaults to `warn`: the command runs and the result carries a note
|
|
65
|
+
when it matches the catastrophic list (`mkfs`, raw device writes, repartitioning, host power
|
|
66
|
+
control, fork bombs, recursive root deletion). `allow` removes even the note, `block` refuses
|
|
67
|
+
before running, and `blockedCommands` adds your own deny list;
|
|
68
|
+
- `allowedRoots` is empty, so the device reaches everything the agent's account can reach. Set it to
|
|
69
|
+
confine a device to specific directories, enforced against the resolved real path.
|
|
70
|
+
|
|
71
|
+
The guarantees that remain are about correctness rather than permission: a bad shell, a closed stdin,
|
|
72
|
+
or a 40 MB line cannot take the runtime down; a crashed runtime is restarted by the agent; terminal
|
|
73
|
+
sessions run in their own process group so `force_terminate` stops the whole pipeline; and a
|
|
74
|
+
misconfigured `runtime.json` stops the device loudly instead of silently dropping your settings.
|
|
75
|
+
|
|
49
76
|
## Usage metrics
|
|
50
77
|
|
|
51
78
|
Usage metrics are **opt-out**, matching the ReMCP client. They cover tool names, durations, outcomes,
|
|
@@ -72,25 +99,33 @@ export REMCP_RUNTIME_DISABLE_TELEMETRY=1 # environment
|
|
|
72
99
|
|
|
73
100
|
in `~/.config/remcp/runtime.json`. `--describe` always reports the current state.
|
|
74
101
|
|
|
75
|
-
##
|
|
76
|
-
|
|
77
|
-
- **No network calls.** The runtime opens no sockets
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
`
|
|
84
|
-
- **
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
`
|
|
102
|
+
## Runtime properties
|
|
103
|
+
|
|
104
|
+
- **No network calls of its own.** The runtime opens no sockets: every byte it emits goes to the
|
|
105
|
+
paired agent. Shell commands it runs can of course reach the network, exactly as they would from
|
|
106
|
+
your own terminal.
|
|
107
|
+
- **Optional confinement.** `allowedRoots` is empty by default. When you set it, it is enforced
|
|
108
|
+
against the resolved real path of the deepest existing ancestor rather than the lexical string, so
|
|
109
|
+
`<allowed>/link -> /etc` cannot be used to read or write outside the allowed directories.
|
|
110
|
+
`allowedRoots: ["/"]` means the whole filesystem and works as written.
|
|
111
|
+
- **Command guardrail.** `dangerousCommands` defaults to `warn`: a catastrophic command still runs and
|
|
112
|
+
the result carries a note. `allow` silences the note, `block` refuses before running. Rules match the
|
|
113
|
+
*command word* of each shell segment, so `grep -n format README.md` is never affected. User
|
|
114
|
+
`blockedCommands` entries are always enforced.
|
|
115
|
+
- **A bad configuration is loud.** If `runtime.json` cannot be parsed, the device refuses to start and
|
|
116
|
+
says why, instead of quietly dropping your `allowedRoots` and re-enabling usage metrics.
|
|
88
117
|
- **Secret masking.** `list_processes` masks command arguments that look like tokens, passwords, or
|
|
89
118
|
API keys before returning them.
|
|
90
|
-
- **Bounded everything.** Tool results are capped (`maxOutputBytes
|
|
91
|
-
(`maxWriteBytes`), buffered session output is capped
|
|
119
|
+
- **Bounded everything.** Tool results are capped (`maxOutputBytes`, also clamped below the MCP
|
|
120
|
+
transport limit), writes are capped (`maxWriteBytes`), buffered session output is capped by both
|
|
121
|
+
line count and total characters - a stream with no newlines cannot grow without limit - and reads
|
|
122
|
+
are paged or chunked.
|
|
123
|
+
- **Crash-resistant sessions.** A bogus shell, a closed stdin, or a dead parent cannot take the
|
|
124
|
+
runtime down; sessions run in their own process group so `force_terminate` stops a whole pipeline;
|
|
125
|
+
the agent restarts the runtime if it ever exits, so a device recovers instead of going silently
|
|
126
|
+
offline.
|
|
92
127
|
- **Protected processes.** `kill_process` refuses pid 1, the runtime itself, and the ReMCP agent that
|
|
93
|
-
hosts it.
|
|
128
|
+
hosts it - the three ways a model could otherwise cut its own connection.
|
|
94
129
|
|
|
95
130
|
These are guardrails, not an operating-system sandbox. A user who can run a shell can reach anything
|
|
96
131
|
their account can reach; use a container, a VM, or a dedicated user account when that matters.
|
|
@@ -108,7 +143,7 @@ Optional settings live in `~/.config/remcp/runtime.json` (override the directory
|
|
|
108
143
|
"name": "workstation",
|
|
109
144
|
"allowedRoots": ["~/projects", "/srv/data"],
|
|
110
145
|
"blockedCommands": ["rm -rf /", "shutdown"],
|
|
111
|
-
"dangerousCommands": "
|
|
146
|
+
"dangerousCommands": "warn",
|
|
112
147
|
"telemetryEnabled": true,
|
|
113
148
|
"maxOutputBytes": 1048576,
|
|
114
149
|
"maxReadLines": 2000,
|
|
@@ -131,7 +166,9 @@ directories.
|
|
|
131
166
|
## Session behavior
|
|
132
167
|
|
|
133
168
|
Terminal sessions and searches live in memory for the lifetime of the runtime process. They end when
|
|
134
|
-
the agent restarts, and exited sessions are dropped 30 minutes after they finish.
|
|
169
|
+
the agent restarts, and exited sessions are dropped 30 minutes after they finish. The agent watches
|
|
170
|
+
this process and restarts it with backoff if it ever exits, so a device recovers instead of staying
|
|
171
|
+
silently offline.
|
|
135
172
|
|
|
136
173
|
## Development
|
|
137
174
|
|
|
@@ -141,16 +178,34 @@ npm run check
|
|
|
141
178
|
npm test
|
|
142
179
|
```
|
|
143
180
|
|
|
144
|
-
|
|
181
|
+
The contract commands (`--help`, `--version`, `--print-tools`, `--describe`) work without
|
|
182
|
+
dependencies installed, so CI can diff the advertised tool surface against the published tarball.
|
|
183
|
+
|
|
184
|
+
## How it compares with Desktop Commander
|
|
145
185
|
|
|
146
186
|
This runtime is an independent implementation written for ReMCP. It is not a fork of, and shares no
|
|
147
|
-
code with,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
and
|
|
153
|
-
|
|
187
|
+
code with, [DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP) or any other
|
|
188
|
+
MCP server.
|
|
189
|
+
|
|
190
|
+
| | Desktop Commander 0.2.50 | ReMCP runtime 0.2.0 |
|
|
191
|
+
| --- | --- | --- |
|
|
192
|
+
| Tools | 26, including config mutators and document tooling | 35, including binary transfer, archives, screenshots, and diffs |
|
|
193
|
+
| Runtime dependencies | 34 (Supabase, Puppeteer/md-to-pdf, `sharp`, `exceljs`, Tiptap, ripgrep download) | 1 (`@modelcontextprotocol/sdk`) |
|
|
194
|
+
| Install scripts | `postinstall` posts an install payload that ignores the telemetry setting | none |
|
|
195
|
+
| Telemetry | opt-out, 51 event names, remote feature flags, A/B assignment, third-party processor | opt-out, whitelisted event schema, no endpoint, no flags |
|
|
196
|
+
| Install size | 3.78 MB unpacked, 249 files | ~110 kB unpacked, 20 files |
|
|
197
|
+
| `read_file` | also fetches arbitrary URLs (SSRF surface) | local files only; `read_binary` transfers any file as base64 |
|
|
198
|
+
| Command guardrails | always on, 32 substring-blocked commands, advisory; also refuses read-only mentions | `warn` by default (never blocks), `allow`/`block` opt-in, command-word matching |
|
|
199
|
+
| Confinement | always on, checked against the lexical path | opt-in, checked against the resolved real path |
|
|
200
|
+
| Local history | writes tool arguments to disk unredacted | none |
|
|
201
|
+
| Images | file preview UI in a specific client | `read_image` returns the image to any MCP client |
|
|
202
|
+
| Termination | session kill only | whole process group, plus runtime supervision and restart |
|
|
203
|
+
|
|
204
|
+
What ReMCP deliberately does not implement, and why: document rendering (`write_pdf`) and spreadsheet
|
|
205
|
+
handling would put Puppeteer, `sharp`, and `exceljs` on your computer; `get_config`/`set_config_value`
|
|
206
|
+
would let the model change its own limits; local usage history would write your arguments to disk;
|
|
207
|
+
URL reads in `read_file` would add an SSRF surface. Everything else the upstream server can do has an
|
|
208
|
+
equivalent here, and the tool count is higher.
|
|
154
209
|
|
|
155
210
|
## License
|
|
156
211
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remcp/runtime",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "First-party ReMCP local device runtime: file, search, terminal and process tools over MCP for computers paired with ReMCP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
},
|
|
29
29
|
"repository": {
|
|
30
30
|
"type": "git",
|
|
31
|
-
"url": "git+https://github.com/antonbaider/remcp
|
|
31
|
+
"url": "git+https://github.com/antonbaider/remcp.git",
|
|
32
|
+
"directory": "packages/runtime"
|
|
32
33
|
},
|
|
33
34
|
"bugs": {
|
|
34
35
|
"url": "https://github.com/antonbaider/remcp/issues"
|