frely-cli 0.9.5 → 0.9.7

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.
Files changed (78) hide show
  1. package/README.md +30 -8
  2. package/README.zh-CN.md +18 -7
  3. package/dist/agent-help.d.ts +110 -14
  4. package/dist/agent-help.js +20 -9
  5. package/dist/agent-help.js.map +1 -1
  6. package/dist/auth.d.ts +14 -1
  7. package/dist/auth.js +14 -22
  8. package/dist/auth.js.map +1 -1
  9. package/dist/cloud.d.ts +11 -1
  10. package/dist/cloud.js +73 -1
  11. package/dist/cloud.js.map +1 -1
  12. package/dist/computer/command.d.ts +6 -0
  13. package/dist/computer/command.js +53 -0
  14. package/dist/computer/command.js.map +1 -0
  15. package/dist/computer/guard.d.ts +18 -0
  16. package/dist/computer/guard.js +82 -0
  17. package/dist/computer/guard.js.map +1 -0
  18. package/dist/computer/image.d.ts +22 -0
  19. package/dist/computer/image.js +183 -0
  20. package/dist/computer/image.js.map +1 -0
  21. package/dist/computer/ocu.d.ts +40 -0
  22. package/dist/computer/ocu.js +59 -0
  23. package/dist/computer/ocu.js.map +1 -0
  24. package/dist/computer/runtime.d.ts +22 -0
  25. package/dist/computer/runtime.js +85 -0
  26. package/dist/computer/runtime.js.map +1 -0
  27. package/dist/computer/server.d.ts +11 -0
  28. package/dist/computer/server.js +31 -0
  29. package/dist/computer/server.js.map +1 -0
  30. package/dist/computer/state.d.ts +11 -0
  31. package/dist/computer/state.js +17 -0
  32. package/dist/computer/state.js.map +1 -0
  33. package/dist/computer/toolset.d.ts +22 -0
  34. package/dist/computer/toolset.js +112 -0
  35. package/dist/computer/toolset.js.map +1 -0
  36. package/dist/device/protocol.d.ts +2 -0
  37. package/dist/device/protocol.js +7 -1
  38. package/dist/device/protocol.js.map +1 -1
  39. package/dist/device/relay-client.d.ts +3 -0
  40. package/dist/device/relay-client.js +7 -1
  41. package/dist/device/relay-client.js.map +1 -1
  42. package/dist/index.js +103 -40
  43. package/dist/index.js.map +1 -1
  44. package/dist/local-mcp-command.d.ts +10 -0
  45. package/dist/local-mcp-command.js +105 -0
  46. package/dist/local-mcp-command.js.map +1 -0
  47. package/dist/mcp-authorization.d.ts +11 -2
  48. package/dist/mcp-authorization.js +21 -6
  49. package/dist/mcp-authorization.js.map +1 -1
  50. package/dist/mcp-command.d.ts +2 -1
  51. package/dist/mcp-command.js +18 -2
  52. package/dist/mcp-command.js.map +1 -1
  53. package/dist/provider/control.d.ts +8 -2
  54. package/dist/provider/control.js.map +1 -1
  55. package/dist/runtime/local-mcp.d.ts +114 -0
  56. package/dist/runtime/local-mcp.js +448 -0
  57. package/dist/runtime/local-mcp.js.map +1 -0
  58. package/dist/runtime/mcp.d.ts +20 -0
  59. package/dist/runtime/mcp.js +29 -0
  60. package/dist/runtime/mcp.js.map +1 -1
  61. package/dist/runtime/relay-mcp.d.ts +3 -1
  62. package/dist/runtime/relay-mcp.js +5 -1
  63. package/dist/runtime/relay-mcp.js.map +1 -1
  64. package/dist/runtime/relay-session.d.ts +2 -2
  65. package/dist/runtime/relay-session.js +1 -1
  66. package/dist/runtime/relay-session.js.map +1 -1
  67. package/dist/runtime/sandbox.js +3 -0
  68. package/dist/runtime/sandbox.js.map +1 -1
  69. package/dist/skill/cloud-item.d.ts +38 -0
  70. package/dist/skill/cloud-item.js +151 -0
  71. package/dist/skill/cloud-item.js.map +1 -0
  72. package/dist/upgrade/maintenance.js +1 -1
  73. package/dist/upgrade/maintenance.js.map +1 -1
  74. package/dist/upgrade/service-refresh.js +1 -1
  75. package/dist/upgrade/service-refresh.js.map +1 -1
  76. package/dist/upgrade/update.js +2 -2
  77. package/dist/upgrade/update.js.map +1 -1
  78. package/package.json +1 -1
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Device-local MCP servers (plan mcp/本机MCP转发-方案.md §9).
3
+ *
4
+ * The Relay never learns how a local server is reached: it only knows the
5
+ * names the owner enabled on the web console. Everything here stays on the
6
+ * device: discovery of loopback HTTP servers, the manual list (HTTP or stdio),
7
+ * the MCP clients, and the policy that only enabled names are callable.
8
+ */
9
+ export declare const LOCAL_MCP_NAME: RegExp;
10
+ export declare const LOCAL_MCP_CAPABILITY_LIMIT = 24;
11
+ export declare const LOCAL_MCP_DEFAULT_TIMEOUT_MS = 60000;
12
+ export declare const LOCAL_MCP_MAX_TIMEOUT_MS = 120000;
13
+ export declare const LOCAL_MCP_TEXT_LIMIT: number;
14
+ export declare const LOCAL_MCP_BINARY_LIMIT: number;
15
+ export type HttpFlavor = "streamable" | "sse";
16
+ export interface LocalMcpHttpEntry {
17
+ name: string;
18
+ source: "discovered" | "manual";
19
+ transport: "http";
20
+ url: string;
21
+ flavor?: HttpFlavor;
22
+ headers?: Record<string, string>;
23
+ }
24
+ export interface LocalMcpStdioEntry {
25
+ name: string;
26
+ source: "manual";
27
+ transport: "stdio";
28
+ command: string;
29
+ args: string[];
30
+ env?: Record<string, string>;
31
+ /** PATH captured when the entry was added, so a background service finds the same binaries. */
32
+ path?: string;
33
+ }
34
+ export type LocalMcpEntry = LocalMcpHttpEntry | LocalMcpStdioEntry;
35
+ export type ManualLocalMcpEntry = Omit<LocalMcpHttpEntry, "source"> | Omit<LocalMcpStdioEntry, "source">;
36
+ export interface LocalMcpToolResult {
37
+ content: unknown[];
38
+ isError?: boolean;
39
+ }
40
+ export declare function localMcpRegistryPath(): string;
41
+ export declare function loadManualEntries(path?: string): Promise<LocalMcpEntry[]>;
42
+ export declare function addManualEntry(entry: ManualLocalMcpEntry, path?: string): Promise<void>;
43
+ export declare function removeManualEntry(name: string, path?: string): Promise<void>;
44
+ /** Only loopback HTTP(S) targets are ever contacted (plan F5). */
45
+ export declare function assertLoopbackUrl(value: string): URL;
46
+ export declare function parseLoopbackListeners(platform: NodeJS.Platform, outputs: readonly string[]): number[];
47
+ /** TCP ports that only accept loopback connections, found without extra dependencies. */
48
+ export declare function listLoopbackPorts(platform?: NodeJS.Platform): Promise<number[]>;
49
+ export interface ProbeHit {
50
+ url: string;
51
+ flavor: HttpFlavor;
52
+ serverName?: string;
53
+ }
54
+ /** One standard `initialize` (or SSE handshake) per port; nothing is sent beyond that and redirects are never followed. */
55
+ export declare function probeHttpMcp(port: number, timeoutMs?: number): Promise<ProbeHit | null>;
56
+ export interface DiscoveryDeps {
57
+ listPorts?: () => Promise<number[]>;
58
+ probe?: (port: number) => Promise<ProbeHit | null>;
59
+ }
60
+ export declare function discoverLoopbackMcps(deps?: DiscoveryDeps, skipPorts?: ReadonlySet<number>): Promise<Array<ProbeHit & {
61
+ port: number;
62
+ }>>;
63
+ export declare function slugName(value: string | undefined): string;
64
+ /** Stable names: manual entries keep theirs, discovered ones use the server's own name and get a numeric suffix on clashes. */
65
+ export declare function nameDiscovered(hits: Array<ProbeHit & {
66
+ port: number;
67
+ }>, taken: Iterable<string>): LocalMcpHttpEntry[];
68
+ export interface LocalMcpHubOptions {
69
+ discovery?: DiscoveryDeps;
70
+ loadManual?: () => Promise<LocalMcpEntry[]>;
71
+ idleMs?: number;
72
+ refreshMs?: number;
73
+ log?: (message: string) => void;
74
+ }
75
+ export declare class LocalMcpHub {
76
+ private readonly options;
77
+ private entries;
78
+ private refreshedAt;
79
+ private refreshing;
80
+ private timer;
81
+ private readonly pool;
82
+ private readonly connecting;
83
+ constructor(options?: LocalMcpHubOptions);
84
+ /** Begin periodic discovery and idle cleanup; both timers are unref'd. */
85
+ start(): void;
86
+ close(): Promise<void>;
87
+ refresh(): Promise<void>;
88
+ private scan;
89
+ ensureFresh(maxAgeMs?: number): Promise<void>;
90
+ snapshot(): readonly LocalMcpEntry[];
91
+ /** Names and transports for the web console; commands, URLs and secrets never leave the device. */
92
+ capabilities(): Array<{
93
+ name: string;
94
+ transport: "http" | "stdio";
95
+ }>;
96
+ /** `local_mcp_list`: enabled servers, or one enabled server's tool definitions. */
97
+ list(enabled: readonly string[], server?: string, signal?: AbortSignal): Promise<unknown>;
98
+ /** `local_mcp_call`: forwards one tools/call to an enabled server and bounds the result. */
99
+ call(enabled: readonly string[], server: string, tool: string, args: Record<string, unknown>, options?: {
100
+ timeoutMs?: number;
101
+ signal?: AbortSignal;
102
+ }): Promise<LocalMcpToolResult>;
103
+ private requireEnabled;
104
+ private client;
105
+ private connect;
106
+ private closeIdle;
107
+ }
108
+ /** Resolve a bare command against PATH so a background service with a different PATH still finds it. */
109
+ export declare function resolveCommand(command: string, pathValue?: string): Promise<string>;
110
+ /** Bounds what one local MCP call can put on the relay: 1 MiB of text, 6 MiB of binary content. */
111
+ export declare function shapeToolResult(result: {
112
+ content?: unknown;
113
+ isError?: unknown;
114
+ }): LocalMcpToolResult;
@@ -0,0 +1,448 @@
1
+ import { execFile } from "node:child_process";
2
+ import { access, constants, readFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { delimiter, dirname, isAbsolute, join } from "node:path";
5
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
7
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
8
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
9
+ import { ensureCredentialDirectory, readPrivateFile, writePrivateFile } from "../credential-file.js";
10
+ import { VERSION } from "../version.js";
11
+ import { safeEnv } from "./workspace.js";
12
+ /**
13
+ * Device-local MCP servers (plan mcp/本机MCP转发-方案.md §9).
14
+ *
15
+ * The Relay never learns how a local server is reached: it only knows the
16
+ * names the owner enabled on the web console. Everything here stays on the
17
+ * device: discovery of loopback HTTP servers, the manual list (HTTP or stdio),
18
+ * the MCP clients, and the policy that only enabled names are callable.
19
+ */
20
+ export const LOCAL_MCP_NAME = /^[a-z0-9][a-z0-9-]{0,31}$/u;
21
+ export const LOCAL_MCP_CAPABILITY_LIMIT = 24;
22
+ export const LOCAL_MCP_DEFAULT_TIMEOUT_MS = 60_000;
23
+ export const LOCAL_MCP_MAX_TIMEOUT_MS = 120_000;
24
+ export const LOCAL_MCP_TEXT_LIMIT = 1024 * 1024;
25
+ export const LOCAL_MCP_BINARY_LIMIT = 6 * 1024 * 1024;
26
+ const PROBE_TIMEOUT_MS = 1_000;
27
+ const CONNECT_TIMEOUT_MS = 10_000;
28
+ const MAX_PROBED_PORTS = 64;
29
+ const PROBE_CONCURRENCY = 8;
30
+ const MAX_LIST_PAGES = 5;
31
+ const HTTP_PATHS = [{ path: "/mcp", flavor: "streamable" }, { path: "/sse", flavor: "sse" }];
32
+ // ---------------------------------------------------------------- manual list
33
+ export function localMcpRegistryPath() {
34
+ return join(process.env.XDG_CONFIG_HOME || join(homedir(), ".config"), "frely", "mcp-v1", "local-mcps.json");
35
+ }
36
+ export async function loadManualEntries(path = localMcpRegistryPath()) {
37
+ const raw = await readPrivateFile(path);
38
+ if (!raw)
39
+ return [];
40
+ const value = JSON.parse(raw);
41
+ if (value.version !== 1 || !Array.isArray(value.servers))
42
+ throw new Error("Local MCP list is corrupted.");
43
+ return value.servers.map((item) => normalizeManual(item));
44
+ }
45
+ export async function addManualEntry(entry, path = localMcpRegistryPath()) {
46
+ const next = normalizeManual(entry);
47
+ const current = await loadManualEntries(path);
48
+ if (current.some((item) => item.name === next.name))
49
+ throw new Error(`A local MCP named ${next.name} already exists. Remove it first.`);
50
+ await writeManual([...current, next], path);
51
+ }
52
+ export async function removeManualEntry(name, path = localMcpRegistryPath()) {
53
+ const current = await loadManualEntries(path);
54
+ if (!current.some((item) => item.name === name))
55
+ throw new Error(`No manually added local MCP named ${name}.`);
56
+ await writeManual(current.filter((item) => item.name !== name), path);
57
+ }
58
+ async function writeManual(entries, path) {
59
+ await ensureCredentialDirectory(dirname(path), true);
60
+ const servers = entries.map((entry) => { const { source: _source, ...rest } = entry; return rest; });
61
+ await writePrivateFile(path, JSON.stringify({ version: 1, servers }) + "\n");
62
+ }
63
+ function normalizeManual(entry) {
64
+ if (!entry || typeof entry !== "object" || !LOCAL_MCP_NAME.test(entry.name))
65
+ throw new Error("Local MCP names use 1-32 lowercase letters, digits or hyphens and start with a letter or digit.");
66
+ if (entry.transport === "http") {
67
+ assertLoopbackUrl(entry.url);
68
+ return { ...entry, source: "manual" };
69
+ }
70
+ if (entry.transport === "stdio") {
71
+ if (typeof entry.command !== "string" || entry.command.length === 0 || !Array.isArray(entry.args) || !entry.args.every((arg) => typeof arg === "string"))
72
+ throw new Error("A stdio local MCP needs a command and string arguments.");
73
+ return { ...entry, source: "manual" };
74
+ }
75
+ throw new Error("Local MCP transport must be http or stdio.");
76
+ }
77
+ // ------------------------------------------------------------------ loopback
78
+ /** Only loopback HTTP(S) targets are ever contacted (plan F5). */
79
+ export function assertLoopbackUrl(value) {
80
+ let url;
81
+ try {
82
+ url = new URL(value);
83
+ }
84
+ catch {
85
+ throw new Error("Local MCP URL is not valid.");
86
+ }
87
+ const host = url.hostname.replace(/^\[|\]$/gu, "");
88
+ const loopback = host === "localhost" || host === "::1" || /^127(?:\.\d{1,3}){3}$/u.test(host);
89
+ if ((url.protocol !== "http:" && url.protocol !== "https:") || !loopback || url.username || url.password) {
90
+ throw new Error("Local MCP URLs must be http(s) on 127.0.0.1, ::1 or localhost without credentials.");
91
+ }
92
+ return url;
93
+ }
94
+ const loopbackFetch = async (input, init) => {
95
+ assertLoopbackUrl(String(input));
96
+ const response = await fetch(input, { ...init, redirect: "manual" });
97
+ if (response.status >= 300 && response.status < 400)
98
+ throw new Error("The local MCP server redirected; redirects are not followed.");
99
+ return response;
100
+ };
101
+ export function parseLoopbackListeners(platform, outputs) {
102
+ const ports = new Set();
103
+ const add = (value) => { const port = Number(value); if (Number.isInteger(port) && port > 0 && port < 65536)
104
+ ports.add(port); };
105
+ for (const output of outputs) {
106
+ for (const line of output.split(/\r?\n/u)) {
107
+ if (platform === "linux") {
108
+ const fields = line.trim().split(/\s+/u);
109
+ const [address, port] = (fields[1] ?? "").split(":");
110
+ if (fields[3] !== "0A" || !address || !port)
111
+ continue;
112
+ if (/^[0-9A-F]{6}7F$/u.test(address) || address === "00000000000000000000000001000000" || /^0000000000000000FFFF0000[0-9A-F]{6}7F$/u.test(address))
113
+ add(String(Number.parseInt(port, 16)));
114
+ }
115
+ else if (platform === "win32") {
116
+ const match = /^\s*TCP\s+(?:127(?:\.\d+){3}|\[::1\]):(\d+)\s+\S+\s+LISTENING/u.exec(line);
117
+ if (match)
118
+ add(match[1]);
119
+ }
120
+ else {
121
+ const match = /^n(?:127(?:\.\d+){3}|\[::1\]|localhost):(\d+)$/u.exec(line.trim());
122
+ if (match)
123
+ add(match[1]);
124
+ }
125
+ }
126
+ }
127
+ return [...ports].sort((a, b) => a - b);
128
+ }
129
+ /** TCP ports that only accept loopback connections, found without extra dependencies. */
130
+ export async function listLoopbackPorts(platform = process.platform) {
131
+ try {
132
+ if (platform === "linux") {
133
+ const files = await Promise.all(["/proc/net/tcp", "/proc/net/tcp6"].map((file) => readFile(file, "utf8").catch(() => "")));
134
+ return parseLoopbackListeners(platform, files);
135
+ }
136
+ const [command, args] = platform === "win32" ? ["netstat", ["-ano", "-p", "tcp"]] : ["lsof", ["-nP", "-iTCP", "-sTCP:LISTEN", "-Fn"]];
137
+ const output = await new Promise((resolve) => {
138
+ execFile(command, [...args], { timeout: 5_000, maxBuffer: 4 * 1024 * 1024, windowsHide: true }, (_error, stdout) => resolve(stdout ?? ""));
139
+ });
140
+ return parseLoopbackListeners(platform, [output]);
141
+ }
142
+ catch {
143
+ return [];
144
+ }
145
+ }
146
+ /** One standard `initialize` (or SSE handshake) per port; nothing is sent beyond that and redirects are never followed. */
147
+ export async function probeHttpMcp(port, timeoutMs = PROBE_TIMEOUT_MS) {
148
+ for (const { path, flavor } of HTTP_PATHS) {
149
+ const url = `http://127.0.0.1:${port}${path}`;
150
+ try {
151
+ const hit = flavor === "streamable" ? await probeStreamable(url, timeoutMs) : await probeSse(url, timeoutMs);
152
+ if (hit)
153
+ return hit;
154
+ }
155
+ catch { /* Not an MCP endpoint on this path. */ }
156
+ }
157
+ return null;
158
+ }
159
+ async function probeStreamable(url, timeoutMs) {
160
+ const response = await fetch(url, {
161
+ method: "POST",
162
+ redirect: "manual",
163
+ signal: AbortSignal.timeout(timeoutMs),
164
+ headers: { "content-type": "application/json", accept: "application/json, text/event-stream" },
165
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "initialize", params: { protocolVersion: "2025-06-18", capabilities: {}, clientInfo: { name: "frely-discovery", version: VERSION } } }),
166
+ });
167
+ const session = response.headers.get("mcp-session-id");
168
+ try {
169
+ if (!response.ok)
170
+ return null;
171
+ const type = response.headers.get("content-type") ?? "";
172
+ const text = (await response.text()).slice(0, 65_536);
173
+ const body = type.includes("text/event-stream") ? text.split(/\r?\n/u).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim())[0] : text;
174
+ const message = JSON.parse(body ?? "");
175
+ if (typeof message.result?.protocolVersion !== "string")
176
+ return null;
177
+ const serverName = typeof message.result.serverInfo?.name === "string" ? message.result.serverInfo.name : undefined;
178
+ return { url, flavor: "streamable", ...(serverName ? { serverName } : {}) };
179
+ }
180
+ finally {
181
+ if (session)
182
+ void fetch(url, { method: "DELETE", redirect: "manual", signal: AbortSignal.timeout(timeoutMs), headers: { "mcp-session-id": session } }).catch(() => undefined);
183
+ }
184
+ }
185
+ async function probeSse(url, timeoutMs) {
186
+ const controller = new AbortController();
187
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
188
+ try {
189
+ const response = await fetch(url, { redirect: "manual", signal: controller.signal, headers: { accept: "text/event-stream" } });
190
+ if (!response.ok || !(response.headers.get("content-type") ?? "").includes("text/event-stream") || !response.body)
191
+ return null;
192
+ const reader = response.body.getReader();
193
+ let seen = "";
194
+ while (seen.length < 4096 && !/^event:\s*endpoint\s*$/mu.test(seen)) {
195
+ const chunk = await reader.read();
196
+ if (chunk.done)
197
+ break;
198
+ seen += Buffer.from(chunk.value).toString("utf8");
199
+ }
200
+ void reader.cancel().catch(() => undefined);
201
+ return /^event:\s*endpoint\s*$/mu.test(seen) ? { url, flavor: "sse" } : null;
202
+ }
203
+ finally {
204
+ clearTimeout(timer);
205
+ controller.abort();
206
+ }
207
+ }
208
+ export async function discoverLoopbackMcps(deps = {}, skipPorts = new Set()) {
209
+ const ports = (await (deps.listPorts ?? listLoopbackPorts)()).filter((port) => !skipPorts.has(port)).slice(0, MAX_PROBED_PORTS);
210
+ const probe = deps.probe ?? probeHttpMcp;
211
+ const found = [];
212
+ let next = 0;
213
+ await Promise.all(Array.from({ length: Math.min(PROBE_CONCURRENCY, ports.length) }, async () => {
214
+ while (next < ports.length) {
215
+ const port = ports[next++];
216
+ const hit = await probe(port).catch(() => null);
217
+ if (hit)
218
+ found.push({ ...hit, port });
219
+ }
220
+ }));
221
+ return found.sort((a, b) => a.port - b.port);
222
+ }
223
+ export function slugName(value) {
224
+ const slug = (value ?? "").toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, 32).replace(/-+$/u, "");
225
+ return slug || "mcp";
226
+ }
227
+ /** Stable names: manual entries keep theirs, discovered ones use the server's own name and get a numeric suffix on clashes. */
228
+ export function nameDiscovered(hits, taken) {
229
+ const used = new Set(taken);
230
+ return hits.map((hit) => {
231
+ const base = slugName(hit.serverName ?? `local-${hit.port}`);
232
+ let name = base;
233
+ for (let n = 2; used.has(name); n++)
234
+ name = `${base.slice(0, 32 - String(n).length - 1)}-${n}`;
235
+ used.add(name);
236
+ return { name, source: "discovered", transport: "http", url: hit.url, flavor: hit.flavor };
237
+ });
238
+ }
239
+ export class LocalMcpHub {
240
+ options;
241
+ entries = [];
242
+ refreshedAt = 0;
243
+ refreshing;
244
+ timer;
245
+ pool = new Map();
246
+ connecting = new Map();
247
+ constructor(options = {}) {
248
+ this.options = options;
249
+ }
250
+ /** Begin periodic discovery and idle cleanup; both timers are unref'd. */
251
+ start() {
252
+ if (this.timer)
253
+ return;
254
+ void this.refresh().catch(() => undefined);
255
+ this.timer = setInterval(() => { void this.refresh().catch(() => undefined); void this.closeIdle(); }, this.options.refreshMs ?? 5 * 60_000);
256
+ this.timer.unref?.();
257
+ }
258
+ async close() {
259
+ if (this.timer)
260
+ clearInterval(this.timer);
261
+ this.timer = undefined;
262
+ await Promise.allSettled([...this.pool.values()].map((item) => item.client.close()));
263
+ this.pool.clear();
264
+ }
265
+ refresh() {
266
+ this.refreshing ??= this.scan().finally(() => { this.refreshing = undefined; });
267
+ return this.refreshing;
268
+ }
269
+ async scan() {
270
+ const manual = await (this.options.loadManual ?? (() => loadManualEntries()))().catch((error) => {
271
+ this.options.log?.(`local MCP list unreadable: ${error instanceof Error ? error.message : String(error)}`);
272
+ return [];
273
+ });
274
+ const covered = new Set(manual.flatMap((entry) => entry.transport === "http" ? [Number(new URL(entry.url).port)] : []));
275
+ const hits = await discoverLoopbackMcps(this.options.discovery, covered);
276
+ this.entries = [...manual, ...nameDiscovered(hits, manual.map((entry) => entry.name))];
277
+ this.refreshedAt = Date.now();
278
+ const live = new Map(this.entries.map((entry) => [entry.name, connectionKey(entry)]));
279
+ for (const [name, item] of [...this.pool])
280
+ if (live.get(name) !== item.key) {
281
+ this.pool.delete(name);
282
+ void item.client.close().catch(() => undefined);
283
+ }
284
+ }
285
+ async ensureFresh(maxAgeMs = 30_000) {
286
+ if (Date.now() - this.refreshedAt > maxAgeMs)
287
+ await this.refresh();
288
+ }
289
+ snapshot() { return this.entries; }
290
+ /** Names and transports for the web console; commands, URLs and secrets never leave the device. */
291
+ capabilities() {
292
+ return this.entries.slice(0, LOCAL_MCP_CAPABILITY_LIMIT).map((entry) => ({ name: entry.name, transport: entry.transport }));
293
+ }
294
+ /** `local_mcp_list`: enabled servers, or one enabled server's tool definitions. */
295
+ async list(enabled, server, signal) {
296
+ await this.ensureFresh();
297
+ if (server === undefined) {
298
+ const present = new Map(this.entries.map((entry) => [entry.name, entry]));
299
+ return { servers: enabled.map((name) => ({ name, transport: present.get(name)?.transport ?? null, available: present.has(name) })) };
300
+ }
301
+ const entry = this.requireEnabled(enabled, server);
302
+ const client = await this.client(entry);
303
+ const tools = [];
304
+ let cursor;
305
+ for (let page = 0; page < MAX_LIST_PAGES; page++) {
306
+ const result = await client.client.listTools(cursor ? { cursor } : {}, { timeout: LOCAL_MCP_DEFAULT_TIMEOUT_MS, ...(signal ? { signal } : {}) });
307
+ tools.push(...result.tools);
308
+ cursor = result.nextCursor;
309
+ if (!cursor)
310
+ break;
311
+ }
312
+ client.lastUsed = Date.now();
313
+ return { server, tools };
314
+ }
315
+ /** `local_mcp_call`: forwards one tools/call to an enabled server and bounds the result. */
316
+ async call(enabled, server, tool, args, options = {}) {
317
+ await this.ensureFresh();
318
+ const entry = this.requireEnabled(enabled, server);
319
+ const timeout = Math.min(Math.max(options.timeoutMs ?? LOCAL_MCP_DEFAULT_TIMEOUT_MS, 100), LOCAL_MCP_MAX_TIMEOUT_MS);
320
+ const pooled = await this.client(entry);
321
+ try {
322
+ const result = await pooled.client.callTool({ name: tool, arguments: args }, undefined, { timeout, ...(options.signal ? { signal: options.signal } : {}) });
323
+ pooled.lastUsed = Date.now();
324
+ return shapeToolResult(result);
325
+ }
326
+ catch (error) {
327
+ pooled.lastUsed = Date.now();
328
+ throw error;
329
+ }
330
+ }
331
+ requireEnabled(enabled, name) {
332
+ if (!enabled.includes(name)) {
333
+ throw new Error(`Local MCP ${JSON.stringify(name)} is not enabled on this device. Enabled: ${enabled.length > 0 ? enabled.join(", ") : "none"}. Enable it on the Frely connections page.`);
334
+ }
335
+ const entry = this.entries.find((item) => item.name === name);
336
+ if (!entry)
337
+ throw new Error(`Local MCP ${JSON.stringify(name)} is enabled but not running on this device right now.`);
338
+ return entry;
339
+ }
340
+ async client(entry) {
341
+ const key = connectionKey(entry);
342
+ const existing = this.pool.get(entry.name);
343
+ if (existing?.key === key)
344
+ return existing;
345
+ const pending = this.connecting.get(entry.name);
346
+ if (pending)
347
+ return pending;
348
+ const created = this.connect(entry, key).finally(() => this.connecting.delete(entry.name));
349
+ this.connecting.set(entry.name, created);
350
+ return created;
351
+ }
352
+ async connect(entry, key) {
353
+ const stale = this.pool.get(entry.name);
354
+ if (stale) {
355
+ this.pool.delete(entry.name);
356
+ void stale.client.close().catch(() => undefined);
357
+ }
358
+ const attempts = entry.transport === "stdio"
359
+ ? [() => stdioTransport(entry)]
360
+ : entry.flavor === "sse" ? [() => sseTransport(entry)] : entry.flavor === "streamable" ? [() => httpTransport(entry)] : [() => httpTransport(entry), () => sseTransport(entry)];
361
+ let lastError;
362
+ for (const make of attempts) {
363
+ const client = new Client({ name: "frely-cli", version: VERSION }, { capabilities: {} });
364
+ try {
365
+ await client.connect(make(), { timeout: CONNECT_TIMEOUT_MS });
366
+ const pooled = { key, client, lastUsed: Date.now() };
367
+ client.onclose = () => { if (this.pool.get(entry.name) === pooled)
368
+ this.pool.delete(entry.name); };
369
+ this.pool.set(entry.name, pooled);
370
+ return pooled;
371
+ }
372
+ catch (error) {
373
+ lastError = error;
374
+ await client.close().catch(() => undefined);
375
+ }
376
+ }
377
+ throw new Error(`Could not connect to local MCP ${JSON.stringify(entry.name)}: ${lastError instanceof Error ? lastError.message : String(lastError)}`);
378
+ }
379
+ async closeIdle() {
380
+ const limit = Date.now() - (this.options.idleMs ?? 10 * 60_000);
381
+ for (const [name, item] of [...this.pool]) {
382
+ if (item.lastUsed < limit) {
383
+ this.pool.delete(name);
384
+ await item.client.close().catch(() => undefined);
385
+ }
386
+ }
387
+ }
388
+ }
389
+ function connectionKey(entry) {
390
+ return entry.transport === "http" ? JSON.stringify([entry.url, entry.flavor ?? null, entry.headers ?? null]) : JSON.stringify([entry.command, entry.args, entry.env ?? null, entry.path ?? null]);
391
+ }
392
+ function httpTransport(entry) {
393
+ const url = assertLoopbackUrl(entry.url);
394
+ return new StreamableHTTPClientTransport(url, { fetch: loopbackFetch, ...(entry.headers ? { requestInit: { headers: entry.headers } } : {}) });
395
+ }
396
+ function sseTransport(entry) {
397
+ const url = assertLoopbackUrl(entry.url);
398
+ return new SSEClientTransport(url, { fetch: loopbackFetch, eventSourceInit: { fetch: loopbackFetch }, ...(entry.headers ? { requestInit: { headers: entry.headers } } : {}) });
399
+ }
400
+ function stdioTransport(entry) {
401
+ const env = { ...safeEnv(), ...entry.env };
402
+ if (entry.path)
403
+ env.PATH = entry.path;
404
+ const transport = new StdioClientTransport({ command: entry.command, args: entry.args, env, cwd: homedir(), stderr: "pipe" });
405
+ // An undrained stderr pipe can stall the child; its output is not forwarded.
406
+ transport.stderr?.on("data", () => undefined);
407
+ return transport;
408
+ }
409
+ /** Resolve a bare command against PATH so a background service with a different PATH still finds it. */
410
+ export async function resolveCommand(command, pathValue = process.env.PATH ?? "") {
411
+ if (isAbsolute(command))
412
+ return command;
413
+ const extensions = process.platform === "win32" ? ["", ...(process.env.PATHEXT ?? ".EXE;.CMD;.BAT").split(";")] : [""];
414
+ for (const directory of pathValue.split(delimiter).filter(Boolean)) {
415
+ for (const extension of extensions) {
416
+ const candidate = join(directory, command + extension);
417
+ if (await access(candidate, process.platform === "win32" ? constants.F_OK : constants.X_OK).then(() => true, () => false))
418
+ return candidate;
419
+ }
420
+ }
421
+ throw new Error(`Command not found on PATH: ${command}`);
422
+ }
423
+ /** Bounds what one local MCP call can put on the relay: 1 MiB of text, 6 MiB of binary content. */
424
+ export function shapeToolResult(result) {
425
+ const content = [];
426
+ let text = 0;
427
+ let binary = 0;
428
+ for (const block of Array.isArray(result.content) ? result.content : []) {
429
+ const item = block;
430
+ if (item.type === "text" && typeof item.text === "string") {
431
+ const room = LOCAL_MCP_TEXT_LIMIT - text;
432
+ if (room <= 0)
433
+ continue;
434
+ const clipped = Buffer.byteLength(item.text) > room ? Buffer.from(item.text).subarray(0, room).toString("utf8") + "\n[truncated]" : item.text;
435
+ text += Buffer.byteLength(item.text);
436
+ content.push({ ...item, text: clipped });
437
+ }
438
+ else if (typeof item.data === "string") {
439
+ binary += item.data.length;
440
+ content.push(binary > LOCAL_MCP_BINARY_LIMIT ? { type: "text", text: `[${String(item.type)} content omitted: larger than ${LOCAL_MCP_BINARY_LIMIT / (1024 * 1024)} MiB relay budget]` } : item);
441
+ }
442
+ else {
443
+ content.push(item);
444
+ }
445
+ }
446
+ return { content, ...(result.isError === true ? { isError: true } : {}) };
447
+ }
448
+ //# sourceMappingURL=local-mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-mcp.js","sourceRoot":"","sources":["../../src/runtime/local-mcp.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import type { MaintenanceGate } from "../upgrade/maintenance.js";
2
2
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import type { LocalMcpHub } from "./local-mcp.js";
3
4
  export interface McpRuntimeOptions {
4
5
  maintenance?: MaintenanceGate;
5
6
  assertAuthorized?: () => void | Promise<void>;
@@ -10,6 +11,10 @@ export interface McpRuntimeOptions {
10
11
  getToolsets?: () => string[];
11
12
  /** Bridge for agent_* tools (frely-app toolset). Without it agent tools stay hidden. */
12
13
  callAgent?: (op: string, args: Record<string, unknown>) => Promise<unknown>;
14
+ /** Device-local MCP servers (plan mcp/本机MCP转发-方案.md). Without a hub the local_mcp_* tools stay hidden. */
15
+ localMcp?: LocalMcpHub;
16
+ /** Names the owner enabled on the current MCP authorization; absent or empty hides the local_mcp_* tools. */
17
+ getLocalMcps?: () => string[];
13
18
  }
14
19
  /** agent_* MCP tools exposed when the frely-app toolset is enabled (plan §5). */
15
20
  export declare const AGENT_TOOLS: readonly [{
@@ -146,5 +151,20 @@ export declare const AGENT_TOOLS: readonly [{
146
151
  };
147
152
  readonly required: readonly ["taskId"];
148
153
  }];
154
+ /** Gateway tools for device-local MCP servers (plan F1): one pair, whatever number of servers or transports sit behind them. */
155
+ export declare const LOCAL_MCP_TOOLS: {
156
+ name: string;
157
+ description: string;
158
+ inputSchema: {
159
+ type: string;
160
+ additionalProperties: boolean;
161
+ properties: Record<string, unknown>;
162
+ };
163
+ annotations: {
164
+ readOnlyHint: boolean;
165
+ destructiveHint: boolean;
166
+ idempotentHint: boolean;
167
+ };
168
+ }[];
149
169
  export declare function createMcpServer(workspaceInput: string, options?: McpRuntimeOptions): Promise<Server>;
150
170
  export declare function startStdioMcp(workspaceInput: string, options?: McpRuntimeOptions): Promise<void>;