@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 +26 -2
- package/dist/bin/mcp.js +41 -3
- package/package.json +1 -1
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
|
|
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
|
|
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.
|
|
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(
|
|
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(
|
|
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.
|
|
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": [
|