@aicommander/mcp 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -4
- package/dist/bin/mcp.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -120,9 +120,25 @@ Steps:
|
|
|
120
120
|
|
|
121
121
|
1. Run the root release flow, which bumps `package.json`, both version fields in
|
|
122
122
|
`server.json`, and the other distribution versions in lockstep.
|
|
123
|
-
2.
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
2. Push the tag. **npm publishes itself** — the `publish-npm` job in
|
|
124
|
+
`.github/workflows/release.yml` runs `npm publish --access public` from here
|
|
125
|
+
over OIDC trusted publishing, so there is no token and no 2FA OTP to enter
|
|
126
|
+
(see OPERATIONS.md, "npm trusted publishing (SR-20)"). `prepublishOnly` runs
|
|
127
|
+
`npm run build`, i.e. `tsc --noEmit` followed by the esbuild bundle into
|
|
128
|
+
`dist/`, so the tarball is built from the tagged source.
|
|
129
|
+
3. Publish to the official MCP Registry — **manual, and easy to forget**: it does
|
|
130
|
+
not run in CI, because domain ownership is proven with an Ed25519 key that
|
|
131
|
+
lives only on the maintainer's machine. From the repo root:
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
pnpm publish:mcp-registry # verify afterwards: pnpm check:mcp-registry
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
That is `scripts/publish-mcp-registry.mjs`, which preflights the manifest
|
|
138
|
+
(the name must be exactly `dev.aicommander/mcp` — registry entries are
|
|
139
|
+
immutable — the two version fields must agree, and the registry caps
|
|
140
|
+
`description` at 100 characters and rejects the publish outright above it),
|
|
141
|
+
then runs exactly this underneath, in `packages/mcp`:
|
|
126
142
|
|
|
127
143
|
```sh
|
|
128
144
|
mcp-publisher login http --domain=aicommander.dev \
|
|
@@ -130,7 +146,17 @@ Steps:
|
|
|
130
146
|
mcp-publisher publish
|
|
131
147
|
```
|
|
132
148
|
|
|
133
|
-
|
|
149
|
+
Login proves ownership over HTTP via
|
|
150
|
+
`https://aicommander.dev/.well-known/mcp-registry-auth`, so the Worker must be
|
|
151
|
+
deployed first for the well-known endpoint to be live. Set
|
|
152
|
+
`MCP_PUBLISHER_KEY_FILE` if the key is not at the default path. `mcp-publisher`
|
|
153
|
+
takes the key only as a command-line argument, so for the seconds the login
|
|
154
|
+
runs it is visible to anything that can read this machine's process table —
|
|
155
|
+
another reason this step belongs on the maintainer's own laptop and nowhere
|
|
156
|
+
shared.
|
|
157
|
+
|
|
158
|
+
`pnpm check:mcp-registry` exits 0 in sync, 1 behind, 2 unreachable (which is
|
|
159
|
+
*not* proof it is up to date), 3 when `server.json` itself is unpublishable.
|
|
134
160
|
|
|
135
161
|
## License
|
|
136
162
|
|
package/dist/bin/mcp.js
CHANGED
|
@@ -241,7 +241,7 @@ var MCP_TOOL_ARGUMENT_DESCRIPTIONS = {
|
|
|
241
241
|
// Concatenated, not a template literal: the sentence quotes `0` in backticks.
|
|
242
242
|
timeout_ms: "Timeout in milliseconds: minimum 1000 (1 s), default 300000 (5 min), maximum " + COMMAND_MAX_TIMEOUT_MS + " (" + EXEC_DEADLINE_SHORT + "). Validated, not clamped \u2014 a value outside the range is rejected with an error. In particular `0` is NOT 'no timeout': it is below the minimum and used to be raised silently to 1000, killing the command after one second. Omit the field to get the default.",
|
|
243
243
|
shell: "Which interpreter runs the command. Omit it for the machine's default \u2014 `/bin/sh -c` on 'darwin'/'linux', `cmd.exe` on 'win32' \u2014 which is what every call got before this argument existed. LEAVING THE FIELD OUT is the only way to ask for that default: `shell: null` is a supplied value that names no interpreter, so it is REJECTED rather than answered with whichever shell the machine happens to default to. Windows machines accept `cmd` and `powershell`; macOS/Linux machines accept `sh` and `bash`. A value the target cannot run (e.g. `powershell` on a Mac, or a misspelling) is REJECTED with a message listing what that machine does accept \u2014 it is never quietly replaced by the default, so if the call succeeds the command really did run in the shell you asked for. `powershell` is Windows PowerShell 5.1, run as `-NoProfile -NonInteractive`, and it is the answer to everything cmd.exe makes painful: `;` works as a separator, `Get-ChildItem`/`ls` exist, and a MULTI-LINE script IS allowed (unlike cmd, where a line break is rejected) because the agent hands PowerShell the script base64-encoded rather than on a command line. That encoding costs size: a PowerShell script is capped at roughly 3000 characters here, and a longer one is rejected rather than truncated \u2014 write it to a .ps1 file in pieces and run `powershell -NoProfile -File <path>` if you need more. STDERR IS POST-PROCESSED ON THIS PATH ONLY: that same encoding makes PowerShell serialize its error/warning/progress streams as CLIXML, so the agent strips the `#< CLIXML` framing and `<Objs>` envelope, drops the module-loading progress records, and reassembles the `<S>` fragments \u2014 undoing `_x000D_`-style escapes and XML entities \u2014 into the text a console would show. Anything it cannot positively identify as PowerShell's own framing (a block cut off mid-record, or CLIXML-shaped text your script printed itself) is passed through byte-for-byte, and `cmd`/`sh`/`bash` stderr is never touched at all. WHAT IT DOES NOT BUY YOU IS A TRUSTWORTHY EXIT CODE: a PowerShell NON-TERMINATING error \u2014 `Write-Error`, a failed cmdlet, most runtime errors \u2014 writes to the error stream and the script CARRIES ON, so THE EXIT CODE TRACKS THE LAST STATEMENT, not whether errors occurred. Measured on Windows: `Write-Output \"stdout-line\"; Write-Error \"this-is-a-real-error\"` returns exit code 0 with the error text on stderr \u2014 the exact shape of a success \u2014 and an error in the MIDDLE of a script that then does something successful leaves 0 just the same; a script whose final statement is the failing one exits 1, so a non-zero code does not mean the error you care about happened either. It is uninformative in BOTH directions. That is PowerShell's own semantics, not something AI Commander does to your command; cmd.exe and POSIX shells do not behave this way, so the surprise lands exactly when you switch to the interpreter recommended above. Under `powershell`, READ STDERR rather than trusting exit 0 on its own, and/or begin your script with `$ErrorActionPreference = 'Stop'` to make those errors terminating. The agent will not insert that for you: it would change YOUR script's control flow \u2014 a script that deliberately continues past an error would start aborting \u2014 so the choice stays yours. `bash` (POSIX) buys you arrays, `[[ ]]`, and `pipefail`, which `/bin/sh` on Debian-family Linux does not have. Cannot be combined with `elevated: true` \u2014 that combination is rejected, not ignored. Machines running an AI Commander too old to understand this argument REFUSE the call outright rather than running the default shell behind your back; update the agent there, or drop the argument.",
|
|
244
|
-
elevated: "Run as root (macOS) / LocalSystem (Windows) via the privileged helper. Account-only; only works on mac/Windows machines with the helper installed. Most commands do NOT need this. NOT accepted together with `shell` \u2014 that combination is rejected with an error rather than silently dropped, because the elevated path runs through a signed capability that has no shell field."
|
|
244
|
+
elevated: "Run as root (macOS) / LocalSystem (Windows) via the privileged helper. Account-only; only works on mac/Windows machines with the helper installed. Most commands do NOT need this. NOT accepted together with `shell` \u2014 that combination is rejected with an error rather than silently dropped, because the elevated path runs through a signed capability that has no shell field. AN ELEVATED COMMAND'S LIFETIME IS BOUND TO THE AGENT CONNECTION THAT REQUESTED IT: the privileged helper leases every command to that connection and kills it the moment the connection drops, so a privileged process can never outlive its authorization. That makes any command which RESTARTS, REPLACES OR KILLS AI Commander itself self-defeating when run in-band \u2014 the app IS the agent, so stopping it drops the connection, and the helper then kills the very command that asked for the stop. Measured: an elevated run of the Windows updater downloaded the new version and started the installer, the installer tree-killed the app, the lease fired, and the PowerShell waiting on the installer died mid-install \u2014 the machine stayed on the old version, the update log ends mid-sentence, and the call came back `Agent disconnected during command execution`, which READS LIKE A NETWORK BLIP while the privileged work was actually cut in half. Launch that kind of work DETACHED from this connection instead: on Windows through a scheduled task (`schtasks /Run /TN \"AI Commander Update\"` starts the updater's own SYSTEM task, which the disconnect cannot touch), on macOS through `remote_job_start` (a job reparents to PID 1 and survives anything aimed at the app), on Linux through a transient systemd unit outside the agent's control group \u2014 which is exactly what `aicommander-agent self-update` already does, and for exactly this reason."
|
|
245
245
|
},
|
|
246
246
|
session_status: {
|
|
247
247
|
code: MACHINE_CODE_FULL
|
|
@@ -254,7 +254,7 @@ var MCP_TOOL_ARGUMENT_DESCRIPTIONS = {
|
|
|
254
254
|
},
|
|
255
255
|
remote_job_start: {
|
|
256
256
|
code: MACHINE_CODE_FULL,
|
|
257
|
-
command: "Shell command to run as the job. WHICH SHELL DEPENDS ON THE MACHINE'S OS \u2014 read `platform` from list_machines or session_status first: POSIX machines ('darwin'/'linux') run it via `/bin/sh -c`, Windows machines ('win32') via cmd.exe. On Windows `;` is not a command separator (`echo a ; echo b` prints the rest as literal text and exits 0 \u2014 a silent false success), POSIX tools like `ls` do not exist, and heredocs are a syntax error; chain steps with `&&` on ONE line (a multi-line command is rejected), and wrap script-writing explicitly, e.g. `powershell -NoProfile -Command \"...\"`. A job ALWAYS runs in the machine's default shell: unlike remote_exec there is no `shell` argument here, and passing one is rejected rather than ignored. Use absolute paths or set `cwd`: the job does not inherit any state from earlier remote_exec calls.",
|
|
257
|
+
command: "Shell command to run as the job. WHICH SHELL DEPENDS ON THE MACHINE'S OS \u2014 read `platform` from list_machines or session_status first: POSIX machines ('darwin'/'linux') run it via `/bin/sh -c`, Windows machines ('win32') via cmd.exe. On Windows `;` is not a command separator (`echo a ; echo b` prints the rest as literal text and exits 0 \u2014 a silent false success), POSIX tools like `ls` do not exist, and heredocs are a syntax error; chain steps with `&&` on ONE line (a multi-line command is rejected), and wrap script-writing explicitly, e.g. `powershell -NoProfile -Command \"...\"`. AND ON WINDOWS A JOB IS NOT REMOTE_EXEC WITH A LONGER LEASH: the machine runs a job's command from a BATCH FILE, not from cmd.exe's command line, so `%` follows batch rules here \u2014 a `for` loop's variable must be doubled (`for /L %%i in (1,1,3) do @echo tick %%i`), and the `%i` that works in remote_exec dies in the first second with `i was unexpected at this time.` and an exit code, which reads as a job that started and then failed rather than as a command you wrote for the wrong dialect. Double the percent signs when you move a working command over from remote_exec. A job ALWAYS runs in the machine's default shell: unlike remote_exec there is no `shell` argument here, and passing one is rejected rather than ignored. Use absolute paths or set `cwd`: the job does not inherit any state from earlier remote_exec calls.",
|
|
258
258
|
cwd: "Working directory on the remote machine. Defaults to a per-job workspace directory the machine creates.",
|
|
259
259
|
env: "Extra environment variables for the job (string values only), e.g. HF_HOME or TORCH_HOME so model weights land somewhere with space rather than in the service account's home directory.",
|
|
260
260
|
name: "Short human-readable label for the job, so you and the user can recognize it later in remote_job_list. The machine generates one if omitted.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aicommander/mcp",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"mcpName": "dev.aicommander/mcp",
|
|
5
5
|
"description": "Remote shell and long-running background jobs for AI agents. Let Claude, Codex, ChatGPT or any MCP client run commands, builds, batch work and GPU/ML training on your own machines without exposed SSH, open ports or VPN.",
|
|
6
6
|
"keywords": [
|