Documentation

Everything you need to connect your AI agent to a Roku device with roku-mcp.

Installation

No install required for MCP usage — npx handles it. For CLI or library use:

npm install @danecodes/roku-mcp

Requires Node.js 18+ and a Roku device in developer mode on your network.

Configuration

Set your Roku device IP address:

MethodHow
MCP serverSet ROKU_DEVICE_IP env var in your MCP config
CLIUse --device <ip> flag (defaults to 192.168.0.30)
ScreenshotsSet ROKU_DEV_PASSWORD if your password isn't rokudev

Claude Code / Cursor / Windsurf

Add to .mcp.json (project root or ~/.claude/.mcp.json for global):

{
  "mcpServers": {
    "roku": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "--package", "@danecodes/roku-mcp", "roku-mcp-server"],
      "env": {
        "ROKU_DEVICE_IP": "192.168.0.30"
      }
    }
  }
}

Replace 192.168.0.30 with your Roku's IP address. The server starts automatically when your agent needs a Roku tool.

GitHub Copilot (VS Code)

Copilot requires the HTTP transport. Start the server in a terminal first:

ROKU_DEVICE_IP=192.168.0.30 npx --package @danecodes/roku-mcp roku-mcp-http
# roku-mcp HTTP server running at http://localhost:3141/mcp

Then add to .vscode/mcp.json:

{
  "servers": {
    "roku": {
      "type": "http",
      "url": "http://localhost:3141/mcp"
    }
  }
}

Custom port: set ROKU_MCP_PORT=8888.

OpenAI Codex CLI

Add to ~/.codex/config.toml (global) or .codex/config.toml (project):

[mcp_servers.roku]
command = "npx"
args = ["-y", "--package", "@danecodes/roku-mcp", "roku-mcp-server"]

[mcp_servers.roku.env]
ROKU_DEVICE_IP = "192.168.0.30"

Device Control Tools

ToolDescription
roku_ui_treeGet the full SceneGraph UI tree — see what's on screen
roku_find_elementFind elements by CSS-like selector
roku_press_keySend remote control key press (Select, Up, Down, Left, Right, Back, Home, etc.)
roku_type_textType text into keyboard inputs
roku_screenshotTake a screenshot, optionally save to disk
roku_launchLaunch a channel with optional deep link params
roku_deep_linkDeep link directly into content by ID
roku_close_appClose the running app (press Home)
roku_sideloadDeploy a .zip package to the device
roku_device_infoGet device model, software version, network info
roku_active_appGet the currently running app
roku_media_playerGet playback state (position, duration, format)
roku_installed_appsList all installed channels
roku_console_logRead BrightScript debug console output (errors, print statements, crashes)
roku_console_commandSend debug commands (bt, var, cont, step, over, out)
roku_volumeVolume up, down, or mute
roku_inputSend custom input parameters to the running app

Test Runner Tools

ToolDescription
roku_wait_forPoll until a selector appears on screen with configurable timeout — use after navigation
roku_assert_elementAssert an element exists, is focused, or has a specific attribute value — returns pass/fail JSON
roku_sideload_and_watchSideload a zip + watch console for errors/crashes — returns CI-ready pass/fail report
roku_smoke_testLaunch app, verify UI renders, optionally verify playback — full pass/fail with step detail

Smoke Test Example

→ roku_smoke_test(
    content_id: "ABC123XYZ",
    media_type: "episode",
    ui_timeout: 15000,
    playback_timeout: 30000
  )

  {
    "passed": true,
    "message": "PASS: App launched, UI rendered, and playback started",
    "steps": [
      { "name": "launch", "passed": true,
        "message": "Deep linked to \"ABC123XYZ\" in channel dev" },
      { "name": "ui_visible", "passed": true,
        "message": "UI rendered after 2340ms", "elapsed_ms": 2340 },
      { "name": "playback", "passed": true,
        "message": "Player reached \"play\" after 8710ms", "elapsed_ms": 8710 }
    ],
    "player_state": {
      "state": "play",
      "position": "00:00:08",
      "duration": "00:42:17"
    }
  }

Agent Efficiency Tools

Token-efficient alternatives to full tree scans. Use these when you only need one piece of information.

ToolDescription
roku_focused_elementReturn only the currently focused element — avoids a full tree scan
roku_screen_nameInfer the current screen name from the SceneGraph root component
roku_console_watchMonitor console for a pattern match during a time window — pass/fail with matching lines

Shift Left Quality Gates

ToolDescription
roku_cert_preflightRun Roku cert failure checklist (back nav, Home exit, relaunch, error scan)
roku_chanperf_sampleSample CPU usage via chanperf for a configurable duration — high watermark + pass/fail

Cert Preflight

Runs the common Roku certification failure checks automatically:

  • Back button navigation from each screen
  • Home button exits cleanly
  • App relaunch after Home exit
  • Console error scan during the entire flow

Selector Syntax

Find elements using CSS-like selectors against SceneGraph node names:

SelectorExampleMatches
Tag nameHomePageNode with tag HomePage
ID#titleLabelNode with name="titleLabel"
Tag + IDAppButton#play_buttonAppButton with name="play_button"
DescendantHomePage HomeHeroCarouselHomeHeroCarousel anywhere inside HomePage
ChildLayoutGroup > AppLabelAppLabel direct child of LayoutGroup
Attribute[focused="true"]Element with that attribute value
Tag + attrAppButton[text="Play"]AppButton with text="Play"
Adjacent siblingModule + ModuleModule preceded by another
nth-childNavTab:nth-child(2)Second NavTab among siblings

CLI: UI Commands

# Full SceneGraph tree
npx roku-mcp ui tree --device 192.168.0.30
npx roku-mcp ui tree --depth 4
npx roku-mcp ui tree --all-attrs

# Find elements by selector
npx roku-mcp ui find "HomePage HomeHeroCarousel"
npx roku-mcp ui find "AppButton#play_button"
npx roku-mcp ui find "AppLabel" --all-attrs

# Raw XML source
npx roku-mcp ui source

CLI: Input Commands

# Key presses
npx roku-mcp press Select
npx roku-mcp press Down --times 3 --delay 200
npx roku-mcp press Back

# Text entry
npx roku-mcp type "search query"

# Launch apps
npx roku-mcp launch dev
npx roku-mcp launch dev --params '{"contentId":"12345","mediaType":"episode"}'

CLI: Info Commands

npx roku-mcp info device    # Device model, software, network
npx roku-mcp info app       # Currently running app
npx roku-mcp info apps      # All installed channels
npx roku-mcp info player    # Playback state

CLI: Test Commands

All test commands exit with code 1 on failure, making them CI-friendly.

# Sideload and watch for errors
npx roku-dev test sideload-watch ./target/build.zip --duration 30000

# Full smoke test with playback verification
npx roku-dev test smoke --content-id ABC123XYZ --media-type episode

# Run cert preflight checklist
npx roku-dev test cert-preflight

# Sample CPU during playback
npx roku-dev test chanperf --duration 15000 --threshold 70

Library Usage

Use roku-mcp as a TypeScript library for custom tooling:

import { EcpClient, Key, parseUiXml, findElement } from 'roku-mcp';

const roku = new EcpClient('192.168.0.30');

// Send keys
await roku.press(Key.Down, { times: 3 });
await roku.press(Key.Select);

// Inspect the UI
const xml = await roku.queryAppUi();
const tree = await parseUiXml(xml);
const button = findElement(tree, 'AppButton#play_button');
console.log(button?.attrs.focused); // "true"
console.log(button?.attrs.text);    // "Play"

// Query state
const player = await roku.queryMediaPlayer();
const app = await roku.queryActiveApp();

HTTP Transport

For editors that don't support stdio (like VS Code with Copilot), use the HTTP transport:

# Start the HTTP server
ROKU_DEVICE_IP=192.168.0.30 npx --package @danecodes/roku-mcp roku-mcp-http

# Custom port
ROKU_MCP_PORT=8888 ROKU_DEVICE_IP=192.168.0.30 npx --package @danecodes/roku-mcp roku-mcp-http

The server runs at http://localhost:3141/mcp by default and speaks the MCP HTTP transport protocol.

App Context File

Provide your agent with app-specific context by creating a roku-app.md file and setting the ROKU_APP_CONTEXT environment variable:

{
  "mcpServers": {
    "roku": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "--package", "@danecodes/roku-mcp", "roku-mcp-server"],
      "env": {
        "ROKU_DEVICE_IP": "192.168.0.30",
        "ROKU_APP_CONTEXT": "./roku-app.md"
      }
    }
  }
}

The context file can contain screen names, navigation patterns, content IDs, and any other information your agent needs to work effectively with your specific Roku app.

Auto-Approve Tool Calls

To skip the approval prompt for every Roku tool call in Claude Code, add to ~/.claude/settings.json:

{
  "permissions": {
    "allow": ["mcp__roku"]
  }
}

You can also use roku-mcp init to append a Roku playbook to your project's CLAUDE.md, giving the agent built-in knowledge of how to navigate your app.