@creatornader/agent-bridge 0.7.3 → 0.7.4

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/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to agent-bridge are documented in this file.
4
4
 
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.7.4] - 2026-07-30
8
+
9
+ ### Fixed
10
+
11
+ - Resolve npm-managed executable symlinks before checking whether the loopback host
12
+ or stdio proxy is the invoked module. Packed-install smoke coverage now invokes
13
+ both public executables.
14
+
7
15
  ## [0.7.3] - 2026-07-30
8
16
 
9
17
  ### Added
@@ -19,7 +19,7 @@ import "./chunk-BZLMF5O5.js";
19
19
 
20
20
  // src/loopback-host.ts
21
21
  import { randomUUID } from "crypto";
22
- import { chmodSync, existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
22
+ import { chmodSync, existsSync, mkdirSync, realpathSync, rmSync, writeFileSync } from "fs";
23
23
  import { createServer } from "http";
24
24
  import { connect } from "net";
25
25
  import { homedir } from "os";
@@ -349,7 +349,15 @@ async function uninstallLaunchdHost(serviceName, port, host = DEFAULT_HOST, home
349
349
  await waitForPortClosed(host, port);
350
350
  return { label, plistPath };
351
351
  }
352
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
352
+ function isMainModule() {
353
+ if (!process.argv[1]) return false;
354
+ try {
355
+ return import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href;
356
+ } catch {
357
+ return false;
358
+ }
359
+ }
360
+ if (isMainModule()) {
353
361
  const args = process.argv.slice(2);
354
362
  if (args.includes("--help") || args.includes("-h")) process.stdout.write(usage());
355
363
  else if (args.includes("--install-launchd")) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/loopback-host.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { chmodSync, existsSync, mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { createServer, type IncomingMessage, type Server as HttpServer, type ServerResponse } from \"node:http\";\nimport { connect, type AddressInfo } from \"node:net\";\nimport { homedir } from \"node:os\";\nimport { dirname, isAbsolute, join } from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { isInitializeRequest } from \"@modelcontextprotocol/sdk/types.js\";\nimport { configFromEnv, createAgentBridgeServer } from \"./server.js\";\nimport { verifyPrivatePathAccess } from \"./private-path.js\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 8794;\nconst DEFAULT_PATH = \"/mcp\";\nconst DEFAULT_SESSION_IDLE_MS = 12 * 60 * 60 * 1000;\nconst MAX_BODY_BYTES = 1024 * 1024;\n\nexport interface LoopbackHostOptions {\n host?: string;\n port?: number;\n path?: string;\n sessionIdleMs?: number;\n}\n\nexport interface LoopbackHost {\n endpoint: string;\n healthEndpoint: string;\n close(): Promise<void>;\n}\n\nexport interface LaunchdInstallOptions extends Required<LoopbackHostOptions> {\n serviceName: string;\n configPath: string;\n agent: string;\n instance: string;\n home?: string;\n executablePath?: string;\n}\n\ninterface Session {\n bridge: ReturnType<typeof createAgentBridgeServer>;\n transport: StreamableHTTPServerTransport;\n id?: string;\n lastSeenAt: number;\n closing: boolean;\n}\n\nfunction normalizePath(raw: string): string {\n const path = raw.startsWith(\"/\") ? raw : `/${raw}`;\n return path.length > 1 ? path.replace(/\\/+$/, \"\") : path;\n}\n\nfunction isLoopback(host: string): boolean {\n return host === \"127.0.0.1\" || host === \"::1\" || host === \"localhost\";\n}\n\nfunction endpoint(host: string, port: number, path: string): string {\n return `http://${host.includes(\":\") ? `[${host}]` : host}:${port}${path}`;\n}\n\nfunction requestPath(req: IncomingMessage): string {\n try {\n return new URL(req.url ?? \"/\", \"http://localhost\").pathname;\n } catch {\n return \"/\";\n }\n}\n\nfunction sessionId(req: IncomingMessage): string | undefined {\n const value = req.headers[\"mcp-session-id\"];\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction reply(res: ServerResponse, status: number, body: unknown): void {\n const bytes = Buffer.from(JSON.stringify(body));\n res.writeHead(status, {\n \"content-type\": \"application/json; charset=utf-8\",\n \"content-length\": bytes.length,\n });\n res.end(bytes);\n}\n\nfunction jsonRpcError(res: ServerResponse, status: number, code: number, message: string): void {\n reply(res, status, { jsonrpc: \"2.0\", error: { code, message }, id: null });\n}\n\nasync function readBody(req: IncomingMessage): Promise<unknown> {\n const chunks: Buffer[] = [];\n let length = 0;\n for await (const chunk of req) {\n const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n length += bytes.length;\n if (length > MAX_BODY_BYTES) throw new Error(`request body exceeds ${MAX_BODY_BYTES} bytes`);\n chunks.push(bytes);\n }\n const value = Buffer.concat(chunks).toString(\"utf8\").trim();\n return value ? JSON.parse(value) : undefined;\n}\n\nfunction listen(server: HttpServer, host: string, port: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const onError = (error: Error) => {\n server.off(\"listening\", onListening);\n reject(error);\n };\n const onListening = () => {\n server.off(\"error\", onError);\n resolve();\n };\n server.once(\"error\", onError);\n server.once(\"listening\", onListening);\n server.listen(port, host);\n });\n}\n\nfunction closeServer(server: HttpServer): Promise<void> {\n return new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));\n}\n\nfunction boundPort(server: HttpServer): number {\n const address = server.address();\n if (!address || typeof address === \"string\") throw new Error(\"loopback host did not bind a TCP port\");\n return (address as AddressInfo).port;\n}\n\nexport async function startLoopbackHost(options: LoopbackHostOptions = {}): Promise<LoopbackHost> {\n const host = options.host ?? DEFAULT_HOST;\n const port = options.port ?? DEFAULT_PORT;\n const mcpPath = normalizePath(options.path ?? DEFAULT_PATH);\n const healthPath = `${mcpPath}/health`;\n const sessionIdleMs = options.sessionIdleMs ?? DEFAULT_SESSION_IDLE_MS;\n if (!isLoopback(host)) throw new Error(\"--host must be 127.0.0.1, ::1, or localhost\");\n if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error(\"--port must be an integer from 0 to 65535\");\n if (!Number.isInteger(sessionIdleMs) || sessionIdleMs <= 0) throw new Error(\"--session-idle-ms must be a positive integer\");\n\n const sessions = new Map<string, Session>();\n let openedSessions = 0;\n let closedSessions = 0;\n let closing = false;\n const closeSession = async (session: Session): Promise<void> => {\n if (session.closing) return;\n session.closing = true;\n if (session.id) sessions.delete(session.id);\n closedSessions += 1;\n await Promise.allSettled([session.transport.close(), session.bridge.close()]);\n };\n const sweep = (): void => {\n const cutoff = Date.now() - sessionIdleMs;\n for (const session of sessions.values()) {\n if (session.lastSeenAt < cutoff) void closeSession(session);\n }\n };\n const sweepTimer = setInterval(sweep, Math.min(sessionIdleMs, 60_000));\n sweepTimer.unref();\n\n const server = createServer(async (req, res) => {\n const path = requestPath(req);\n if (path === healthPath || path === \"/health\") {\n reply(res, 200, {\n status: \"healthy\",\n report: {\n bridgeRuntime: \"agent-bridge\",\n transport: \"streamable-http\",\n sessions: { active: sessions.size, opened: openedSessions, closed: closedSessions, idleTimeoutMs: sessionIdleMs },\n },\n });\n return;\n }\n if (path !== mcpPath) return jsonRpcError(res, 404, -32000, \"Not Found\");\n if (![\"POST\", \"GET\", \"DELETE\"].includes(req.method ?? \"\")) {\n return jsonRpcError(res, 405, -32000, \"Method Not Allowed\");\n }\n sweep();\n try {\n const body = req.method === \"POST\" ? await readBody(req) : undefined;\n const existingId = sessionId(req);\n if (existingId) {\n const session = sessions.get(existingId);\n if (!session) return jsonRpcError(res, 404, -32000, \"Session not found\");\n session.lastSeenAt = Date.now();\n await session.transport.handleRequest(req, res, body);\n return;\n }\n if (req.method !== \"POST\" || !isInitializeRequest(body)) {\n return jsonRpcError(res, 400, -32000, \"initialize first or provide mcp-session-id\");\n }\n let session: Session | undefined;\n try {\n const bridge = createAgentBridgeServer(configFromEnv());\n session = {\n bridge,\n transport: new StreamableHTTPServerTransport({\n sessionIdGenerator: randomUUID,\n onsessioninitialized: (id) => {\n if (!session) return;\n session.id = id;\n session.lastSeenAt = Date.now();\n sessions.set(id, session);\n },\n }),\n lastSeenAt: Date.now(),\n closing: false,\n };\n session.transport.onclose = () => { if (session) void closeSession(session); };\n await bridge.connect(session.transport);\n openedSessions += 1;\n await session.transport.handleRequest(req, res, body);\n } finally {\n if (session && !session.id && !session.closing) await closeSession(session);\n }\n } catch (error) {\n if (!res.headersSent) {\n const message = error instanceof Error ? error.message : String(error);\n jsonRpcError(res, 500, -32603, `Internal server error: ${message}`);\n }\n }\n });\n await listen(server, host, port);\n const actualPort = boundPort(server);\n const mcpEndpoint = endpoint(host, actualPort, mcpPath);\n const healthEndpoint = endpoint(host, actualPort, healthPath);\n process.stdout.write(`${JSON.stringify({ status: \"ready\", endpoint: mcpEndpoint, healthEndpoint })}\\n`);\n\n return {\n endpoint: mcpEndpoint,\n healthEndpoint,\n close: async () => {\n if (closing) return;\n closing = true;\n clearInterval(sweepTimer);\n await Promise.allSettled([...sessions.values()].map(closeSession));\n await closeServer(server);\n },\n };\n}\n\nfunction option(args: string[], name: string, fallback: string): string {\n const index = args.indexOf(name);\n if (index < 0) return fallback;\n return args[index + 1] ?? (() => { throw new Error(`${name} requires a value`); })();\n}\n\nfunction usage(): string {\n return `Usage:\n agent-bridge-loopback-host [--host 127.0.0.1] [--port 8794] [--path /mcp] [--session-idle-ms 43200000]\n agent-bridge-loopback-host --install-launchd --service-name <name> --config <private-backend> --agent <identity> --instance <stable-key> [host options]\n agent-bridge-loopback-host --uninstall-launchd --service-name <name> --port <port>\n`;\n}\n\nfunction required(args: string[], name: string): string {\n const value = option(args, name, \"\");\n if (!value) throw new Error(`${name} requires a value`);\n return value;\n}\n\nfunction serviceLabel(name: string): string {\n if (!/^[A-Za-z0-9_-]+$/.test(name)) throw new Error(\"--service-name must contain only letters, numbers, _ or -\");\n return `com.creatornader.agent-bridge.${name}`;\n}\n\nfunction launchctl(args: string[]): void {\n const result = spawnSync(\"launchctl\", args, { encoding: \"utf8\" });\n if (result.status !== 0 && result.status !== 3 && result.status !== 113) {\n throw new Error(`launchctl ${args[0]} failed: ${(result.stderr || result.stdout || \"unknown error\").trim()}`);\n }\n}\n\nfunction currentUserId(): number {\n if (!process.getuid) throw new Error(\"launchd requires a POSIX user identity\");\n return process.getuid();\n}\n\nexport function launchdPlist(options: LaunchdInstallOptions): string {\n const executable = options.executablePath ?? fileURLToPath(import.meta.url);\n const label = serviceLabel(options.serviceName);\n const environment = {\n AGENT_BRIDGE_CONFIG: options.configPath,\n AGENT_BRIDGE_AGENT: options.agent,\n AGENT_BRIDGE_INSTANCE: options.instance,\n };\n const encode = (value: string): string => value.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n const strings = (values: string[]): string => values.map((value) => ` <string>${encode(value)}</string>`).join(\"\\n\");\n const env = Object.entries(environment).map(([key, value]) => ` <key>${key}</key>\\n <string>${encode(value)}</string>`).join(\"\\n\");\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${label}</string>\n <key>ProgramArguments</key>\n <array>\n${strings([process.execPath, executable, \"--host\", options.host, \"--port\", String(options.port), \"--path\", options.path, \"--session-idle-ms\", String(options.sessionIdleMs)])}\n </array>\n <key>EnvironmentVariables</key>\n <dict>\n${env}\n </dict>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <true/>\n <key>StandardOutPath</key>\n <string>${encode(join(options.home ?? homedir(), \".agent-bridge\", \"logs\", `${options.serviceName}.out.log`))}</string>\n <key>StandardErrorPath</key>\n <string>${encode(join(options.home ?? homedir(), \".agent-bridge\", \"logs\", `${options.serviceName}.err.log`))}</string>\n</dict>\n</plist>\n`;\n}\n\nasync function waitForHealth(healthEndpoint: string): Promise<void> {\n let lastError = \"no response\";\n for (let attempt = 0; attempt < 30; attempt += 1) {\n try {\n const response = await fetch(healthEndpoint, { signal: AbortSignal.timeout(1_000) });\n const body = await response.json() as { status?: unknown };\n if (response.ok && body.status === \"healthy\") return;\n lastError = `HTTP ${response.status}`;\n } catch (error) {\n lastError = error instanceof Error ? error.message : String(error);\n }\n await new Promise((resolve) => setTimeout(resolve, 200));\n }\n throw new Error(`launchd started but ${healthEndpoint} did not become healthy: ${lastError}`);\n}\n\nexport async function installLaunchdHost(options: LaunchdInstallOptions): Promise<{ label: string; plistPath: string; healthEndpoint: string }> {\n if (process.platform !== \"darwin\") throw new Error(\"--install-launchd is supported only on macOS\");\n if (!isLoopback(options.host)) throw new Error(\"--host must be 127.0.0.1, ::1, or localhost\");\n if (!Number.isInteger(options.port) || options.port < 1 || options.port > 65535) throw new Error(\"--port must be an integer from 1 to 65535 for launchd\");\n if (!isAbsolute(options.configPath) || !existsSync(options.configPath)) throw new Error(`--config must be an existing absolute path: ${options.configPath}`);\n verifyPrivatePathAccess(options.configPath, \"file\");\n const home = options.home ?? homedir();\n const label = serviceLabel(options.serviceName);\n const agents = join(home, \"Library\", \"LaunchAgents\");\n const logs = join(home, \".agent-bridge\", \"logs\");\n const plistPath = join(agents, `${label}.plist`);\n mkdirSync(agents, { recursive: true, mode: 0o700 });\n mkdirSync(logs, { recursive: true, mode: 0o700 });\n chmodSync(agents, 0o700);\n chmodSync(logs, 0o700);\n launchctl([\"bootout\", `gui/${currentUserId()}/${label}`]);\n writeFileSync(plistPath, launchdPlist({ ...options, home }), { mode: 0o600 });\n chmodSync(plistPath, 0o600);\n launchctl([\"bootstrap\", `gui/${currentUserId()}`, plistPath]);\n const healthEndpoint = endpoint(options.host, options.port, `${normalizePath(options.path)}/health`);\n await waitForHealth(healthEndpoint);\n return { label, plistPath, healthEndpoint };\n}\n\nasync function portIsOpen(host: string, port: number): Promise<boolean> {\n return await new Promise((resolve) => {\n const socket = connect({ host, port });\n const finish = (open: boolean) => { socket.destroy(); resolve(open); };\n socket.once(\"connect\", () => finish(true));\n socket.once(\"error\", () => finish(false));\n socket.setTimeout(1_000, () => finish(false));\n });\n}\n\nasync function waitForPortClosed(host: string, port: number): Promise<void> {\n for (let attempt = 0; attempt < 30; attempt += 1) {\n if (!await portIsOpen(host, port)) return;\n await new Promise((resolve) => setTimeout(resolve, 200));\n }\n throw new Error(`launchd unloaded but ${host}:${port} is still accepting connections`);\n}\n\nexport async function uninstallLaunchdHost(\n serviceName: string,\n port: number,\n host = DEFAULT_HOST,\n home = homedir(),\n): Promise<{ label: string; plistPath: string }> {\n if (process.platform !== \"darwin\") throw new Error(\"--uninstall-launchd is supported only on macOS\");\n if (!isLoopback(host)) throw new Error(\"--host must be 127.0.0.1, ::1, or localhost\");\n if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error(\"--port must be an integer from 1 to 65535 for launchd\");\n const label = serviceLabel(serviceName);\n const plistPath = join(home, \"Library\", \"LaunchAgents\", `${label}.plist`);\n launchctl([\"bootout\", `gui/${currentUserId()}/${label}`]);\n rmSync(plistPath, { force: true });\n await waitForPortClosed(host, port);\n return { label, plistPath };\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n const args = process.argv.slice(2);\n if (args.includes(\"--help\") || args.includes(\"-h\")) process.stdout.write(usage());\n else if (args.includes(\"--install-launchd\")) {\n void (async () => {\n try {\n const result = await installLaunchdHost({\n serviceName: required(args, \"--service-name\"),\n configPath: required(args, \"--config\"),\n agent: required(args, \"--agent\"),\n instance: required(args, \"--instance\"),\n host: option(args, \"--host\", DEFAULT_HOST),\n port: Number(option(args, \"--port\", String(DEFAULT_PORT))),\n path: option(args, \"--path\", DEFAULT_PATH),\n sessionIdleMs: Number(option(args, \"--session-idle-ms\", String(DEFAULT_SESSION_IDLE_MS))),\n });\n process.stdout.write(`${JSON.stringify({ status: \"installed\", ...result })}\\n`);\n } catch (error) {\n process.stderr.write(`agent-bridge-loopback-host: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n }\n })();\n } else if (args.includes(\"--uninstall-launchd\")) {\n void (async () => {\n try {\n const result = await uninstallLaunchdHost(\n required(args, \"--service-name\"),\n Number(required(args, \"--port\")),\n option(args, \"--host\", DEFAULT_HOST),\n );\n process.stdout.write(`${JSON.stringify({ status: \"uninstalled\", ...result })}\\n`);\n } catch (error) {\n process.stderr.write(`agent-bridge-loopback-host: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n }\n })();\n }\n else void startLoopbackHost({\n host: option(args, \"--host\", DEFAULT_HOST),\n port: Number(option(args, \"--port\", String(DEFAULT_PORT))),\n path: option(args, \"--path\", DEFAULT_PATH),\n sessionIdleMs: Number(option(args, \"--session-idle-ms\", String(DEFAULT_SESSION_IDLE_MS))),\n }).then((host) => {\n const shutdown = () => void host.close().finally(() => process.exit(0));\n process.once(\"SIGINT\", shutdown);\n process.once(\"SIGTERM\", shutdown);\n }).catch((error) => {\n process.stderr.write(`agent-bridge-loopback-host: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n });\n}\n"],"mappings":"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","names":["session"]}
1
+ {"version":3,"sources":["../src/loopback-host.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { chmodSync, existsSync, mkdirSync, realpathSync, rmSync, writeFileSync } from \"node:fs\";\nimport { createServer, type IncomingMessage, type Server as HttpServer, type ServerResponse } from \"node:http\";\nimport { connect, type AddressInfo } from \"node:net\";\nimport { homedir } from \"node:os\";\nimport { dirname, isAbsolute, join } from \"node:path\";\nimport { spawnSync } from \"node:child_process\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { isInitializeRequest } from \"@modelcontextprotocol/sdk/types.js\";\nimport { configFromEnv, createAgentBridgeServer } from \"./server.js\";\nimport { verifyPrivatePathAccess } from \"./private-path.js\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 8794;\nconst DEFAULT_PATH = \"/mcp\";\nconst DEFAULT_SESSION_IDLE_MS = 12 * 60 * 60 * 1000;\nconst MAX_BODY_BYTES = 1024 * 1024;\n\nexport interface LoopbackHostOptions {\n host?: string;\n port?: number;\n path?: string;\n sessionIdleMs?: number;\n}\n\nexport interface LoopbackHost {\n endpoint: string;\n healthEndpoint: string;\n close(): Promise<void>;\n}\n\nexport interface LaunchdInstallOptions extends Required<LoopbackHostOptions> {\n serviceName: string;\n configPath: string;\n agent: string;\n instance: string;\n home?: string;\n executablePath?: string;\n}\n\ninterface Session {\n bridge: ReturnType<typeof createAgentBridgeServer>;\n transport: StreamableHTTPServerTransport;\n id?: string;\n lastSeenAt: number;\n closing: boolean;\n}\n\nfunction normalizePath(raw: string): string {\n const path = raw.startsWith(\"/\") ? raw : `/${raw}`;\n return path.length > 1 ? path.replace(/\\/+$/, \"\") : path;\n}\n\nfunction isLoopback(host: string): boolean {\n return host === \"127.0.0.1\" || host === \"::1\" || host === \"localhost\";\n}\n\nfunction endpoint(host: string, port: number, path: string): string {\n return `http://${host.includes(\":\") ? `[${host}]` : host}:${port}${path}`;\n}\n\nfunction requestPath(req: IncomingMessage): string {\n try {\n return new URL(req.url ?? \"/\", \"http://localhost\").pathname;\n } catch {\n return \"/\";\n }\n}\n\nfunction sessionId(req: IncomingMessage): string | undefined {\n const value = req.headers[\"mcp-session-id\"];\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction reply(res: ServerResponse, status: number, body: unknown): void {\n const bytes = Buffer.from(JSON.stringify(body));\n res.writeHead(status, {\n \"content-type\": \"application/json; charset=utf-8\",\n \"content-length\": bytes.length,\n });\n res.end(bytes);\n}\n\nfunction jsonRpcError(res: ServerResponse, status: number, code: number, message: string): void {\n reply(res, status, { jsonrpc: \"2.0\", error: { code, message }, id: null });\n}\n\nasync function readBody(req: IncomingMessage): Promise<unknown> {\n const chunks: Buffer[] = [];\n let length = 0;\n for await (const chunk of req) {\n const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n length += bytes.length;\n if (length > MAX_BODY_BYTES) throw new Error(`request body exceeds ${MAX_BODY_BYTES} bytes`);\n chunks.push(bytes);\n }\n const value = Buffer.concat(chunks).toString(\"utf8\").trim();\n return value ? JSON.parse(value) : undefined;\n}\n\nfunction listen(server: HttpServer, host: string, port: number): Promise<void> {\n return new Promise((resolve, reject) => {\n const onError = (error: Error) => {\n server.off(\"listening\", onListening);\n reject(error);\n };\n const onListening = () => {\n server.off(\"error\", onError);\n resolve();\n };\n server.once(\"error\", onError);\n server.once(\"listening\", onListening);\n server.listen(port, host);\n });\n}\n\nfunction closeServer(server: HttpServer): Promise<void> {\n return new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));\n}\n\nfunction boundPort(server: HttpServer): number {\n const address = server.address();\n if (!address || typeof address === \"string\") throw new Error(\"loopback host did not bind a TCP port\");\n return (address as AddressInfo).port;\n}\n\nexport async function startLoopbackHost(options: LoopbackHostOptions = {}): Promise<LoopbackHost> {\n const host = options.host ?? DEFAULT_HOST;\n const port = options.port ?? DEFAULT_PORT;\n const mcpPath = normalizePath(options.path ?? DEFAULT_PATH);\n const healthPath = `${mcpPath}/health`;\n const sessionIdleMs = options.sessionIdleMs ?? DEFAULT_SESSION_IDLE_MS;\n if (!isLoopback(host)) throw new Error(\"--host must be 127.0.0.1, ::1, or localhost\");\n if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error(\"--port must be an integer from 0 to 65535\");\n if (!Number.isInteger(sessionIdleMs) || sessionIdleMs <= 0) throw new Error(\"--session-idle-ms must be a positive integer\");\n\n const sessions = new Map<string, Session>();\n let openedSessions = 0;\n let closedSessions = 0;\n let closing = false;\n const closeSession = async (session: Session): Promise<void> => {\n if (session.closing) return;\n session.closing = true;\n if (session.id) sessions.delete(session.id);\n closedSessions += 1;\n await Promise.allSettled([session.transport.close(), session.bridge.close()]);\n };\n const sweep = (): void => {\n const cutoff = Date.now() - sessionIdleMs;\n for (const session of sessions.values()) {\n if (session.lastSeenAt < cutoff) void closeSession(session);\n }\n };\n const sweepTimer = setInterval(sweep, Math.min(sessionIdleMs, 60_000));\n sweepTimer.unref();\n\n const server = createServer(async (req, res) => {\n const path = requestPath(req);\n if (path === healthPath || path === \"/health\") {\n reply(res, 200, {\n status: \"healthy\",\n report: {\n bridgeRuntime: \"agent-bridge\",\n transport: \"streamable-http\",\n sessions: { active: sessions.size, opened: openedSessions, closed: closedSessions, idleTimeoutMs: sessionIdleMs },\n },\n });\n return;\n }\n if (path !== mcpPath) return jsonRpcError(res, 404, -32000, \"Not Found\");\n if (![\"POST\", \"GET\", \"DELETE\"].includes(req.method ?? \"\")) {\n return jsonRpcError(res, 405, -32000, \"Method Not Allowed\");\n }\n sweep();\n try {\n const body = req.method === \"POST\" ? await readBody(req) : undefined;\n const existingId = sessionId(req);\n if (existingId) {\n const session = sessions.get(existingId);\n if (!session) return jsonRpcError(res, 404, -32000, \"Session not found\");\n session.lastSeenAt = Date.now();\n await session.transport.handleRequest(req, res, body);\n return;\n }\n if (req.method !== \"POST\" || !isInitializeRequest(body)) {\n return jsonRpcError(res, 400, -32000, \"initialize first or provide mcp-session-id\");\n }\n let session: Session | undefined;\n try {\n const bridge = createAgentBridgeServer(configFromEnv());\n session = {\n bridge,\n transport: new StreamableHTTPServerTransport({\n sessionIdGenerator: randomUUID,\n onsessioninitialized: (id) => {\n if (!session) return;\n session.id = id;\n session.lastSeenAt = Date.now();\n sessions.set(id, session);\n },\n }),\n lastSeenAt: Date.now(),\n closing: false,\n };\n session.transport.onclose = () => { if (session) void closeSession(session); };\n await bridge.connect(session.transport);\n openedSessions += 1;\n await session.transport.handleRequest(req, res, body);\n } finally {\n if (session && !session.id && !session.closing) await closeSession(session);\n }\n } catch (error) {\n if (!res.headersSent) {\n const message = error instanceof Error ? error.message : String(error);\n jsonRpcError(res, 500, -32603, `Internal server error: ${message}`);\n }\n }\n });\n await listen(server, host, port);\n const actualPort = boundPort(server);\n const mcpEndpoint = endpoint(host, actualPort, mcpPath);\n const healthEndpoint = endpoint(host, actualPort, healthPath);\n process.stdout.write(`${JSON.stringify({ status: \"ready\", endpoint: mcpEndpoint, healthEndpoint })}\\n`);\n\n return {\n endpoint: mcpEndpoint,\n healthEndpoint,\n close: async () => {\n if (closing) return;\n closing = true;\n clearInterval(sweepTimer);\n await Promise.allSettled([...sessions.values()].map(closeSession));\n await closeServer(server);\n },\n };\n}\n\nfunction option(args: string[], name: string, fallback: string): string {\n const index = args.indexOf(name);\n if (index < 0) return fallback;\n return args[index + 1] ?? (() => { throw new Error(`${name} requires a value`); })();\n}\n\nfunction usage(): string {\n return `Usage:\n agent-bridge-loopback-host [--host 127.0.0.1] [--port 8794] [--path /mcp] [--session-idle-ms 43200000]\n agent-bridge-loopback-host --install-launchd --service-name <name> --config <private-backend> --agent <identity> --instance <stable-key> [host options]\n agent-bridge-loopback-host --uninstall-launchd --service-name <name> --port <port>\n`;\n}\n\nfunction required(args: string[], name: string): string {\n const value = option(args, name, \"\");\n if (!value) throw new Error(`${name} requires a value`);\n return value;\n}\n\nfunction serviceLabel(name: string): string {\n if (!/^[A-Za-z0-9_-]+$/.test(name)) throw new Error(\"--service-name must contain only letters, numbers, _ or -\");\n return `com.creatornader.agent-bridge.${name}`;\n}\n\nfunction launchctl(args: string[]): void {\n const result = spawnSync(\"launchctl\", args, { encoding: \"utf8\" });\n if (result.status !== 0 && result.status !== 3 && result.status !== 113) {\n throw new Error(`launchctl ${args[0]} failed: ${(result.stderr || result.stdout || \"unknown error\").trim()}`);\n }\n}\n\nfunction currentUserId(): number {\n if (!process.getuid) throw new Error(\"launchd requires a POSIX user identity\");\n return process.getuid();\n}\n\nexport function launchdPlist(options: LaunchdInstallOptions): string {\n const executable = options.executablePath ?? fileURLToPath(import.meta.url);\n const label = serviceLabel(options.serviceName);\n const environment = {\n AGENT_BRIDGE_CONFIG: options.configPath,\n AGENT_BRIDGE_AGENT: options.agent,\n AGENT_BRIDGE_INSTANCE: options.instance,\n };\n const encode = (value: string): string => value.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n const strings = (values: string[]): string => values.map((value) => ` <string>${encode(value)}</string>`).join(\"\\n\");\n const env = Object.entries(environment).map(([key, value]) => ` <key>${key}</key>\\n <string>${encode(value)}</string>`).join(\"\\n\");\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n <key>Label</key>\n <string>${label}</string>\n <key>ProgramArguments</key>\n <array>\n${strings([process.execPath, executable, \"--host\", options.host, \"--port\", String(options.port), \"--path\", options.path, \"--session-idle-ms\", String(options.sessionIdleMs)])}\n </array>\n <key>EnvironmentVariables</key>\n <dict>\n${env}\n </dict>\n <key>RunAtLoad</key>\n <true/>\n <key>KeepAlive</key>\n <true/>\n <key>StandardOutPath</key>\n <string>${encode(join(options.home ?? homedir(), \".agent-bridge\", \"logs\", `${options.serviceName}.out.log`))}</string>\n <key>StandardErrorPath</key>\n <string>${encode(join(options.home ?? homedir(), \".agent-bridge\", \"logs\", `${options.serviceName}.err.log`))}</string>\n</dict>\n</plist>\n`;\n}\n\nasync function waitForHealth(healthEndpoint: string): Promise<void> {\n let lastError = \"no response\";\n for (let attempt = 0; attempt < 30; attempt += 1) {\n try {\n const response = await fetch(healthEndpoint, { signal: AbortSignal.timeout(1_000) });\n const body = await response.json() as { status?: unknown };\n if (response.ok && body.status === \"healthy\") return;\n lastError = `HTTP ${response.status}`;\n } catch (error) {\n lastError = error instanceof Error ? error.message : String(error);\n }\n await new Promise((resolve) => setTimeout(resolve, 200));\n }\n throw new Error(`launchd started but ${healthEndpoint} did not become healthy: ${lastError}`);\n}\n\nexport async function installLaunchdHost(options: LaunchdInstallOptions): Promise<{ label: string; plistPath: string; healthEndpoint: string }> {\n if (process.platform !== \"darwin\") throw new Error(\"--install-launchd is supported only on macOS\");\n if (!isLoopback(options.host)) throw new Error(\"--host must be 127.0.0.1, ::1, or localhost\");\n if (!Number.isInteger(options.port) || options.port < 1 || options.port > 65535) throw new Error(\"--port must be an integer from 1 to 65535 for launchd\");\n if (!isAbsolute(options.configPath) || !existsSync(options.configPath)) throw new Error(`--config must be an existing absolute path: ${options.configPath}`);\n verifyPrivatePathAccess(options.configPath, \"file\");\n const home = options.home ?? homedir();\n const label = serviceLabel(options.serviceName);\n const agents = join(home, \"Library\", \"LaunchAgents\");\n const logs = join(home, \".agent-bridge\", \"logs\");\n const plistPath = join(agents, `${label}.plist`);\n mkdirSync(agents, { recursive: true, mode: 0o700 });\n mkdirSync(logs, { recursive: true, mode: 0o700 });\n chmodSync(agents, 0o700);\n chmodSync(logs, 0o700);\n launchctl([\"bootout\", `gui/${currentUserId()}/${label}`]);\n writeFileSync(plistPath, launchdPlist({ ...options, home }), { mode: 0o600 });\n chmodSync(plistPath, 0o600);\n launchctl([\"bootstrap\", `gui/${currentUserId()}`, plistPath]);\n const healthEndpoint = endpoint(options.host, options.port, `${normalizePath(options.path)}/health`);\n await waitForHealth(healthEndpoint);\n return { label, plistPath, healthEndpoint };\n}\n\nasync function portIsOpen(host: string, port: number): Promise<boolean> {\n return await new Promise((resolve) => {\n const socket = connect({ host, port });\n const finish = (open: boolean) => { socket.destroy(); resolve(open); };\n socket.once(\"connect\", () => finish(true));\n socket.once(\"error\", () => finish(false));\n socket.setTimeout(1_000, () => finish(false));\n });\n}\n\nasync function waitForPortClosed(host: string, port: number): Promise<void> {\n for (let attempt = 0; attempt < 30; attempt += 1) {\n if (!await portIsOpen(host, port)) return;\n await new Promise((resolve) => setTimeout(resolve, 200));\n }\n throw new Error(`launchd unloaded but ${host}:${port} is still accepting connections`);\n}\n\nexport async function uninstallLaunchdHost(\n serviceName: string,\n port: number,\n host = DEFAULT_HOST,\n home = homedir(),\n): Promise<{ label: string; plistPath: string }> {\n if (process.platform !== \"darwin\") throw new Error(\"--uninstall-launchd is supported only on macOS\");\n if (!isLoopback(host)) throw new Error(\"--host must be 127.0.0.1, ::1, or localhost\");\n if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error(\"--port must be an integer from 1 to 65535 for launchd\");\n const label = serviceLabel(serviceName);\n const plistPath = join(home, \"Library\", \"LaunchAgents\", `${label}.plist`);\n launchctl([\"bootout\", `gui/${currentUserId()}/${label}`]);\n rmSync(plistPath, { force: true });\n await waitForPortClosed(host, port);\n return { label, plistPath };\n}\n\nfunction isMainModule(): boolean {\n if (!process.argv[1]) return false;\n try {\n return import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href;\n } catch {\n return false;\n }\n}\n\nif (isMainModule()) {\n const args = process.argv.slice(2);\n if (args.includes(\"--help\") || args.includes(\"-h\")) process.stdout.write(usage());\n else if (args.includes(\"--install-launchd\")) {\n void (async () => {\n try {\n const result = await installLaunchdHost({\n serviceName: required(args, \"--service-name\"),\n configPath: required(args, \"--config\"),\n agent: required(args, \"--agent\"),\n instance: required(args, \"--instance\"),\n host: option(args, \"--host\", DEFAULT_HOST),\n port: Number(option(args, \"--port\", String(DEFAULT_PORT))),\n path: option(args, \"--path\", DEFAULT_PATH),\n sessionIdleMs: Number(option(args, \"--session-idle-ms\", String(DEFAULT_SESSION_IDLE_MS))),\n });\n process.stdout.write(`${JSON.stringify({ status: \"installed\", ...result })}\\n`);\n } catch (error) {\n process.stderr.write(`agent-bridge-loopback-host: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n }\n })();\n } else if (args.includes(\"--uninstall-launchd\")) {\n void (async () => {\n try {\n const result = await uninstallLaunchdHost(\n required(args, \"--service-name\"),\n Number(required(args, \"--port\")),\n option(args, \"--host\", DEFAULT_HOST),\n );\n process.stdout.write(`${JSON.stringify({ status: \"uninstalled\", ...result })}\\n`);\n } catch (error) {\n process.stderr.write(`agent-bridge-loopback-host: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n }\n })();\n }\n else void startLoopbackHost({\n host: option(args, \"--host\", DEFAULT_HOST),\n port: Number(option(args, \"--port\", String(DEFAULT_PORT))),\n path: option(args, \"--path\", DEFAULT_PATH),\n sessionIdleMs: Number(option(args, \"--session-idle-ms\", String(DEFAULT_SESSION_IDLE_MS))),\n }).then((host) => {\n const shutdown = () => void host.close().finally(() => process.exit(0));\n process.once(\"SIGINT\", shutdown);\n process.once(\"SIGTERM\", shutdown);\n }).catch((error) => {\n process.stderr.write(`agent-bridge-loopback-host: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n });\n}\n"],"mappings":"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","names":["session"]}
@@ -9,6 +9,7 @@ import {
9
9
  } from "./chunk-7B3XRRNI.js";
10
10
 
11
11
  // src/stdio-http-proxy.ts
12
+ import { realpathSync } from "fs";
12
13
  import { pathToFileURL } from "url";
13
14
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
14
15
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
@@ -45,7 +46,15 @@ async function startStdioHttpProxy(endpoint) {
45
46
  function usage() {
46
47
  return "Usage: agent-bridge-stdio-http-proxy --endpoint http://127.0.0.1:<port>/mcp\n";
47
48
  }
48
- if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
49
+ function isMainModule() {
50
+ if (!process.argv[1]) return false;
51
+ try {
52
+ return import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href;
53
+ } catch {
54
+ return false;
55
+ }
56
+ }
57
+ if (isMainModule()) {
49
58
  const args = process.argv.slice(2);
50
59
  if (args.includes("--help") || args.includes("-h")) process.stdout.write(usage());
51
60
  else {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stdio-http-proxy.ts"],"sourcesContent":["import { pathToFileURL } from \"node:url\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { CallToolRequestSchema, ListToolsRequestSchema, type CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { validateLoopbackMcpUrl } from \"./client-lifecycle.js\";\nimport { packageVersion } from \"./package-metadata.js\";\n\nexport interface StdioHttpProxyRuntime {\n server: Server;\n close(): Promise<void>;\n}\n\nexport async function createStdioHttpProxyRuntime(endpoint: string): Promise<StdioHttpProxyRuntime> {\n const url = validateLoopbackMcpUrl(endpoint, \"--endpoint\");\n const upstreamTransport = new StreamableHTTPClientTransport(new URL(url));\n const upstream = new Client({ name: \"agent-bridge-stdio-http-proxy\", version: packageVersion() });\n await upstream.connect(upstreamTransport);\n const listed = await upstream.listTools();\n const server = new Server(\n { name: \"agent-bridge-stdio-http-proxy\", version: packageVersion() },\n { capabilities: { tools: {} } },\n );\n server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: listed.tools }));\n server.setRequestHandler(CallToolRequestSchema, async (request) =>\n upstream.callTool(request.params) as Promise<CallToolResult>);\n return {\n server,\n close: async () => {\n await Promise.allSettled([server.close(), upstream.close(), upstreamTransport.close()]);\n },\n };\n}\n\nexport async function startStdioHttpProxy(endpoint: string): Promise<void> {\n const runtime = await createStdioHttpProxyRuntime(endpoint);\n const transport = new StdioServerTransport();\n const shutdown = () => void Promise.allSettled([transport.close(), runtime.close()]).finally(() => process.exit(0));\n process.once(\"SIGINT\", shutdown);\n process.once(\"SIGTERM\", shutdown);\n await runtime.server.connect(transport);\n}\n\nfunction usage(): string {\n return \"Usage: agent-bridge-stdio-http-proxy --endpoint http://127.0.0.1:<port>/mcp\\n\";\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n const args = process.argv.slice(2);\n if (args.includes(\"--help\") || args.includes(\"-h\")) process.stdout.write(usage());\n else {\n const index = args.indexOf(\"--endpoint\");\n const endpoint = index < 0 ? undefined : args[index + 1];\n if (!endpoint || args.length !== 2) {\n process.stderr.write(`agent-bridge-stdio-http-proxy: ${usage()}`);\n process.exitCode = 1;\n } else {\n void startStdioHttpProxy(endpoint).catch((error) => {\n process.stderr.write(`agent-bridge-stdio-http-proxy: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n });\n }\n }\n}\n"],"mappings":";;;;;;;;;;;AAAA,SAAS,qBAAqB;AAC9B,SAAS,cAAc;AACvB,SAAS,qCAAqC;AAC9C,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC,SAAS,uBAAuB,8BAAmD;AASnF,eAAsB,4BAA4B,UAAkD;AAClG,QAAM,MAAM,uBAAuB,UAAU,YAAY;AACzD,QAAM,oBAAoB,IAAI,8BAA8B,IAAI,IAAI,GAAG,CAAC;AACxE,QAAM,WAAW,IAAI,OAAO,EAAE,MAAM,iCAAiC,SAAS,eAAe,EAAE,CAAC;AAChG,QAAM,SAAS,QAAQ,iBAAiB;AACxC,QAAM,SAAS,MAAM,SAAS,UAAU;AACxC,QAAM,SAAS,IAAI;AAAA,IACjB,EAAE,MAAM,iCAAiC,SAAS,eAAe,EAAE;AAAA,IACnE,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,EAChC;AACA,SAAO,kBAAkB,wBAAwB,aAAa,EAAE,OAAO,OAAO,MAAM,EAAE;AACtF,SAAO,kBAAkB,uBAAuB,OAAO,YACrD,SAAS,SAAS,QAAQ,MAAM,CAA4B;AAC9D,SAAO;AAAA,IACL;AAAA,IACA,OAAO,YAAY;AACjB,YAAM,QAAQ,WAAW,CAAC,OAAO,MAAM,GAAG,SAAS,MAAM,GAAG,kBAAkB,MAAM,CAAC,CAAC;AAAA,IACxF;AAAA,EACF;AACF;AAEA,eAAsB,oBAAoB,UAAiC;AACzE,QAAM,UAAU,MAAM,4BAA4B,QAAQ;AAC1D,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,WAAW,MAAM,KAAK,QAAQ,WAAW,CAAC,UAAU,MAAM,GAAG,QAAQ,MAAM,CAAC,CAAC,EAAE,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC;AAClH,UAAQ,KAAK,UAAU,QAAQ;AAC/B,UAAQ,KAAK,WAAW,QAAQ;AAChC,QAAM,QAAQ,OAAO,QAAQ,SAAS;AACxC;AAEA,SAAS,QAAgB;AACvB,SAAO;AACT;AAEA,IAAI,QAAQ,KAAK,CAAC,KAAK,YAAY,QAAQ,cAAc,QAAQ,KAAK,CAAC,CAAC,EAAE,MAAM;AAC9E,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,MAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,EAAG,SAAQ,OAAO,MAAM,MAAM,CAAC;AAAA,OAC3E;AACH,UAAM,QAAQ,KAAK,QAAQ,YAAY;AACvC,UAAM,WAAW,QAAQ,IAAI,SAAY,KAAK,QAAQ,CAAC;AACvD,QAAI,CAAC,YAAY,KAAK,WAAW,GAAG;AAClC,cAAQ,OAAO,MAAM,kCAAkC,MAAM,CAAC,EAAE;AAChE,cAAQ,WAAW;AAAA,IACrB,OAAO;AACL,WAAK,oBAAoB,QAAQ,EAAE,MAAM,CAAC,UAAU;AAClD,gBAAQ,OAAO,MAAM,kCAAkC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,CAAI;AACjH,gBAAQ,WAAW;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/stdio-http-proxy.ts"],"sourcesContent":["import { realpathSync } from \"node:fs\";\nimport { pathToFileURL } from \"node:url\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { CallToolRequestSchema, ListToolsRequestSchema, type CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport { validateLoopbackMcpUrl } from \"./client-lifecycle.js\";\nimport { packageVersion } from \"./package-metadata.js\";\n\nexport interface StdioHttpProxyRuntime {\n server: Server;\n close(): Promise<void>;\n}\n\nexport async function createStdioHttpProxyRuntime(endpoint: string): Promise<StdioHttpProxyRuntime> {\n const url = validateLoopbackMcpUrl(endpoint, \"--endpoint\");\n const upstreamTransport = new StreamableHTTPClientTransport(new URL(url));\n const upstream = new Client({ name: \"agent-bridge-stdio-http-proxy\", version: packageVersion() });\n await upstream.connect(upstreamTransport);\n const listed = await upstream.listTools();\n const server = new Server(\n { name: \"agent-bridge-stdio-http-proxy\", version: packageVersion() },\n { capabilities: { tools: {} } },\n );\n server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: listed.tools }));\n server.setRequestHandler(CallToolRequestSchema, async (request) =>\n upstream.callTool(request.params) as Promise<CallToolResult>);\n return {\n server,\n close: async () => {\n await Promise.allSettled([server.close(), upstream.close(), upstreamTransport.close()]);\n },\n };\n}\n\nexport async function startStdioHttpProxy(endpoint: string): Promise<void> {\n const runtime = await createStdioHttpProxyRuntime(endpoint);\n const transport = new StdioServerTransport();\n const shutdown = () => void Promise.allSettled([transport.close(), runtime.close()]).finally(() => process.exit(0));\n process.once(\"SIGINT\", shutdown);\n process.once(\"SIGTERM\", shutdown);\n await runtime.server.connect(transport);\n}\n\nfunction usage(): string {\n return \"Usage: agent-bridge-stdio-http-proxy --endpoint http://127.0.0.1:<port>/mcp\\n\";\n}\n\nfunction isMainModule(): boolean {\n if (!process.argv[1]) return false;\n try {\n return import.meta.url === pathToFileURL(realpathSync(process.argv[1])).href;\n } catch {\n return false;\n }\n}\n\nif (isMainModule()) {\n const args = process.argv.slice(2);\n if (args.includes(\"--help\") || args.includes(\"-h\")) process.stdout.write(usage());\n else {\n const index = args.indexOf(\"--endpoint\");\n const endpoint = index < 0 ? undefined : args[index + 1];\n if (!endpoint || args.length !== 2) {\n process.stderr.write(`agent-bridge-stdio-http-proxy: ${usage()}`);\n process.exitCode = 1;\n } else {\n void startStdioHttpProxy(endpoint).catch((error) => {\n process.stderr.write(`agent-bridge-stdio-http-proxy: ${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n });\n }\n }\n}\n"],"mappings":";;;;;;;;;;;AAAA,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,cAAc;AACvB,SAAS,qCAAqC;AAC9C,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC,SAAS,uBAAuB,8BAAmD;AASnF,eAAsB,4BAA4B,UAAkD;AAClG,QAAM,MAAM,uBAAuB,UAAU,YAAY;AACzD,QAAM,oBAAoB,IAAI,8BAA8B,IAAI,IAAI,GAAG,CAAC;AACxE,QAAM,WAAW,IAAI,OAAO,EAAE,MAAM,iCAAiC,SAAS,eAAe,EAAE,CAAC;AAChG,QAAM,SAAS,QAAQ,iBAAiB;AACxC,QAAM,SAAS,MAAM,SAAS,UAAU;AACxC,QAAM,SAAS,IAAI;AAAA,IACjB,EAAE,MAAM,iCAAiC,SAAS,eAAe,EAAE;AAAA,IACnE,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,EAChC;AACA,SAAO,kBAAkB,wBAAwB,aAAa,EAAE,OAAO,OAAO,MAAM,EAAE;AACtF,SAAO,kBAAkB,uBAAuB,OAAO,YACrD,SAAS,SAAS,QAAQ,MAAM,CAA4B;AAC9D,SAAO;AAAA,IACL;AAAA,IACA,OAAO,YAAY;AACjB,YAAM,QAAQ,WAAW,CAAC,OAAO,MAAM,GAAG,SAAS,MAAM,GAAG,kBAAkB,MAAM,CAAC,CAAC;AAAA,IACxF;AAAA,EACF;AACF;AAEA,eAAsB,oBAAoB,UAAiC;AACzE,QAAM,UAAU,MAAM,4BAA4B,QAAQ;AAC1D,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,WAAW,MAAM,KAAK,QAAQ,WAAW,CAAC,UAAU,MAAM,GAAG,QAAQ,MAAM,CAAC,CAAC,EAAE,QAAQ,MAAM,QAAQ,KAAK,CAAC,CAAC;AAClH,UAAQ,KAAK,UAAU,QAAQ;AAC/B,UAAQ,KAAK,WAAW,QAAQ;AAChC,QAAM,QAAQ,OAAO,QAAQ,SAAS;AACxC;AAEA,SAAS,QAAgB;AACvB,SAAO;AACT;AAEA,SAAS,eAAwB;AAC/B,MAAI,CAAC,QAAQ,KAAK,CAAC,EAAG,QAAO;AAC7B,MAAI;AACF,WAAO,YAAY,QAAQ,cAAc,aAAa,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE;AAAA,EAC1E,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,IAAI,aAAa,GAAG;AAClB,QAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,MAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,IAAI,EAAG,SAAQ,OAAO,MAAM,MAAM,CAAC;AAAA,OAC3E;AACH,UAAM,QAAQ,KAAK,QAAQ,YAAY;AACvC,UAAM,WAAW,QAAQ,IAAI,SAAY,KAAK,QAAQ,CAAC;AACvD,QAAI,CAAC,YAAY,KAAK,WAAW,GAAG;AAClC,cAAQ,OAAO,MAAM,kCAAkC,MAAM,CAAC,EAAE;AAChE,cAAQ,WAAW;AAAA,IACrB,OAAO;AACL,WAAK,oBAAoB,QAAQ,EAAE,MAAM,CAAC,UAAU;AAClD,gBAAQ,OAAO,MAAM,kCAAkC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,CAAI;AACjH,gBAAQ,WAAW;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@creatornader/agent-bridge",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "description": "Let AI agents message each other and hand off work across tools, sessions, and machines.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",