/** * Every directory the socket and the daemon log may live in, best first. * * XDG_RUNTIME_DIR first: it is per-user, mode 0700, and cleared on logout, so a * socket never outlives the login session that made it. macOS never sets it, * hence the per-uid directory under TMPDIR — which is also what keeps one * user's socket out of another's reach on a shared /tmp. `/tmp` itself is the * last resort: a TMPDIR long enough to break the path limit still leaves it. * * This is a LIST, not one answer, because every entry but the last comes from * the environment. A sandbox, a read-only mount or a stale variable pointing at * a directory this user cannot write makes the first choice fail, and one * failed candidate must cost a session nothing: the next one is tried. */ export declare function socketDirCandidates(): string[]; /** * Create `dir` if it is missing, and report whether it is a directory this * process can write afterwards. Never throws: a candidate that cannot be used * is a reason to try the next one, not a failure. * * Deliberately NOT `mkdirSync(dir, { recursive: true })`. Node 23's recursive * mkdir walks BACK to the parent whenever a component reports ENOENT and * forward again when one exists — and a path whose parent exists while the * child still reports ENOENT makes it oscillate between the two forever, at * 100% of a core. `/proc/anything` does exactly that on Linux: `mkdir * /proc/x` returns ENOENT, not EACCES. This path comes from XDG_RUNTIME_DIR or * TMPDIR — the values this program does not control — so it must never be * handed to that loop. (Verified on Node v23.9.0: the recursive call never * returns; a single-level `mkdirSync` on the same path throws ENOENT at once.) * * This walks up to the deepest ancestor that already exists, bounded, then * creates forward from there ONE level at a time. It never revisits a level, * so it cannot spin. */ export declare function usableDir(dir: string): boolean; /** * Make `dir` private to this user, and report whether that took effect. * * This is also the OWNERSHIP proof. `usableDir` says yes to anything writable, * and on a shared /tmp that includes a directory another local user created * first — our socket would then sit in their directory, theirs to swap out. * chmod(2) fails with EPERM for anyone but the owner, so a chmod that * succeeded means we own the directory; the mode check after it catches a * filesystem that accepts chmod and ignores it (FAT, some FUSE mounts). No * uid comparison, no window between a stat and a chmod. Windows has no POSIX * modes; the per-user LOCALAPPDATA path is the protection there. */ export declare function privateDir(dir: string): boolean; /** * The runtime directory for this user: the first candidate that can be used * AND made private, created on the way. Throws only when NO candidate works, * which the relay turns into serving the session in-process. */ export declare function ensureSocketDir(): string; /** * Close the socket file itself to other users. connect(2) needs write * permission on a Unix socket, so 0600 refuses every other uid even if the * directory were traversable. Named pipes on Windows are not files. */ export declare function restrictSocket(path: string): void; /** * What makes two sessions share a daemon. * * The profile decides WHICH TOOLS a server registers — "lean" is 27, "full" is * all 61 — and that list is fixed when the server object is built. Two sessions * that asked for different lists therefore cannot share one daemon; keying on it * gives them one each. The server URL is in the key for the same reason: a * daemon holds a connection to one backend. * * The version is in it because without it an upgraded package would attach to a * daemon still running the old code — the handshake would succeed and every * answer would come from the version the user believes they replaced. */ export declare function socketSlug(version: string): string; /** * The address the daemon listens on, inside the runtime directory the caller * resolved with `ensureSocketDir()`. * * Windows gets a named pipe rather than a file. Node's local-domain sockets ARE * named pipes there, and a path outside the pipe namespace is not a valid one — * so this is the native equivalent, not a workaround. It also needs no * directory and leaves nothing behind when the daemon dies. */ export declare function socketPath(dir: string, version: string): string; /** Where a daemon's diagnostics go. Never a session's stderr: it outlives it. */ export declare function logPath(dir: string, version: string): string; /** * The flag the relay hands the daemon it starts. The relay already resolved a * directory and is waiting on that exact path, so the daemon binds there rather * than resolving again — a second resolution could land somewhere else if the * environment shifted between the two processes. */ export declare const SOCKET_FLAG = "--socket"; /** The path given with `--socket`, if the process was started with one. */ export declare function socketPathFromArgv(argv: readonly string[]): string | undefined; /** True unless the user asked to keep everything inside their own session. */ export declare function daemonEnabled(): boolean; //# sourceMappingURL=mcp-socket.d.ts.map