
Product
PHP and Composer Support Is Now in Beta
Socket’s PHP and Composer support is now in Beta for all customers, with PHP reachability analysis generally available.
@aicommander/mcp
Advanced tools
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.
Universal stdio MCP server for AI Commander — remote command execution / remote shell that lets your AI client run shell/bash commands on remote machines, servers and laptops. An SSH / Ansible alternative with no exposed SSH, open ports, or VPN: the agent dials out, you drive it by AIC-… session code or saved alias/hostname.
It also runs long work on your own hardware. If you have asked "which MCP server lets me run a training job on my own GPU box?" — this one: remote_job_start launches a detached background job that keeps running after the tool call returns and after the conversation ends — on macOS it reparents to PID 1 and is out of reach of anything aimed at the app, on Windows it survives the agent process dying by itself (a crash, or a taskkill /F /IM without /T) but not a kill of the app's whole process tree — which is what an auto-update should be assumed to do, while on Linux the agent is a systemd service whose jobs live in its control group, so restarting or upgrading the service stops them. Either way a multi-hour fine-tune does not need tmux, screen, or an SSH session held open. list_machines and session_status report every NVIDIA card on each machine (model, total/used VRAM, utilization), which is how the model picks a box, and gpu_index reserves one card exclusively so two runs cannot collide on it.
Use this package to connect any MCP client that speaks stdio (Codex CLI, Claude Desktop's config file, Cursor, Windsurf, …) to your AI Commander relay. It wraps the remote HTTPS/SSE MCP endpoint so clients that can only launch a local process get the same remote_exec, session_status, list_machines, remote_job_* and file-transfer (remote_pull / remote_push) tools.
Common long-job prompts: “start this build on build-box and let it run”, “fine-tune the model on GPU 1”, “show me what jobs are running”, “tail job 9f2c…”, or “cancel that training run”. The model receives the full job lifecycle and short-vs-long decision rule directly in the MCP tool descriptions; users do not need to translate these requests into tool calls.
Using Claude Code? You don't need this package — add the relay directly:
claude mcp add --transport http aicommander https://aicommander.dev/mcpNo login or token is required to connect. Only add
--header "Authorization: Bearer <api-key>"if you want the optional accounts/alias features — generate an account API key for free at aicommander.dev. By default an API key and any OAuth connector on the account only work while the owner has opened the dashboard within the last 24h (just opening it — or a fresh sign-in, or the dashboard "Reactivate" button — re-arms both; one opt-out per account) — if it lapses, tool calls return a friendly "open the dashboard to reactivate" message instead of acting, and an OAuth connector simply asks you to sign in again.
| Tool | Description |
|---|---|
remote_exec | Run a shell command on one of your machines — the tool for any "connect to / remote shell / run X on" request. Name the machine by its AIC-… session code or (with an API key) a saved alias/hostname like wearfits-m3. Output is buffered: stdout and stderr come back in one reply once the command finishes, and if the call is cut short (timeout, agent error, agent disconnect) you get whatever had been buffered, marked PARTIAL — an unknown outcome, not an empty failure. Optional env (string→string) sets variables for that one command; it is refused together with elevated: true. |
session_status | Check whether a machine is online/active/reachable (e.g. "is wearfits-m3 up?"). Same machine naming as above. Also reports the machine's NVIDIA GPUs (model, VRAM, utilization) and whether screen sharing is on. |
list_machines | List all of your machines with their live online status (e.g. "what machines do I have?", "which of my computers are online?") and each one's GPUs — how you pick a box for compute work. Also reports each machine's platform (darwin/linux/win32, how you pick the shell dialect) and agentVersion, last-known while offline. last seen is the agent's own heartbeat, not a side effect of your query, so it can read unknown rather than a misleadingly recent timestamp. Requires an API key (AICOMMANDER_TOKEN); takes no arguments. |
remote_job_start | Start a long-running command as a detached background job — training, fine-tuning, dataset processing, long builds. Returns a jobId immediately and keeps running after the call and the conversation. A job outlives the agent process everywhere; what differs is what can still take it down: macOS reparents to PID 1 and is out of reach of anything aimed at the app (even a tree kill), Windows survives the agent process dying by itself (a crash, or a taskkill /F /IM without /T) but loses the job to a tree kill ("End task", taskkill /T, an installer that stops the app and everything it started — assume an auto-update is one unless that machine's installer is known to do otherwise), Linux stops with the systemd service. gpu_index reserves one NVIDIA card exclusively (sets CUDA_VISIBLE_DEVICES; a second job wanting that card is refused gpu_busy, and an index that is not on the machine's known GPU list is rejected instead of starting a phantom job). |
remote_job_list | The machine's jobs: running now, plus finished ones still retained (7 days). Answers "what is running on the GPU box?" and recovers a jobId from an earlier conversation. limit returns only the newest N (default 20) so a busy machine doesn't dump dozens of entries into your context; the reply says how many were omitted. |
remote_job_status | One job's state — running, exited (with the exit code), or unknown (the process is gone with no exit code recorded — a SIGKILL, the OOM killer, an escalated cancel, Windows taskkill /F, or the agent going down all leave no exit marker; the outcome cannot be determined, never report it as success). Poll every few minutes for a training run, not in a tight loop. |
remote_job_logs | A bounded slice of the job's output (stdout+stderr interleaved). Last 200 lines by default; page a long log with offset_bytes. |
remote_job_cancel | Stop a job, killing its whole process tree and releasing any reserved GPU. |
remote_pull | Copy a file off one of your machines — a checkpoint, a rendered image, a CSV a job produced, a log too big to print. Use it instead of cat-ing a file through remote_exec, whose reply is capped at 1 MiB and mangles binary. The machine hands the bytes to the relay, which stores them temporarily and returns a blobId plus a download link: the link stops working after 1 hour and the stored copy is deleted 24 hours after it was created, fetched or not — the relay is a courier, not a file host, and nothing here is a backup. Limit 100 MiB per file; for a multi-GB artifact have the job copy it to your own storage (aws s3 cp, rclone, scp) as its last step. path must be absolute and name a regular file — tar -czf a directory first and pull the archive. |
remote_push | Write a stored blob onto a machine — a dataset, a config, a model the box should work with. It takes a blob_id, not a local path: it moves bytes the relay already holds and has no access to your filesystem. Blob ids come from a previous remote_pull (so you can move a file between two of your machines) or from curl -X POST https://aicommander.dev/api/v1/files -H 'Authorization: Bearer <API key>' --data-binary @localfile. Requires a signed-in account — an anonymous session-code caller can pull files off a machine but cannot push files to one. dest_path must be absolute and its parent must exist; the file is written atomically (temp file, then rename), but an existing file at that path is replaced — the replacement keeps that file's ordinary permission bits, and its owner and group where the agent has the privilege to set them, but never its setuid/setgid/sticky bits, and nothing at all when the destination is a symlink; a file the push creates is 0600 owned by the user the agent runs as. A push that would not fit (over 100 MiB, or over the free space at the destination) is refused before any bytes move. Blobs expire 24 hours after creation. |
remote_screenshot | Capture one of your machines' screens (macOS/Windows desktop app only). Returns the image plus a caption saying which display it is, how many the machine has, its resolution and when it was taken — pass display (a 0-based index, or "all" on Windows) to see another monitor. Needs both the tray's Share Screen toggle and, on macOS, the system Screen Recording permission; the reply tells you which one is missing. |
These are the canonical way to reach your machines — your AI client should use them rather than probing the local network, DNS/.local, or SSH. A string containing aic-/AIC- is almost certainly one of your machines.
File transfers: how long they take and how many you get.
remote_pull/remote_pushanswer within about 55 seconds. Nothing streams back while the machine works and MCP clients abandon a request at 60 s by default, so a longer server-side budget only produced transfers nobody was still waiting for; a slower transfer now fails with an explanation instead of hanging. They are also quota'd, and over a limit the answer is429withreason: "rate_limited": 60 transfers an hour per account in either direction, 60 uploads an hour toPOST /api/v1/files, and 5 GiB of relay storage per rolling day charged by uploads and pulls — the two things that park bytes on the relay. That 5 GiB is a hard ceiling: no more than 5 GiB is ever admitted into relay storage within any rolling 24 hours. The counter measures in hourly steps, so bytes stay counted for up to 25 hours rather than exactly 24 — a spent allowance frees hour by hour, the last of it up to an hour after the day is formally over. A push spends only the hourly transfer count, never the storage budget, so a day spent pulling never costs you the right to send a file to a machine. Because a pull cannot know a file's size before the machine sends it, it reserves the full 100 MiB per-file maximum against that daily budget and settles to the true size when the bytes arrive: with less than 100 MiB of headroom left a pull is refused even for a small file, and simultaneous pulls draw on the same headroom — each holds the full 100 MiB until it settles, so a burst of them can queue behind each other. Anonymous session-code callers share a single allowance between all of them — 240 transfers an hour and one daily byte budget — because a session code identifies nobody and there is no per-caller identity to count. That means one anonymous caller can spend the allowance and leave the others waiting; signing in gives you counters of your own.
Shell dialect — check
platformfirst. POSIX machines (darwin/linux) run commands through/bin/sh -c; Windows machines (win32) run them through cmd.exe. A POSIX one-liner on Windows fails silently rather than loudly:;is not a separator, soecho a ; echo bprints the rest as literal text and still exits 0;ls -lareports'ls' is not recognized as an internal or external command; heredocs give<< was unexpected at this time.. Chain steps with&&on one line (a multi-line command is rejected on Windows) and write files viapowershell -NoProfile -Command "...", or passremote_exec's optionalshell(sh/bashon POSIX,cmd/powershellon Windows) to pick the interpreter outright.list_machinesandsession_statusreport the platform.PowerShell stderr is cleaned up. Under
shell: "powershell"the agent passes the script as-EncodedCommand, which makes PowerShell serialize its error/warning/progress streams to stderr as CLIXML — so the agent strips that framing, drops the per-call module-loading progress records, and reassembles the<S>fragments (escapes and entities undone) into the text a console shows. Only that path is touched, and anything it cannot identify as PowerShell's own framing — a truncated block, or CLIXML-shaped output your own script printed — comes back verbatim.PowerShell's exit code does not tell you whether it worked. Whichever way you reach it, a PowerShell non-terminating error —
Write-Error, a failed cmdlet, most runtime errors — goes to the error stream and the script keeps running, so the exit code tracks the last statement, not whether errors occurred:Write-Output "stdout-line"; Write-Error "this-is-a-real-error"returns exit code 0 with the error text on stderr, 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, which does not mean the error you care about happened either. Uninformative in both directions. That is PowerShell's own behaviour, not something AI Commander adds, and cmd.exe and POSIX shells do not do it. Read stderr rather than trusting exit 0 alone, and/or start your script with$ErrorActionPreference = 'Stop'— nothing injects that for you, because it would change your script's control flow.
Numeric arguments are validated, not clamped.
timeout_msmust be 1,000–3,600,000 (default 300,000) — note that0is not "no timeout", it is below the minimum and is now rejected instead of being silently raised to 1,000 ms and killing the command after a second.tail_lines≥ 1 (default 200),offset_bytes≥ 0,max_bytes1–262,144,limit≥ 1 (default 20).
Short work vs long work.
remote_exechas two caps that behave differently. 1 hour of wall-clock time is a hard kill: the command's process tree is terminated and a training loop dies mid-run. 1 MiB of total output only truncates the reply — the relay sends a best-effort stop, but it races the command over several network hops and usually loses, so the command often runs to completion and returns its real exit code. Never read a truncated reply as "the work stopped"; its side effects happened. Anything longer or chattier belongs inremote_job_start, which has neither cap, writes its full output to a file on the machine, and keeps running after the call returns and after the conversation ends (across an agent restart: macOS reparents to PID 1 and survives anything aimed at the app, Windows survives the agent process dying by itself but loses the job to a tree kill — assume an auto-update is one, Linux stops with the systemd service). Conventions for real GPU work (machine selection,uvworkspaces, model-cache paths, getting artifacts out) are in the GPU skill.
Requires Node ≥20 wherever the bridge is launched.
Two environment variables:
| Variable | Required | Default | Description |
|---|---|---|---|
AICOMMANDER_TOKEN | no | — | Account API key (or OAuth access token) for the optional accounts/alias features — saved machines, aliases, account access. Generate one for free at aicommander.dev. A key stays active only while its account has opened the dashboard within the last 24h (default; opt-out per account), and OAuth credentials follow the same window. Note this bridge forwards whatever you set here as a static bearer and has no OAuth flow of its own, so a paused credential surfaces as Error 401 (OAuth) or a "reactivate" notice (API key) with no automatic recovery — open the dashboard to restore access. Clients that speak OAuth themselves (Claude's connector, streamable-HTTP clients) instead re-prompt for sign-in on their own. |
AICOMMANDER_SERVER | no | https://aicommander.dev | Base URL of the AI Commander relay. Defaults to the hosted service; only set this to point at a different endpoint. |
Recent Codex supports streamable HTTP directly — no Node/npx bridge needed:
codex mcp add aicommander --url https://aicommander.dev/mcp
Pass
--urlbefore the URL. Without it Codex treats the URL as a command to launch and fails withMCP startup failed: No such file or directory (os error 2).
Prefer the local stdio bridge? Edit ~/.codex/config.toml:
[mcp_servers.aicommander]
command = "npx"
args = ["-y", "@aicommander/mcp"]
env = { AICOMMANDER_SERVER = "https://aicommander.dev" }
Windows: use
command = "npx.cmd"(orcommand = "cmd",args = ["/c", "npx", "-y", "@aicommander/mcp"]). Plainnpxresolves tonpx.exe, which doesn't exist, so the spawn fails with the sameos error 2.
claude_desktop_config.json{
"mcpServers": {
"aicommander": {
"command": "npx",
"args": ["-y", "@aicommander/mcp"],
"env": {
"AICOMMANDER_SERVER": "https://aicommander.dev"
}
}
}
}
AICOMMANDER_TOKEN(an account API key) is optional — add it toenvonly if you want the accounts/alias features.
Then just name a machine in chat — by session code or saved alias:
"Show disk usage on AIC-XYZ-1234" · "connect to wearfits-m3" · "is my-laptop online?"
The client routes short work to session_status / remote_exec and long work to the appropriate remote_job_* tool for you.
Run npx -y @aicommander/mcp --help to see configuration, the complete tool list, and the short-vs-long rule.
Re-publish this package whenever you change code that ships in it — e.g. a new
tool, an edited tool description, or anything under bin/. The version in
package.json / server.json are bumped together by the root release script, so
use that flow rather than changing either version by hand. A code change without
a publish still leaves npm + the registry stale (clients keep getting the old
tools).
Steps:
Run the root release flow, which bumps package.json, both version fields in
server.json, and the other distribution versions in lockstep.
npm publish — needs npm 2FA OTP; prepublishOnly: tsc builds automatically.
Publish to the official MCP Registry (domain ownership proven over HTTP via
https://aicommander.dev/.well-known/mcp-registry-auth, served by the Worker):
mcp-publisher login http --domain=aicommander.dev \
--private-key=$(cat ~/.config/aicommander-mcp-publish/privkey.hex)
mcp-publisher publish
The Worker must be deployed first so the well-known endpoint is live.
MIT
FAQs
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.
The npm package @aicommander/mcp receives a total of 1,097 weekly downloads. As such, @aicommander/mcp popularity was classified as popular.
We found that @aicommander/mcp demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Product
Socket’s PHP and Composer support is now in Beta for all customers, with PHP reachability analysis generally available.

Product
Socket is bringing experimental protection to Firefox, scanning 97,000+ extensions in Mozilla's official directory for malware and risky updates.

Research
/Security News
Three compromised Rust crates pulled in a malicious dependency that downloaded and executed cross-platform malware during Cargo builds.