@aicommander/mcp 1.0.15 → 1.0.17

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 CHANGED
@@ -7,7 +7,7 @@ Use this package to connect any MCP client that speaks **stdio** (Codex CLI, Cla
7
7
  > Using **Claude Code**? You don't need this package — add the relay directly:
8
8
  > `claude mcp add --transport http aicommander https://aicommander.dev/mcp`
9
9
  >
10
- > No 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](https://aicommander.dev). By default an API key only works while its owner has signed in to the dashboard within the last **24h** (a sign-in or the dashboard "Reactivate" button re-arms it; opt-out per account) — if it lapses, tool calls return a friendly "sign in to reactivate" message instead of acting.
10
+ > No 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](https://aicommander.dev). By default an API key only works while its owner has opened the dashboard within the last **24h** (just opening it — or a fresh sign-in, or the dashboard "Reactivate" button — re-arms it; opt-out per account) — if it lapses, tool calls return a friendly "open the dashboard to reactivate" message instead of acting.
11
11
 
12
12
  ## Tools
13
13
 
@@ -15,6 +15,7 @@ Use this package to connect any MCP client that speaks **stdio** (Codex CLI, Cla
15
15
  |---|---|
16
16
  | `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`; streams stdout/stderr back. |
17
17
  | `session_status` | Check whether a machine is online/active/reachable (e.g. "is wearfits-m3 up?"). Same machine naming as above. |
18
+ | `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?"). Requires an API key (`AICOMMANDER_TOKEN`); takes no arguments. |
18
19
 
19
20
  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.
20
21
 
@@ -24,7 +25,7 @@ Two environment variables:
24
25
 
25
26
  | Variable | Required | Default | Description |
26
27
  |---|---|---|---|
27
- | `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](https://aicommander.dev). An API key stays active only while its account has signed in to the dashboard within the last 24h (default; opt-out per account); OAuth access tokens are not gated this way. |
28
+ | `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](https://aicommander.dev). An API key stays active only while its account has opened the dashboard within the last 24h (default; opt-out per account); OAuth access tokens are not gated this way. |
28
29
  | `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. |
29
30
 
30
31
  ## Usage
@@ -78,6 +79,29 @@ Then just name a machine in chat — by session code or saved alias:
78
79
 
79
80
  The client routes it to `session_status` / `remote_exec` for you.
80
81
 
82
+ ## Publishing
83
+
84
+ **Re-publish this package whenever you change code that ships in it** — e.g. a new
85
+ tool, an edited tool description, or anything under `bin/`. The version in
86
+ `package.json` / `server.json` is NOT auto-bumped, so a code change without a
87
+ publish silently leaves npm + the registry stale (clients keep getting the old
88
+ tools). Easy to forget — don't.
89
+
90
+ Steps:
91
+
92
+ 1. Bump `version` in **both** `package.json` and `server.json` (keep them in sync).
93
+ 2. `npm publish` — needs npm 2FA OTP; `prepublishOnly: tsc` builds automatically.
94
+ 3. Publish to the official MCP Registry (domain ownership proven over HTTP via
95
+ `https://aicommander.dev/.well-known/mcp-registry-auth`, served by the Worker):
96
+
97
+ ```sh
98
+ mcp-publisher login http --domain=aicommander.dev \
99
+ --private-key=$(cat ~/.config/aicommander-mcp-publish/privkey.hex)
100
+ mcp-publisher publish
101
+ ```
102
+
103
+ The Worker must be deployed first so the well-known endpoint is live.
104
+
81
105
  ## License
82
106
 
83
107
  MIT
package/dist/bin/mcp.js CHANGED
@@ -8,9 +8,14 @@ const SERVER_URL = process.env["AICOMMANDER_SERVER"] ?? "https://aicommander.dev
8
8
  // access. Without it the bridge works anonymously and you drive machines by their
9
9
  // session code (AIC-…) inside the code's 1-hour freshness window.
10
10
  const ACCOUNT_TOKEN = process.env["AICOMMANDER_TOKEN"];
11
+ // The /mcp endpoint is account-bound by default (it 401s an unauthenticated caller
12
+ // to drive the OAuth flow). This stdio bridge authenticates with a Bearer token when
13
+ // AICOMMANDER_TOKEN is set; without one it uses the explicit anonymous opt-in
14
+ // (?anonymous=1) so the AIC-code path keeps working.
15
+ const MCP_URL = ACCOUNT_TOKEN ? `${SERVER_URL}/mcp` : `${SERVER_URL}/mcp?anonymous=1`;
11
16
  const server = new McpServer({
12
17
  name: "aicommander",
13
- version: "1.0.15",
18
+ version: "1.0.17",
14
19
  }, {
15
20
  instructions: "AI Commander — remote command execution / remote shell over an outbound-only agent. " +
16
21
  "Use these tools for any SSH-style remote access: connect to a computer/machine/server, " +
@@ -66,7 +71,7 @@ server.registerTool("remote_exec", {
66
71
  .describe("Timeout in milliseconds. Default 300000 (5 min), max 3600000 (1 hr)"),
67
72
  },
68
73
  }, async ({ code, command, cwd, timeout_ms }) => {
69
- const res = await fetch(`${SERVER_URL}/mcp`, {
74
+ const res = await fetch(MCP_URL, {
70
75
  method: "POST",
71
76
  headers: {
72
77
  "Content-Type": "application/json",
@@ -140,7 +145,7 @@ server.registerTool("session_status", {
140
145
  .describe("How the user named the machine, passed exactly as given: an AIC- session code (e.g. AIC-XYZ-1234), or — with an API key — a saved alias/hostname like 'wearfits-m3' or 'aic-wearfits'."),
141
146
  },
142
147
  }, async ({ code }) => {
143
- const res = await fetch(`${SERVER_URL}/mcp`, {
148
+ const res = await fetch(MCP_URL, {
144
149
  method: "POST",
145
150
  headers: {
146
151
  "Content-Type": "application/json",
@@ -168,5 +173,38 @@ server.registerTool("session_status", {
168
173
  content: content,
169
174
  };
170
175
  });
176
+ // Tool: list_machines
177
+ server.registerTool("list_machines", {
178
+ description: "List ALL of the user's machines (the computers/servers linked to their AI Commander account) with each one's live status. USE THIS for fleet-wide questions rather than one named machine — e.g. \"what machines do I have?\", \"which of my computers are online?\", \"list my servers/hosts\" — or when the user wants to act on a machine but hasn't said which yet (call this first to discover the options). Requires an API key (set AICOMMANDER_TOKEN); without it there is no account to list and it returns an error — fall back to session_status with a specific AIC- code. Each entry gives the machine's alias (pass it as `code` to the other tools), whether its agent is online right now, when it was last seen, and whether the link is still awaiting the machine operator's approval. Takes no arguments.",
179
+ inputSchema: {},
180
+ }, async () => {
181
+ const res = await fetch(MCP_URL, {
182
+ method: "POST",
183
+ headers: {
184
+ "Content-Type": "application/json",
185
+ ...(ACCOUNT_TOKEN ? { Authorization: `Bearer ${ACCOUNT_TOKEN}` } : {}),
186
+ },
187
+ body: JSON.stringify({
188
+ jsonrpc: "2.0",
189
+ id: 1,
190
+ method: "tools/call",
191
+ params: { name: "list_machines", arguments: {} },
192
+ }),
193
+ });
194
+ if (!res.ok) {
195
+ const text = await res.text();
196
+ return {
197
+ content: [{ type: "text", text: `Error ${res.status}: ${text}` }],
198
+ isError: true,
199
+ };
200
+ }
201
+ const data = (await res.json());
202
+ const content = data?.result?.content ?? [
203
+ { type: "text", text: JSON.stringify(data) },
204
+ ];
205
+ return {
206
+ content: content,
207
+ };
208
+ });
171
209
  const transport = new StdioServerTransport();
172
210
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aicommander/mcp",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "mcpName": "dev.aicommander/mcp",
5
5
  "description": "MCP server for remote command execution — run shell/bash commands on remote machines, servers and laptops from your AI agent (Claude, Codex, any stdio MCP client). An SSH / Ansible alternative with no exposed SSH, open ports or VPN; drive machines by AIC-… session code or saved alias/hostname.",
6
6
  "keywords": [