Skip to main content
Run your FrontMCP server over a Unix domain socket for local-only, persistent access — ideal for Claude Code integrations, background daemons, and local AI agents.
Unix socket mode is best suited for:
  • Local-only servers that don’t need network exposure
  • Claude Code / Claude Desktop integration via socketPath
  • Background daemons that persist across sessions
  • Avoiding TCP port conflicts on developer machines

Quick Start (CLI)

The frontmcp socket command starts a FrontMCP server listening on a Unix socket file.
# Start in foreground (default)
frontmcp socket ./src/main.ts

# Specify a custom socket path
frontmcp socket ./src/main.ts --socket /tmp/my-app.sock

# Enable SQLite storage for sessions and events
frontmcp socket ./src/main.ts --db ~/.frontmcp/data/my-app.sqlite

# Run as a background daemon
frontmcp socket ./src/main.ts --background

CLI Flags

FlagAliasDescription
--socket <path>-sCustom socket file path. Defaults to ~/.frontmcp/sockets/{app-name}.sock
--db <path>SQLite database path for persistent sessions and events
--background-bDetach and run as a background daemon
When no --socket path is given, the CLI automatically creates the socket at ~/.frontmcp/sockets/{app-name}.sock, where {app-name} is derived from the parent directory of your entry file.

Programmatic API

Use FrontMcpInstance.runUnixSocket() for full control from your own code.
import { FrontMcpInstance } from '@frontmcp/sdk';
import { serverConfig } from './config';

const handle = await FrontMcpInstance.runUnixSocket({
  ...serverConfig,
  socketPath: '/tmp/my-app.sock',
  sqlite: {
    path: '~/.frontmcp/data/my-app.sqlite',
  },
});

// Later: graceful shutdown
await handle.close();
The method signature:
FrontMcpInstance.runUnixSocket(options: FrontMcpConfigInput & {
  socketPath: string;
  sqlite?: SqliteOptionsInput;
}): Promise<{ close: () => Promise<void> }>
The full HTTP feature set — streamable HTTP, SSE, elicitation, sessions — works unchanged over Unix sockets. The only difference is the transport layer: a .sock file instead of a TCP port.

SQLite Storage

By default, Unix socket mode uses in-memory storage for sessions and events. For persistence across server restarts, configure SQLite.

Basic Configuration

const handle = await FrontMcpInstance.runUnixSocket({
  ...serverConfig,
  socketPath: '/tmp/my-app.sock',
  sqlite: {
    path: '~/.frontmcp/data/my-app.sqlite',
  },
});

With Encryption

Enable at-rest encryption for stored values using AES-256-GCM:
const handle = await FrontMcpInstance.runUnixSocket({
  ...serverConfig,
  socketPath: '/tmp/my-app.sock',
  sqlite: {
    path: '~/.frontmcp/data/my-app.sqlite',
    encryption: {
      secret: process.env.FRONTMCP_ENCRYPTION_SECRET!,
    },
  },
});

SQLite Options

OptionTypeDefaultDescription
pathstringrequiredPath to the .sqlite database file
encryption.secretstringSecret key for AES-256-GCM encryption via HKDF-SHA256
walModebooleantrueEnable WAL mode for better read concurrency
ttlCleanupIntervalMsnumber60000Interval in ms for purging expired keys

Connecting to the Socket

curl

# Health check
curl --unix-socket /tmp/my-app.sock http://localhost/health

# Call the MCP endpoint
curl --unix-socket /tmp/my-app.sock http://localhost/mcp \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Node.js (node:http)

import http from 'node:http';

const options = {
  socketPath: '/tmp/my-app.sock',
  path: '/mcp',
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
};

const req = http.request(options, (res) => {
  let data = '';
  res.on('data', (chunk) => (data += chunk));
  res.on('end', () => console.log(JSON.parse(data)));
});

req.write(JSON.stringify({
  jsonrpc: '2.0',
  id: 1,
  method: 'tools/list',
}));
req.end();

Claude Desktop / Claude Code

Point your MCP client config at the socket file:
{
  "mcpServers": {
    "my-server": {
      "transport": "http",
      "url": "http://localhost/mcp",
      "socketPath": "/tmp/my-app.sock"
    }
  }
}

Socket Lifecycle

Permissions

When the server starts listening, the socket file is set to permission mode 0o660 (owner and group read/write). This prevents other users on the machine from connecting.

Stale Socket Cleanup

If a .sock file already exists when the server starts (e.g., from a previous crash), it is automatically removed before binding. This avoids EADDRINUSE errors.

Graceful Shutdown

The server registers handlers for SIGINT and SIGTERM. On either signal:
  1. The socket file is removed
  2. The PID file (if running via CLI) is cleaned up
  3. The process exits cleanly
// Programmatic shutdown
const handle = await FrontMcpInstance.runUnixSocket({ ... });

// When you're done:
await handle.close();

PID File (CLI Background Mode)

When launched with --background, the CLI writes a PID file at {socketPath}.pid so you can manage the daemon:
# Check if running
cat /tmp/my-app.sock.pid

# Stop the daemon
kill $(cat /tmp/my-app.sock.pid)

Best Practices

macOS limits Unix socket paths to 104 bytes. Keep your socket paths short. The default location ~/.frontmcp/sockets/{app}.sock is designed to stay within this limit.
# Good — short path
/tmp/my-app.sock

# Risky — may exceed 104 bytes on deep home directories
/Users/longusername/deeply/nested/project/path/.frontmcp/sockets/my-very-long-app-name.sock
Let the CLI pick the default path (~/.frontmcp/sockets/) unless you have a specific reason to override. This keeps sockets organized and discoverable.
Unix sockets provide natural access control via file permissions — no firewall rules needed. They also avoid port conflicts and have slightly lower latency than loopback TCP.
The stale socket cleanup handles normal cases, but if your process is killed with SIGKILL (kill -9), the socket file may linger. Use the CLI’s built-in cleanup or manually remove the file before restarting:
rm -f /tmp/my-app.sock /tmp/my-app.sock.pid
Without SQLite, all session data lives in memory and is lost on restart. If your use case requires sessions to survive restarts (e.g., a background daemon), enable SQLite storage with the --db flag or the sqlite config option.

Runtime Modes

Compare SDK, Server, and Handler deployment modes

DirectClient

Programmatic in-process access without any transport

Redis Setup

Configure Redis for distributed session storage

Production Build

Build and optimize for production deployment