Run the rk CLI as a persistent HTTP server for improved performance. Server mode keeps the process running with cached configuration, eliminating the startup overhead of spawning a new Node.js process for each command.

When rk finds a live server, it also uses a CLI fast path for build, dev, device, package, dcl, perfetto, and cdp. It sends the server request before importing local command modules. This reduces startup overhead for these commands compared to local-only execution.

Synopsis

The following syntax shows how to run the command:

rk server
rk server start [options]
rk server start --daemon [options]
rk server stop [--port <port>]
rk server status [--json]

Usage

The following sections describe how to start, stop, and check the server.

Starting the server

The following commands start the server:

npx rk server
npx rk server start

The command starts the rk server if it is not already running. The server does the following:

  • Binds to localhost on a port that it derives from the workspace root path: 3737 plus a hash of that path, which gives each workspace its own port. Derived ports skip WHATWG Fetch blocked ports (for example, 4045 and 4190) so that Node fetch clients can connect. You can run rk server status to see the actual port, or pin it with --port (the command rejects blocked ports).
  • Writes server info to .roku/rk-server.json for client discovery.
  • Stays running and handles commands through the HTTP REST API.
  • Exits automatically after 240 minutes of inactivity (the default; you can configure it with the --timeout option).
  • Caches device configuration and other state for faster operations.

If a server is already running, the command does nothing.

Starting as a daemon

The following command starts the server as a daemon:

npx rk server start --daemon

The command starts rk in detached background mode and exits immediately after the daemon is healthy. The command behaves as follows:

  • The parent process waits for .roku/rk-server.json and /api/health.
  • The success output includes the daemon PID, the port, and the resolved rkRoot.
  • If a healthy server already exists for the same rkRoot, the command does not start a duplicate.

The following commands show a typical workflow:

npx rk server start --daemon
npx rk server status
npx rk server stop

Stopping the server

The following commands stop the server:

npx rk server stop
npx rk server stop --port 8080

rk server stop returns once the server has exited. A server that started RCE devices with device_start stops them first, then releases its sessions; rk server stop waits as long as that shutdown may take (about three and a half minutes at most). It prints that it is waiting, and if the server has not exited by then, says so and names rk server status and rk device ls to check.

Finds the server the same way rk server status does, through the .roku/rk-server.json file in the current directory, and falls back to the port derived from the workspace root when there is no usable port file. It asks that server to exit gracefully. If no server is running, it reports that and exits successfully.

Before it exits, the server stops every Roku Cloud Emulator device it started through MCP device_start (see rce.md), then closes its log, profiling and debug sessions. The same happens on Ctrl-C, SIGTERM, SIGHUP and the inactivity timeout. A second signal while that runs exits at once, except while RCE devices are being stopped or the sessions on them closed: then the second only warns that they would keep running, and billed, until their maximum runtime, and a third exits without waiting.

A server started here with --port is recorded in that file, so rk server stop finds it without the flag. Use --port to stop a server that is not recorded in this directory's .roku/rk-server.json.

The legacy --stop flag still works during the deprecation window, but it prints a warning. You should replace it with rk server stop.

Checking server status

npx rk server status
npx rk server status --json

The command reports whether the current workspace's rk server is reachable by using the .roku/rk-server.json file in the current directory.

The human-readable output includes the server API URL, PID, rkRoot, and current log session count:

rk server running at http://localhost:4025/api (pid 12345, rkRoot: /Users/user/work/sdk/workspace)
No log sessions

When you use --json, the command prints machine-readable output:

{ "running": true, "port": 4025, "pid": 12345, "rkRoot": "/Users/user/work/sdk/workspace", "logSessions": 0 }

If the server is not running or unreachable, rk server status still exits successfully and reports that state:

rk server not running (no port file found above /Users/user/work/sdk/workspace)

Options

The rk server command supports the following options.

--port

The --port option specifies the port to bind the server. Without this option, the command derives the port from the workspace root path instead of using a fixed 3737; therefore, you must pass --port whenever a client must use a fixed port:

npx rk server start --port 8080

When you use --port with rk server stop, it targets a server that is already running on that port instead of the one recorded in .roku/rk-server.json:

npx rk server stop --port 8080

--timeout

The --timeout option configures the inactivity timeout in minutes (default: 240). The server shuts down automatically after this period of inactivity:

npx rk server start --timeout 240  # Auto-stop after 4 hours of inactivity
npx rk server start --timeout 1    # Auto-stop after 1 minute of inactivity
npx rk server start --timeout 0    # Disable automatic shutdown

You can set the value to 0 to disable automatic shutdown. The server then runs until you stop it explicitly.

--lifecycle

The --lifecycle option configures the lifecycle mode (unmanaged or managed):

npx rk server start --lifecycle unmanaged  # Default manual CLI behavior
npx rk server start --lifecycle managed    # Enable client-lease lifecycle

The option accepts the following values:

  • unmanaged (default): The server does not track client leases. The timeout and an explicit stop control its lifetime.
  • managed: The server enables client lease endpoints (/api/clients/*) and zero-client shutdown behavior.

--daemon

The --daemon option starts the server as a detached background process and exits:

npx rk server start --daemon
npx rk server start --daemon --port 8080 --lifecycle managed

The following notes describe platform differences:

  • On macOS and Linux, daemon mode is supported directly.
  • On Windows, detached process semantics differ; you can use shell backgrounding instead.

--json

The --json option is available only for rk server status:

npx rk server status --json

The command prints a JSON object that contains whether the server is running and, when the server is reachable, the port, pid, rkRoot, and logSessions values that GET /api/health returns.

Integrating with MCP clients

You can use the rk server standalone or with any compatible MCP client (for example, VS Code and Cursor). Clients can start the server on demand and connect through the configured port.

The --timeout flag controls the server timeout (default: 240 minutes, or 4 hours) and replaces the VS Code extension setting roku-sdk.pilot.serverTimeoutMinutes. You can pass --timeout 0 to disable the inactivity timeout.

You can manually control the server from the command line using npx rk server start and npx rk server stop.

Managed lifecycle design (phase 0)

See rk server managed lifecycle (Phase 0 contract) for more information about the managed and unmanaged lifecycle contract (window-based client leases, heartbeat, and zero-client shutdown).

Understanding managed runtime behavior

See Server managed lifecycle for more information about lease, heartbeat, restart, and multi-window behavior.

Integrating AI assistants with the Model Context Protocol (MCP)

See AI integration via MCP for more information about editor transports and the generated MCP reference for more information about tool parameters.

Understanding log collection

The log collection feature runs inside the rk server process. It maintains persistent telnet connections to Roku devices and buffers log lines in memory for quick retrieval and search. When configured, it also writes logs to .roku/logs and rehydrates buffers from recent files on session start. See rk logs for more information about CLI usage.

High-level flow

The following diagram shows how log lines flow through the server:

Roku device (telnet 8085/8086/...)
  |
  v
ConsoleStreamManager (shared per device:port)
  |
  v
LogSessionManager -> CircularBuffer (RAM)
  |
  +-- Optional LogFileWriter (.roku/logs/*.log)
  |
  +-- /api/logs/get (last N lines)
  +-- /api/logs/search (regex)
  +-- /api/logs/tail (SSE)

Session lifecycle

A session goes through the following stages:

  1. Start: The POST /api/logs/start route creates a session, optionally runs garbage collection (GC) and buffer rehydration from disk, and then connects to the device.
  2. Active: The server appends lines to the buffer, and you can retrieve them through get or search.
  3. Reconnect: On disconnect, the session enters reconnecting and retries with backoff.
  4. Stop: The POST /api/logs/stop route disconnects the stream but keeps the buffer in memory.
  5. Cleanup: A server shutdown or a working directory change clears sessions and disconnects managers.

By default, sessions are ephemeral and live only while the server is running. With logStorage.enabled=true, disk persistence under .roku/logs provides continuity across restarts.

Telnet connection coordination

Roku devices allow only one telnet connection for each combination of device and port. The server enforces this with a shared registry of ConsoleStreamManager instances. Multiple features (log sessions, rk dev --console, SSE tail) subscribe to the same shared connection instead of opening new ones.

ConsoleStreamManager integration

The ConsoleStreamManager integration works as follows:

  • The ConsoleStreamManager instance owns the telnet socket and normalizes log lines.
  • Log sessions call pipeToBuffer() to capture lines into the circular buffer.
  • The rk dev --console command attaches through pipeToSSE() when it runs in server mode.
  • When the last listener detaches, the manager disconnects and the server removes the registry entry.

Memory management (circular buffers)

The server manages memory as follows:

  • Each session uses a fixed-size circular buffer (default: 10,000 lines).
  • The buffer overwrites older entries when it is full.
  • The server monitors total buffer memory every 5 seconds and logs a warning if usage exceeds 100 MB.
  • You can use smaller buffers or stop unused sessions to reduce memory usage.

Reconnects and heartbeat

The server handles reconnects as follows:

  • Sessions retry with backoff delays (5, 10, 15, and 30 seconds).
  • A heartbeat checks device availability through ECP (/query/active-app).
  • If the heartbeat fails, the session transitions to reconnecting and resumes when the device returns.

Server coordination file

When the server starts, it writes connection information to:

<rkRoot>/.roku/rk-server.json

The file contains the following fields:

{
    "port": 3941,
    "pid": 12345,
    "startTime": 1698361234567,
    "apiEndpoint": "http://localhost:3941/api"
}

The port above is an example of a derived port, not a constant; another workspace produces a different number. Clients (for example, the VS Code extension) read this file to discover and connect to the running server; therefore, they do not need to know the port in advance.

Notes

The following notes apply to the rk server:

  • The server binds only to 127.0.0.1 (localhost) and is not accessible from other machines.
  • The server does not require authentication because it is accessible only locally.
  • After you update the RSG 2.0 SDK, you must restart the server to pick up the new version.
  • The server exits automatically after a configurable period of inactivity (default: 240 minutes) to avoid leaving orphaned processes. You can use --timeout to customize or disable the timeout.

HTTP API reference

See the generated HTTP reference for more information about documented routes. Command options remain here until a generated rk server page is available.

Related documentation


Did this page help you?