agentsclimarketplace

Long lived mcp daemon over unix socket

Skill kjuhwa/skills-hub/skills/daemon/long-lived-mcp-daemon-over-unix-socket

Front an MCP stdio server with a long-lived local daemon so a CLI can invoke tools across many short-lived commands while preserving browser/session state, using a Unix socket on POSIX and a named pipe on Windows.From its SKILL.md

Install
npx -y skills add kjuhwa/skills-hub --skill long-lived-mcp-daemon-over-unix-socket

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

4.1 KB, 820 tokens by cl100k_base, as published. Nobody here has run it

Long-Lived MCP Daemon with Socket IPC

When to use

  • Your MCP server holds expensive state per session (a browser, a DB connection pool, a trained model) and you don't want each CLI invocation to pay the cold-start cost.
  • You want mycli status, mycli navigate URL, mycli screenshot to feel like a REPL — each command returns in milliseconds but the underlying server stays up.
  • Multiple MCP server args (--headless, --userDataDir) need to be captured at daemon start and applied to every subsequent call.

How it works

  • Daemon process: on start, write its PID to a well-known file, open a local socket, then spawn the MCP stdio server as a child and connect to it with an MCP Client using StdioClientTransport. Accept messages like {method: 'invoke_tool', tool, args} and {method: 'stop'} / {method: 'status'}. Forward invoke_tool to the MCP client, serialize the response, send back.
  • Client (CLI) process: check if PID file exists and the process is alive (process.kill(pid, 0)). If not, spawn the daemon detached with child.unref() and wait for the PID file to appear before sending the first command.
  • Socket path: use XDG_RUNTIME_DIR if set, otherwise /tmp/<app>-<uid>.sock on macOS/Linux (NOT ~/Library/Application Support — POSIX socket paths are capped around 104 chars). On Windows use \\.\pipe\<app>\server.sock — named pipes, not files.
  • Reuse an MCP PipeTransport for framing JSON messages over the raw socket. Send one command per connection, close on response; keeps the protocol trivially stateless and avoids read-buffer demux.
  • Surface start, stop, status as explicit CLI subcommands; auto-start on first tool call but never auto-stop — let the user decide when to release state.

Example

// daemon.ts - listens on socket, forwards to inner MCP stdio server
const mcpClient = new Client({name: 'daemon', version}, {capabilities:{}});
await mcpClient.connect(new StdioClientTransport({
  command: process.execPath, args: [INDEX_SCRIPT_PATH, ...serverArgs],
}));
createServer(socket => {
  const transport = new PipeTransport(socket, socket);
  transport.onmessage = async (msg) => {
    const { method, tool, args } = JSON.parse(msg);
    const result = await mcpClient.callTool({ name: tool, arguments: args });
    transport.send(JSON.stringify({ success: true, result: JSON.stringify(result) }));
    socket.end();
  };
}).listen({ path: socketPath });

// client.ts - one-shot call
const socket = net.createConnection({ path: getSocketPath() });
const transport = new PipeTransport(socket, socket);
transport.onmessage = m => resolve(JSON.parse(m));
transport.send(JSON.stringify({ method: 'invoke_tool', tool: 'navigate_page', args: {url} }));

Gotchas

  • On macOS/Linux, the PID file can outlive a crashed daemon; always probe with process.kill(pid, 0) before trusting it. Delete stale files during start.
  • On non-Windows platforms, unlinkSync(socketPath) before listen() — a stale socket file blocks bind even if the previous process is gone.
  • Detached spawn on Windows: pass windowsHide: true and stdio: 'ignore', else the daemon flashes a console window.
  • If the underlying MCP server streams large results (images, traces), serialize to a temp file and return the path, not the bytes — socket IPC is not the place for megabyte payloads.
  • Time-out the client's socket read with a generous default (the daemon example uses 60s); some MCP tool calls genuinely take that long.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,764. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.