remote-access-mcp 3.0.0 → 3.0.2
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/AGENTS.md +79 -0
- package/CHANGELOG.md +25 -0
- package/CONTRIBUTING.md +35 -0
- package/README.fa.md +9 -6
- package/README.md +22 -7
- package/SECURITY.md +41 -0
- package/dist/core/integrations.d.ts +16 -0
- package/dist/core/integrations.d.ts.map +1 -1
- package/dist/core/integrations.js +45 -32
- package/dist/core/integrations.js.map +1 -1
- package/dist/core/webcrypto.d.ts +2 -0
- package/dist/core/webcrypto.d.ts.map +1 -0
- package/dist/core/webcrypto.js +15 -0
- package/dist/core/webcrypto.js.map +1 -0
- package/dist/server/app.d.ts +1 -0
- package/dist/server/app.d.ts.map +1 -1
- package/dist/server/app.js +1 -0
- package/dist/server/app.js.map +1 -1
- package/docs/ai/architecture.md +106 -0
- package/docs/ai/decisions.md +141 -0
- package/docs/ai/security-model.md +114 -0
- package/docs/ai/tools-and-cli.md +152 -0
- package/docs/ai/transport-compatibility.md +85 -0
- package/package.json +19 -10
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js +0 -7
- package/dist/cli.js.map +0 -1
- package/dist/core/fleet.d.ts +0 -71
- package/dist/core/fleet.d.ts.map +0 -1
- package/dist/core/fleet.js +0 -148
- package/dist/core/fleet.js.map +0 -1
- package/dist/tools/fleet.d.ts +0 -4
- package/dist/tools/fleet.d.ts.map +0 -1
- package/dist/tools/fleet.js +0 -39
- package/dist/tools/fleet.js.map +0 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Transport Compatibility
|
|
2
|
+
|
|
3
|
+
Why the server speaks three MCP dialects, and the exact bugs that forced
|
|
4
|
+
each one. This file exists so nobody "simplifies" it away.
|
|
5
|
+
|
|
6
|
+
## The three dialects
|
|
7
|
+
|
|
8
|
+
| # | Dialect | Who speaks it | Handshake | Replies |
|
|
9
|
+
|---|---|---|---|---|
|
|
10
|
+
| 1 | Streamable HTTP, **stateless** | ChatGPT, Grok | POST initialize | inside the POST response; session id ignored |
|
|
11
|
+
| 2 | Streamable HTTP, **stateful** | Claude (new SDK), most reference clients | POST initialize → `Mcp-Session-Id` response header | every request carries the id; GET opens a server→client notification stream |
|
|
12
|
+
| 3 | **Legacy SSE** (2024-11-05) | Claude's connector UI auto-selects it when the URL ends in `/sse` | **GET** → `event: endpoint` frame announces the POST URL + sessionId | replies ride the long-lived GET stream; POSTs are 202 |
|
|
13
|
+
|
|
14
|
+
All three are served on **both** endpoint paths (`/mcp` and `/sse`, plus any
|
|
15
|
+
configured aliases) — the URL does not determine the dialect; the request
|
|
16
|
+
shape does.
|
|
17
|
+
|
|
18
|
+
## Dispatch rules (server/app.ts)
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
POST with Mcp-Session-Id:
|
|
22
|
+
known session → that session's StreamableHTTP transport
|
|
23
|
+
unknown session → 404 "Session not found" (client re-initializes)
|
|
24
|
+
POST initialize (no id) → new stateful session, id in response header
|
|
25
|
+
POST anything else (no id) → stateless throwaway transport (ChatGPT/Grok)
|
|
26
|
+
GET with Mcp-Session-Id → streamable notification stream for that session
|
|
27
|
+
GET without id → legacy SSE handshake (event: endpoint …)
|
|
28
|
+
POST /<token>/<path>/messages?sessionId=… → legacy SSE post-back leg
|
|
29
|
+
DELETE with id → session teardown (204)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`normalizeAccept()` widens every Accept header to
|
|
33
|
+
`application/json, text/event-stream` (GET → `text/event-stream`) before
|
|
34
|
+
the SDK sees it. The SDK enforces the spec strictly and answers 406 to
|
|
35
|
+
`*/*` or single-type Accepts; real clients send all of those.
|
|
36
|
+
|
|
37
|
+
Responses are **SSE-framed** (`enableJsonResponse: false`) — the spec's
|
|
38
|
+
reference behavior, and the framing every dialect we've seen accepts.
|
|
39
|
+
Plain-JSON mode was tried; Claude's connector silently dropped it.
|
|
40
|
+
|
|
41
|
+
## The incident log (each of these shipped and hurt)
|
|
42
|
+
|
|
43
|
+
1. **No session id** → Claude retried initialize every ~60s and reported
|
|
44
|
+
"Couldn't reach <server>". Fix: stateful sessions (v2.2.0),
|
|
45
|
+
`sessions.ts` store with 30-min idle TTL, 200 cap, per-token binding.
|
|
46
|
+
2. **406 on honest Accepts** → clients sending `*/*` or
|
|
47
|
+
`text/event-stream` alone got rejected by the SDK's strict check.
|
|
48
|
+
Fix: normalizeAccept (v2.2.1).
|
|
49
|
+
3. **`Unknown SSE event: endpoint`** → the legacy transport was bolted on
|
|
50
|
+
by hijacking **every** GET; a stateful client opening its notification
|
|
51
|
+
stream received the legacy `event: endpoint` frame and aborted its whole
|
|
52
|
+
TaskGroup. Fix: dispatch GETs by the Mcp-Session-Id header (v2.2.2/3).
|
|
53
|
+
4. **Plain-JSON responses dropped** → initialize answered 200 +
|
|
54
|
+
`application/json`, Claude read it and silently gave up. Fix: SSE
|
|
55
|
+
framing everywhere (v2.2.4). Diagnosed with a byte-logging wire proxy:
|
|
56
|
+
the client's exact headers/body made it obvious Claude got a *valid*
|
|
57
|
+
reply and still walked away — only the framing differed.
|
|
58
|
+
|
|
59
|
+
## Verification (do not trust, run)
|
|
60
|
+
|
|
61
|
+
The byte-exact Claude simulation lives in git history
|
|
62
|
+
(`python-httpx/0.28.1` + `clientInfo.name: "Anthropic"`); the pinned suite
|
|
63
|
+
covers the matrix:
|
|
64
|
+
|
|
65
|
+
- `tests/sessions.test.ts` — stateful handshake, routing, hijack-refusal,
|
|
66
|
+
DELETE teardown, stateless fallback
|
|
67
|
+
- `tests/get-dispatch.test.ts` — GET with id never emits `endpoint`; GET
|
|
68
|
+
without id always does
|
|
69
|
+
- `tests/legacy-sse.test.ts` — full 2024-11-05 handshake over `/sse` and
|
|
70
|
+
`/mcp`, sessionId-less POST-back → 400, unknown → 404, cross-token → 403
|
|
71
|
+
- `tests/accept-compat.test.ts` — six Accept variants all initialize
|
|
72
|
+
|
|
73
|
+
## Edge / proxy notes (production config)
|
|
74
|
+
|
|
75
|
+
- nginx: `proxy_buffering off`, `proxy_request_buffering off`,
|
|
76
|
+
`proxy_set_header Connection ""`, `chunked_transfer_encoding on`,
|
|
77
|
+
`gzip off`, `add_header X-Accel-Buffering no`, read/send timeouts 3600s —
|
|
78
|
+
a legacy SSE stream idles between tool calls; the default 60s proxy
|
|
79
|
+
timeouts kill it. The gateway sends `: keepalive` comments every 15s so
|
|
80
|
+
intermediate hops don't reap the stream.
|
|
81
|
+
- Cloudflare proxies all three dialects fine (verified from the edge).
|
|
82
|
+
- Quick tunnels on filtered networks can register but not carry traffic —
|
|
83
|
+
`ramcp tunnel` self-verifies and warns instead of handing out a dead URL
|
|
84
|
+
(that's environment, not protocol; http2-over-TCP is forced for the same
|
|
85
|
+
reason — QUIC is blocked on some ISPs).
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remote-access-mcp",
|
|
3
|
-
"version": "3.0.
|
|
4
|
-
"description": "Turn any
|
|
3
|
+
"version": "3.0.2",
|
|
4
|
+
"description": "Turn any machine into a secure AI-agent-accessible endpoint via MCP. Connect ChatGPT, Claude, Grok, and other MCP clients to files, shell, git, services, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"remote-access-mcp": "dist/cli.js",
|
|
@@ -12,10 +12,15 @@
|
|
|
12
12
|
"README.md",
|
|
13
13
|
"README.fa.md",
|
|
14
14
|
"LICENSE",
|
|
15
|
-
"install.sh"
|
|
15
|
+
"install.sh",
|
|
16
|
+
"AGENTS.md",
|
|
17
|
+
"SECURITY.md",
|
|
18
|
+
"CHANGELOG.md",
|
|
19
|
+
"CONTRIBUTING.md",
|
|
20
|
+
"docs/ai"
|
|
16
21
|
],
|
|
17
22
|
"engines": {
|
|
18
|
-
"node": ">=
|
|
23
|
+
"node": ">=18"
|
|
19
24
|
},
|
|
20
25
|
"scripts": {
|
|
21
26
|
"build": "tsc",
|
|
@@ -28,14 +33,18 @@
|
|
|
28
33
|
},
|
|
29
34
|
"keywords": [
|
|
30
35
|
"mcp",
|
|
36
|
+
"mcp-server",
|
|
37
|
+
"mcp-gateway",
|
|
31
38
|
"model-context-protocol",
|
|
32
|
-
"ai",
|
|
33
|
-
"
|
|
39
|
+
"ai-agent",
|
|
40
|
+
"ai-ops",
|
|
34
41
|
"remote-access",
|
|
35
42
|
"server-management",
|
|
43
|
+
"infrastructure",
|
|
44
|
+
"devops",
|
|
45
|
+
"linux",
|
|
36
46
|
"chatgpt",
|
|
37
|
-
"claude"
|
|
38
|
-
"devops"
|
|
47
|
+
"claude"
|
|
39
48
|
],
|
|
40
49
|
"author": "Amir Ali Manzar (https://amiralimanzar.ir)",
|
|
41
50
|
"license": "MIT",
|
|
@@ -49,13 +58,13 @@
|
|
|
49
58
|
"homepage": "https://github.com/AmirAliManzar/remote-access-mcp#readme",
|
|
50
59
|
"dependencies": {
|
|
51
60
|
"@modelcontextprotocol/sdk": "^1.20.0",
|
|
52
|
-
"@upstash/context7-mcp": "^4.0.4",
|
|
53
61
|
"better-sqlite3": "^11.6.0",
|
|
54
|
-
"codebase-memory-mcp": "^0.10.8",
|
|
55
62
|
"express": "^4.21.0",
|
|
56
63
|
"zod": "^3.24.0"
|
|
57
64
|
},
|
|
58
65
|
"optionalDependencies": {
|
|
66
|
+
"@upstash/context7-mcp": "^4.0.4",
|
|
67
|
+
"codebase-memory-mcp": "^0.10.8",
|
|
59
68
|
"context-mode": "^1.0.169"
|
|
60
69
|
},
|
|
61
70
|
"devDependencies": {
|
package/dist/cli.d.ts
DELETED
package/dist/cli.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
DELETED
package/dist/cli.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE;IACtC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/core/fleet.d.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fleet: run tools on remote machines over SSH.
|
|
3
|
-
*
|
|
4
|
-
* Design decisions, deliberately narrow:
|
|
5
|
-
*
|
|
6
|
-
* - Outbound SSH only. The gateway machine holds one private key; remote
|
|
7
|
-
* machines need nothing installed except an SSH server and a POSIX shell.
|
|
8
|
-
* No agent daemons, no listening ports, no new attack surface inbound.
|
|
9
|
-
*
|
|
10
|
-
* - Per-host allowlists of tools. `ramcp fleet add --tools shell,fs` is the
|
|
11
|
-
* whole security model: a host that was never granted a tool group
|
|
12
|
-
* refuses it with a clear error. Local-only tools (schedule, policy
|
|
13
|
-
* management, ops) ignore `host` entirely.
|
|
14
|
-
*
|
|
15
|
-
* - File transfer for fs tools is piped over stdin via base64, so writes
|
|
16
|
-
* don't touch the remote disk with temp files (which would race, leak
|
|
17
|
-
* into other users' listings, or fail on full filesystems).
|
|
18
|
-
*
|
|
19
|
-
* - SSH_BIN env override exists for tests (fake ssh) and for Windows hosts
|
|
20
|
-
* that want a specific OpenSSH path.
|
|
21
|
-
*/
|
|
22
|
-
export interface FleetHost {
|
|
23
|
-
name: string;
|
|
24
|
-
host: string;
|
|
25
|
-
port?: number;
|
|
26
|
-
tools: string[];
|
|
27
|
-
note?: string;
|
|
28
|
-
added: string;
|
|
29
|
-
}
|
|
30
|
-
/** Tool group → fleet capability check. Local-only groups have no remote path. */
|
|
31
|
-
export declare const FLEET_CAPABILITIES: readonly ["shell", "fs", "services", "packages", "logs"];
|
|
32
|
-
export declare function isFleetCapability(g: string): boolean;
|
|
33
|
-
export declare function sshBin(): string;
|
|
34
|
-
export interface SshOpts {
|
|
35
|
-
timeoutMs?: number;
|
|
36
|
-
stdin?: string;
|
|
37
|
-
}
|
|
38
|
-
/** Run one command over SSH. Throws on non-zero exit with combined output. */
|
|
39
|
-
export declare function sshRun(host: string, port: number | undefined, command: string, opts?: SshOpts): Promise<{
|
|
40
|
-
stdout: string;
|
|
41
|
-
stderr: string;
|
|
42
|
-
}>;
|
|
43
|
-
/** Exit status of a probe command; 0 = reachable. */
|
|
44
|
-
export declare function fleetProbe(host: FleetHost): Promise<{
|
|
45
|
-
ok: boolean;
|
|
46
|
-
detail: string;
|
|
47
|
-
}>;
|
|
48
|
-
/** shell group */
|
|
49
|
-
export declare function buildRunCommand(command: string, cwd?: string, timeoutMs?: number): string;
|
|
50
|
-
/** fs group */
|
|
51
|
-
export declare function buildReadCommand(path: string): string;
|
|
52
|
-
export declare function buildWriteCommand(path: string, content: string, mkdir: boolean): string;
|
|
53
|
-
export declare function buildDeleteCommand(path: string): string;
|
|
54
|
-
export declare function buildListCommand(path: string): string;
|
|
55
|
-
export declare function buildFileInfoCommand(path: string): string;
|
|
56
|
-
export declare function buildTailCommand(path: string, lines: number): string;
|
|
57
|
-
export declare function buildSearchCommand(path: string, pattern: string, maxResults: number): string;
|
|
58
|
-
/** services group */
|
|
59
|
-
export declare function buildServiceStatusCommand(unit: string): string;
|
|
60
|
-
export declare function buildServiceActionCommand(unit: string, action: string): string;
|
|
61
|
-
/** packages group */
|
|
62
|
-
export declare function buildPackageListCommand(filter?: string): string;
|
|
63
|
-
/** logs group */
|
|
64
|
-
export declare function buildJournalCommand(unit: string, lines: number): string;
|
|
65
|
-
export declare class FleetError extends Error {
|
|
66
|
-
constructor(msg: string);
|
|
67
|
-
}
|
|
68
|
-
export declare function findHost(hosts: FleetHost[], name: string): FleetHost;
|
|
69
|
-
/** Throws unless the host was granted the tool group at `ramcp fleet add` time. */
|
|
70
|
-
export declare function assertCapability(hosts: FleetHost[], name: string, group: string): FleetHost;
|
|
71
|
-
//# sourceMappingURL=fleet.d.ts.map
|
package/dist/core/fleet.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fleet.d.ts","sourceRoot":"","sources":["../../src/core/fleet.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,0DAA2D,CAAC;AAE3F,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,MAAM,IAAI,MAAM,CAE/B;AAED,MAAM,WAAW,OAAO;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,8EAA8E;AAC9E,wBAAsB,MAAM,CAC1B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,OAAY,GACjB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA0C7C;AAED,qDAAqD;AACrD,wBAAsB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAO1F;AAYD,kBAAkB;AAClB,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,SAAU,GAAG,MAAM,CAM1F;AAED,eAAe;AACf,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAIvF;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAI5F;AAED,qBAAqB;AACrB,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED,qBAAqB;AACrB,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAI/D;AAED,iBAAiB;AACjB,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvE;AAMD,qBAAa,UAAW,SAAQ,KAAK;gBACvB,GAAG,EAAE,MAAM;CACxB;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAIpE;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAM3F"}
|
package/dist/core/fleet.js
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { execFile, spawn } from 'node:child_process';
|
|
2
|
-
import { promisify } from 'node:util';
|
|
3
|
-
const exec = promisify(execFile);
|
|
4
|
-
/** Tool group → fleet capability check. Local-only groups have no remote path. */
|
|
5
|
-
export const FLEET_CAPABILITIES = ['shell', 'fs', 'services', 'packages', 'logs'];
|
|
6
|
-
export function isFleetCapability(g) {
|
|
7
|
-
return FLEET_CAPABILITIES.includes(g);
|
|
8
|
-
}
|
|
9
|
-
export function sshBin() {
|
|
10
|
-
return process.env.SSH_BIN || 'ssh';
|
|
11
|
-
}
|
|
12
|
-
/** Run one command over SSH. Throws on non-zero exit with combined output. */
|
|
13
|
-
export async function sshRun(host, port, command, opts = {}) {
|
|
14
|
-
const args = [
|
|
15
|
-
// -T: no pty (we want clean pipes), BatchMode: never prompt — a hung
|
|
16
|
-
// password prompt inside an AI tool call is a deadlock.
|
|
17
|
-
'-o', 'BatchMode=yes',
|
|
18
|
-
'-o', 'StrictHostKeyChecking=accept-new',
|
|
19
|
-
'-o', 'ConnectTimeout=10',
|
|
20
|
-
'-o', 'ServerAliveInterval=15',
|
|
21
|
-
];
|
|
22
|
-
if (port)
|
|
23
|
-
args.push('-p', String(port));
|
|
24
|
-
args.push(host, '--', command);
|
|
25
|
-
// NOTE: promisify(execFile) does not forward the `input` option (a known
|
|
26
|
-
// footgun — the child's stdin never closes and the call hangs to timeout).
|
|
27
|
-
// stdin piping is therefore done by hand: write, then end.
|
|
28
|
-
if (opts.stdin !== undefined) {
|
|
29
|
-
return await new Promise((resolve, reject) => {
|
|
30
|
-
const child = spawn(sshBin(), args, { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
31
|
-
let stdout = '';
|
|
32
|
-
let stderr = '';
|
|
33
|
-
const timer = setTimeout(() => {
|
|
34
|
-
child.kill();
|
|
35
|
-
reject(new Error(`ssh timed out after ${Math.round((opts.timeoutMs ?? 120_000) / 1000)}s`));
|
|
36
|
-
}, opts.timeoutMs ?? 120_000);
|
|
37
|
-
child.stdout.on('data', c => { stdout += c; });
|
|
38
|
-
child.stderr.on('data', c => { stderr += c; });
|
|
39
|
-
child.on('error', e => { clearTimeout(timer); reject(e); });
|
|
40
|
-
child.on('close', code => {
|
|
41
|
-
clearTimeout(timer);
|
|
42
|
-
if (code === 0)
|
|
43
|
-
resolve({ stdout, stderr });
|
|
44
|
-
else
|
|
45
|
-
reject(Object.assign(new Error(`ssh exited with ${code}`), { stdout, stderr }));
|
|
46
|
-
});
|
|
47
|
-
child.stdin.write(opts.stdin);
|
|
48
|
-
child.stdin.end();
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
const { stdout, stderr } = await exec(sshBin(), args, {
|
|
52
|
-
timeout: opts.timeoutMs ?? 120_000,
|
|
53
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
54
|
-
});
|
|
55
|
-
return { stdout, stderr };
|
|
56
|
-
}
|
|
57
|
-
/** Exit status of a probe command; 0 = reachable. */
|
|
58
|
-
export async function fleetProbe(host) {
|
|
59
|
-
try {
|
|
60
|
-
const { stdout } = await sshRun(host.host, host.port, 'echo ramcp-ok', { timeoutMs: 15_000 });
|
|
61
|
-
return { ok: stdout.includes('ramcp-ok'), detail: stdout.trim() };
|
|
62
|
-
}
|
|
63
|
-
catch (e) {
|
|
64
|
-
return { ok: false, detail: (e.stderr || e.stdout || e.message || '').split('\n')[0].slice(0, 120) };
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
// Command builders — single source of truth for what runs remotely.
|
|
69
|
-
// All of these are invoked via `ssh … -- command`, so each one gets ONE
|
|
70
|
-
// shell string. Keep them quoting-tight: paths arrive validated from the
|
|
71
|
-
// tool schema (zod), but we still quote everything with double quotes.
|
|
72
|
-
// ---------------------------------------------------------------------------
|
|
73
|
-
const q = (s) => `"${s.replace(/(["\\$`])/g, '\\$1')}"`;
|
|
74
|
-
const b64 = (s) => Buffer.from(s, 'utf8').toString('base64');
|
|
75
|
-
/** shell group */
|
|
76
|
-
export function buildRunCommand(command, cwd, timeoutMs = 120_000) {
|
|
77
|
-
const secs = Math.min(Math.round(timeoutMs / 1000), 600);
|
|
78
|
-
const inner = cwd
|
|
79
|
-
? `cd ${q(cwd)} 2>/dev/null && ${command}`
|
|
80
|
-
: command;
|
|
81
|
-
return `timeout ${secs} sh -c ${q(inner)} 2>&1`;
|
|
82
|
-
}
|
|
83
|
-
/** fs group */
|
|
84
|
-
export function buildReadCommand(path) {
|
|
85
|
-
return `[ -f ${q(path)} ] && base64 ${q(path)}`;
|
|
86
|
-
}
|
|
87
|
-
export function buildWriteCommand(path, content, mkdir) {
|
|
88
|
-
const pre = mkdir ? `mkdir -p ${q(path.replace(/\/[^/]*$/, ''))} && ` : '';
|
|
89
|
-
// stdin carries the base64; the command decodes it. No temp files.
|
|
90
|
-
return `${pre}base64 -d > ${q(path)}`;
|
|
91
|
-
}
|
|
92
|
-
export function buildDeleteCommand(path) {
|
|
93
|
-
return `rm -rf ${q(path)}`;
|
|
94
|
-
}
|
|
95
|
-
export function buildListCommand(path) {
|
|
96
|
-
// trailing / on dirs; -F suffixes symlinks with @
|
|
97
|
-
return `ls -1F ${q(path)} 2>&1 | head -2000`;
|
|
98
|
-
}
|
|
99
|
-
export function buildFileInfoCommand(path) {
|
|
100
|
-
return `stat ${q(path)} 2>&1`;
|
|
101
|
-
}
|
|
102
|
-
export function buildTailCommand(path, lines) {
|
|
103
|
-
return `tail -n ${Math.max(1, Math.min(lines, 1000))} ${q(path)} 2>&1`;
|
|
104
|
-
}
|
|
105
|
-
export function buildSearchCommand(path, pattern, maxResults) {
|
|
106
|
-
// pattern is ERE; validated as a string by zod, quoted single to avoid interpolation
|
|
107
|
-
const p = pattern.replace(/'/g, `'\\''`);
|
|
108
|
-
return `grep -rEn ${q(p)} ${q(path)} 2>/dev/null | head -${Math.min(maxResults, 200)} || echo "(no matches)"`;
|
|
109
|
-
}
|
|
110
|
-
/** services group */
|
|
111
|
-
export function buildServiceStatusCommand(unit) {
|
|
112
|
-
return `systemctl is-active ${q(unit)}; systemctl is-enabled ${q(unit)} 2>&1`;
|
|
113
|
-
}
|
|
114
|
-
export function buildServiceActionCommand(unit, action) {
|
|
115
|
-
return `systemctl ${q(action)} ${q(unit)} 2>&1`;
|
|
116
|
-
}
|
|
117
|
-
/** packages group */
|
|
118
|
-
export function buildPackageListCommand(filter) {
|
|
119
|
-
const base = `dpkg-query -W -f '\"\${Package}\\t\${Version}\\n\"' 2>/dev/null`;
|
|
120
|
-
if (!filter)
|
|
121
|
-
return base;
|
|
122
|
-
return `${base} | grep -i ${q(filter)} || true`;
|
|
123
|
-
}
|
|
124
|
-
/** logs group */
|
|
125
|
-
export function buildJournalCommand(unit, lines) {
|
|
126
|
-
return `journalctl -u ${q(unit)} -n ${Math.min(lines, 500)} --no-pager -o short-iso 2>&1 | tail -${Math.min(lines, 500)}`;
|
|
127
|
-
}
|
|
128
|
-
// ---------------------------------------------------------------------------
|
|
129
|
-
// Host lookup + capability gate
|
|
130
|
-
// ---------------------------------------------------------------------------
|
|
131
|
-
export class FleetError extends Error {
|
|
132
|
-
constructor(msg) { super(msg); this.name = 'FleetError'; }
|
|
133
|
-
}
|
|
134
|
-
export function findHost(hosts, name) {
|
|
135
|
-
const h = hosts.find(h => h.name === name);
|
|
136
|
-
if (!h)
|
|
137
|
-
throw new FleetError(`Unknown fleet host "${name}". Known: ${hosts.map(h => h.name).join(', ') || '(none)'}`);
|
|
138
|
-
return h;
|
|
139
|
-
}
|
|
140
|
-
/** Throws unless the host was granted the tool group at `ramcp fleet add` time. */
|
|
141
|
-
export function assertCapability(hosts, name, group) {
|
|
142
|
-
const h = findHost(hosts, name);
|
|
143
|
-
if (!h.tools.includes(group)) {
|
|
144
|
-
throw new FleetError(`Host "${name}" does not allow the ${group} tool group (allowed: ${h.tools.join(', ') || 'none'}). Grant it with: ramcp fleet edit ${name} --tools ${group}`);
|
|
145
|
-
}
|
|
146
|
-
return h;
|
|
147
|
-
}
|
|
148
|
-
//# sourceMappingURL=fleet.js.map
|
package/dist/core/fleet.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fleet.js","sourceRoot":"","sources":["../../src/core/fleet.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/fleet.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fleet.d.ts","sourceRoot":"","sources":["../../src/tools/fleet.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAetD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CA+B5E"}
|
package/dist/tools/fleet.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { fleetProbe } from '../core/fleet.js';
|
|
2
|
-
/**
|
|
3
|
-
* Fleet meta-tools: listing and probing the machines this gateway can drive.
|
|
4
|
-
* The actual remote operations (run_command, read_file, …) live in their own
|
|
5
|
-
* suites — each gained an optional `host` parameter that routes over SSH
|
|
6
|
-
* when provided. This split keeps one tool per verb (the AI does not have
|
|
7
|
-
* to learn "remote_run_command") while the per-host allowlist gates access.
|
|
8
|
-
*/
|
|
9
|
-
function hostList(ctx) {
|
|
10
|
-
return ctx.cfg.fleet?.hosts || [];
|
|
11
|
-
}
|
|
12
|
-
export function registerFleetTools(server, ctx) {
|
|
13
|
-
// ---- fleet_list ---------------------------------------------------------
|
|
14
|
-
server.registerTool('fleet_list', {
|
|
15
|
-
description: 'List fleet machines this gateway can reach over SSH, with their granted tool groups.',
|
|
16
|
-
inputSchema: {},
|
|
17
|
-
}, async () => {
|
|
18
|
-
const hosts = hostList(ctx);
|
|
19
|
-
if (!hosts.length)
|
|
20
|
-
return { content: [{ type: 'text', text: '(no fleet hosts — add with `ramcp fleet add`)' }] };
|
|
21
|
-
const out = hosts.map(h => `${h.name.padEnd(14)} ${h.host}${h.port ? ':' + h.port : ''} tools: ${h.tools.join(',') || '(none)'}${h.note ? ' — ' + h.note : ''}`);
|
|
22
|
-
return { content: [{ type: 'text', text: out.join('\n') }] };
|
|
23
|
-
});
|
|
24
|
-
// ---- fleet_status ----------------------------------------------------------
|
|
25
|
-
server.registerTool('fleet_status', {
|
|
26
|
-
description: 'Probe every fleet machine over SSH. Reports reachable/unreachable per host.',
|
|
27
|
-
inputSchema: {},
|
|
28
|
-
}, async () => {
|
|
29
|
-
const hosts = hostList(ctx);
|
|
30
|
-
if (!hosts.length)
|
|
31
|
-
return { content: [{ type: 'text', text: '(no fleet hosts)' }] };
|
|
32
|
-
const results = await Promise.all(hosts.map(async (h) => {
|
|
33
|
-
const r = await fleetProbe(h);
|
|
34
|
-
return `${r.ok ? '✔' : '✖'} ${h.name.padEnd(14)} ${h.host}${h.port ? ':' + h.port : ''} ${r.ok ? 'reachable' : 'unreachable — ' + r.detail}`;
|
|
35
|
-
}));
|
|
36
|
-
return { content: [{ type: 'text', text: results.join('\n') }] };
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
//# sourceMappingURL=fleet.js.map
|
package/dist/tools/fleet.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fleet.js","sourceRoot":"","sources":["../../src/tools/fleet.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAkB,MAAM,kBAAkB,CAAC;AAE9D;;;;;;GAMG;AAEH,SAAS,QAAQ,CAAC,GAAgB;IAChC,OAAO,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAiB,EAAE,GAAgB;IACpE,4EAA4E;IAC5E,MAAM,CAAC,YAAY,CAAC,YAAY,EAC9B;QACE,WAAW,EAAE,sFAAsF;QACnG,WAAW,EAAE,EAAE;KAChB,EACD,KAAK,IAAI,EAAE;QACT,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,+CAA+C,EAAE,CAAC,EAAE,CAAC;QACjH,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CACxB,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACvI,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEL,+EAA+E;IAC/E,MAAM,CAAC,YAAY,CAAC,cAAc,EAChC;QACE,WAAW,EAAE,6EAA6E;QAC1F,WAAW,EAAE,EAAE;KAChB,EACD,KAAK,IAAI,EAAE;QACT,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,EAAE,CAAC;QACpF,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAC,CAAC,EAAC,EAAE;YACpD,MAAM,CAAC,GAAG,MAAM,UAAU,CAAC,CAAC,CAAC,CAAC;YAC9B,OAAO,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,gBAAgB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;QAC/I,CAAC,CAAC,CAAC,CAAC;QACJ,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IACnE,CAAC,CAAC,CAAC;AACP,CAAC"}
|