{
  "markdown": "# roku-mcp\n\nA [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server for Roku device automation. Exposes tools for app deployment, ECP remote control, screenshot capture, SceneGraph node inspection, and BrightScript debug console access.\n\n## Install\n\nThe server ships as a single `npx` command. Install once globally if you prefer, or let your MCP client launch it on demand via `npx -y roku-mcp` — both work.\n\n```bash\nnpm install -g roku-mcp     # optional, global install\n# or just point your client at: npx -y roku-mcp\n```\n\nConfigure your AI client below. Every platform uses the same launch line; only the config file and reload step change.\n\n<details>\n<summary><strong>Cursor</strong> — agent-mode tools, auto-discovers MCP servers</summary>\n\n**Prerequisites:** Cursor 0.45+ with Agent mode.\n\n**Install:** create `.cursor/mcp.json` in your project root (or `~/.cursor/mcp.json` for global):\n\n```json\n{\n  \"mcpServers\": {\n    \"roku\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"roku-mcp\"],\n      \"env\": {\n        \"ROKU_DEVICE_HOST\": \"192.168.1.XXX\",\n        \"ROKU_DEVICE_PASSWORD\": \"your-password\"\n      }\n    }\n  }\n}\n```\n\nThen reload the window (`Cmd+Shift+P` / `Ctrl+Shift+P` → **Developer: Reload Window**).\n\n**Verify:** open **Cursor Settings → MCP** and confirm the `roku` row shows a green dot. If it appears disabled, click the toggle. In a new agent chat, type `list roku tools` — you should see `roku_deploy`, `roku_screenshot`, etc.\n\n**Routing rule (recommended):** the repo also ships an [`AGENTS.md`](./AGENTS.md). Cursor picks it up automatically, so the agent knows the canonical *observe → act → wait → verify* loop and the RTA `uiElementId` gotcha without you having to re-explain it every session.\n\n**Troubleshoot:** if the server stays grey/disabled, check `View → Output → MCP Logs` — the most common cause is `ROKU_DEVICE_HOST` unreachable on the LAN. Omit the `env` block entirely to fall back to SSDP auto-discovery.\n\n</details>\n\n<details>\n<summary><strong>VS Code (GitHub Copilot)</strong> — agent mode, MCP via <code>.vscode/mcp.json</code></summary>\n\n**Prerequisites:** VS Code 1.99+ with the GitHub Copilot extension and an active Copilot subscription that includes Agent mode.\n\n**Install:** create `.vscode/mcp.json` in your project root:\n\n```json\n{\n  \"servers\": {\n    \"roku\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"roku-mcp\"],\n      \"env\": {\n        \"ROKU_DEVICE_HOST\": \"192.168.1.XXX\",\n        \"ROKU_DEVICE_PASSWORD\": \"your-password\"\n      }\n    }\n  }\n}\n```\n\nReload the window (`Cmd+Shift+P` / `Ctrl+Shift+P` → **Developer: Reload Window**).\n\n**Verify:** open Copilot Chat, switch the chat-mode dropdown to **Agent**, and ask \"what roku tools do you have?\". You should see the full `roku_*` list. The MCP panel (`Cmd+Shift+P` → **MCP: List Servers**) should show `roku` as `Running`.\n\n**Troubleshoot:** if the server fails to start, run `npx -y roku-mcp --help` in a regular terminal first — that confirms Node 18+ and `npx` are working before VS Code launches it.\n\n</details>\n\n<details>\n<summary><strong>Claude Desktop</strong> — official Anthropic desktop app</summary>\n\n**Prerequisites:** Claude Desktop (latest from claude.ai/download), Node.js 18+ on `PATH`.\n\n**Install:** edit your Claude Desktop config:\n\n- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`\n- Windows: `%APPDATA%\\Claude\\claude_desktop_config.json`\n\n```json\n{\n  \"mcpServers\": {\n    \"roku\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"roku-mcp\"],\n      \"env\": {\n        \"ROKU_DEVICE_HOST\": \"192.168.1.XXX\",\n        \"ROKU_DEVICE_PASSWORD\": \"your-password\"\n      }\n    }\n  }\n}\n```\n\nFully quit and restart Claude Desktop (the menu-bar icon must close — `Cmd+Q` on macOS).\n\n**Verify:** open a new chat. The 🛠️ icon in the input bar should list `roku-mcp` with all its tools. Ask \"take a Roku screenshot\" — Claude will request approval for `roku_screenshot` and run it.\n\n**Troubleshoot:** if no tool icon appears, check `~/Library/Logs/Claude/mcp-server-roku.log` (macOS) — `command not found: npx` means Node isn't on the GUI app's `PATH`. Either install Node via the official `.pkg`, or hard-code the absolute paths: `\"command\": \"/usr/local/bin/node\"`, `\"args\": [\"/usr/local/bin/npx\", \"-y\", \"roku-mcp\"]`.\n\n</details>\n\n<details>\n<summary><strong>Windsurf</strong> — Codeium's agentic IDE</summary>\n\n**Prerequisites:** Windsurf with Cascade enabled.\n\n**Install:** create `.windsurf/mcp.json` in your project root (or `~/.codeium/windsurf/mcp_config.json` globally):\n\n```json\n{\n  \"mcpServers\": {\n    \"roku\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"roku-mcp\"],\n      \"env\": {\n        \"ROKU_DEVICE_HOST\": \"192.168.1.XXX\",\n        \"ROKU_DEVICE_PASSWORD\": \"your-password\"\n      }\n    }\n  }\n}\n```\n\nReload the window. In Cascade settings, refresh the MCP server list.\n\n**Verify:** ask Cascade \"list available MCP tools\" — `roku_*` entries should appear.\n\n**Troubleshoot:** Windsurf occasionally caches a stale server. If reloads don't pick up edits, fully quit Windsurf and reopen.\n\n</details>\n\n<details>\n<summary><strong>Any MCP-compatible client</strong> (Continue, Cline, Zed, Codex, Claude Code, OpenCode, …)</summary>\n\nThe server speaks the standard MCP **stdio** transport. Anywhere you can declare:\n\n```\ncommand: npx\nargs:    [\"-y\", \"roku-mcp\"]\nenv:     { ROKU_DEVICE_HOST: \"...\", ROKU_DEVICE_PASSWORD: \"...\" }\n```\n\n…the server runs. Both env vars are optional: omit `ROKU_DEVICE_HOST` to use SSDP auto-discovery on the LAN, and pass `host` / `password` on each tool call to override.\n\nThe repo-root [`AGENTS.md`](./AGENTS.md) is picked up automatically by Claude Code, OpenCode, Codex CLI, and any other tool that follows the AGENTS.md convention, so those agents inherit the same usage guidance without extra setup.\n\n</details>\n\n## Agent rules\n\nFor better agent behavior (the `observe → act → wait → verify` loop, the RTA `uiElementId` gotcha that silently breaks `roku_edit_node`, when to use which tool), the repo ships drop-in rules pre-formatted for each major agent. The body is identical — only the wrapper differs to match what each agent auto-loads.\n\n| Agent | File | Install path |\n|---|---|---|\n| Cursor | [`rules/cursor/roku-mcp.mdc`](./rules/cursor/roku-mcp.mdc) | `.cursor/rules/roku-mcp.mdc` |\n| Claude Code | [`rules/claude-code/CLAUDE.md`](./rules/claude-code/CLAUDE.md) | `CLAUDE.md` (repo root) |\n| Claude Desktop | [`rules/claude-desktop/roku-mcp.md`](./rules/claude-desktop/roku-mcp.md) | Settings → System Prompt |\n| Windsurf | [`rules/windsurf/roku-mcp.md`](./rules/windsurf/roku-mcp.md) | `.windsurf/rules/roku-mcp.md` |\n| Codex CLI / OpenCode / Aider | [`AGENTS.md`](./AGENTS.md) (repo root) | `AGENTS.md` (repo root) |\n\nSee [`rules/README.md`](./rules/README.md) for one-line copy commands per agent.\n\n## Quickstart\n\nOnce your client is wired up, these three prompts work out of the box and exercise the main capability groups.\n\n**1. Confirm the device is reachable**\n\n```\nUse roku-mcp to query my Roku device info and tell me the model, firmware, and IP.\n```\n\nThe agent should call `roku_query_device_info` (and possibly `roku_discover` if no host is configured) and reply in one turn.\n\n**2. Drive the UI with screenshots**\n\n```\nPress Home, wait 2 seconds, take a screenshot, then move Right twice and\nscreenshot again. Describe what changed between the two screenshots.\n```\n\nThis exercises `roku_keypress`, `roku_sleep`, and `roku_screenshot` — the standard *observe → act → wait → verify* loop.\n\n**3. Live-edit a running channel (requires RTA — see [Runtime UI Editing](#runtime-ui-editing))**\n\n```\nOn the currently running dev channel, find the label that shows the page\ntitle, change its text to \"Hello from MCP\", verify the change with\nroku_get_value, then change it back.\n```\n\nThe agent will `roku_query_app_ui` to locate the node, grab the `uiElementId`, call `roku_edit_node` + `roku_get_value`, and roll back — proving end-to-end RTA wiring.\n\n## Environment Variables\n\n| Variable | Description |\n|---|---|\n| `ROKU_DEVICE_HOST` | IP address or hostname of the Roku device |\n| `ROKU_DEVICE_PASSWORD` | Developer password for the Roku device |\n\nBoth can also be passed as parameters on each tool call, which override the environment variables.\n\n### Auto-discovery\n\nIf `ROKU_DEVICE_HOST` is not set and no `host` parameter is provided, the server automatically discovers Roku devices on the local network using SSDP and uses the first one found. You can also use the `roku_discover` tool to list all available devices. Note that the password cannot be discovered and must still be configured.\n\n### `.env` file support\n\nThe server automatically loads a `.env` file from the current working directory using [dotenv](https://www.npmjs.com/package/dotenv). If your project's `.env` already uses `ROKU_DEVICE_HOST` and `ROKU_DEVICE_PASSWORD`, the server picks them up with no extra configuration — just omit the `env` block from your MCP config:\n\n```\nROKU_DEVICE_HOST=192.168.1.100\nROKU_DEVICE_PASSWORD=my-password\n```\n\nIf your project uses different variable names (e.g. `ROKU_IP`, `ROKU_DEV_PASSWORD`), you can map them in the `env` block:\n\n```json\n\"env\": {\n  \"ROKU_DEVICE_HOST\": \"${ROKU_IP}\",\n  \"ROKU_DEVICE_PASSWORD\": \"${ROKU_DEV_PASSWORD}\"\n}\n```\n\nOr simply add the two expected variables to your `.env` alongside your existing ones.\n\n## Available Tools\n\n### Deploy\n\n| Tool | Description |\n|---|---|\n| `roku_deploy` | Sideload (deploy) a Roku app to the device |\n| `roku_delete_dev_channel` | Delete the currently sideloaded developer channel |\n\n### Discovery\n\n| Tool | Description |\n|---|---|\n| `roku_discover` | Scan the local network for Roku devices via SSDP |\n\n### ECP (External Control Protocol)\n\n| Tool | Description |\n|---|---|\n| `roku_keypress` | Send a single key press (Home, Select, Up, Down, Left, Right, Back, etc.) |\n| `roku_keypress_sequence` | Send multiple key presses in sequence with configurable delay |\n| `roku_type_text` | Type a text string into the focused field (e.g. email, password, search) |\n| `roku_launch` | Launch or deep-link into a channel |\n| `roku_query_device_info` | Get device model, firmware, serial number, network info |\n| `roku_query_active_app` | Get the currently running app |\n| `roku_query_media_player` | Get media player state (play/pause/buffer/stop), position, and duration |\n| `roku_query_app_ui` | Get the current app UI tree as XML |\n| `roku_query_sg_nodes` | Query SceneGraph nodes (all, roots, or by node ID) |\n| `roku_find_node` | Search the UI tree for a node by ID or attribute (subtype, text, etc.) |\n| `roku_get_focused_node` | Get the currently focused node with all its properties |\n| `roku_sleep` | Wait for a specified duration (useful between navigation steps) |\n\n### Screenshot\n\n| Tool | Description |\n|---|---|\n| `roku_screenshot` | Capture a screenshot (returns base64 image and file path) |\n\n### Debug Console\n\n| Tool | Description |\n|---|---|\n| `roku_console_connect` | Open a TCP connection to the BrightScript debug console (port 8085) |\n| `roku_console_read` | Read buffered console output and auto-disconnect |\n| `roku_console_send` | Send a command to the debug console and auto-disconnect |\n| `roku_console_disconnect` | Close the console connection (safety net) |\n\n### Runtime UI Editing\n\nEdit the SceneGraph UI of a running sideloaded dev channel without redeploying — the same backend the SceneGraph Inspector in the [vscode-brightscript-language](https://github.com/rokucommunity/vscode-brightscript-language) extension uses. These tools speak the [roku-test-automation](https://github.com/triwav/roku-test-automation) (RTA) protocol against the channel's **On-Device Component** on TCP port 9000, so changes apply instantly with no debugger pause.\n\n| Tool | Description |\n|---|---|\n| `roku_edit_node` | Set one or more fields on a node by id (visible, translation, text, color, opacity, etc.) |\n| `roku_set_node_visible` | Show or hide a node by id |\n| `roku_move_node` | Move a node to `[x, y]` |\n| `roku_focus_node` | Set focus on a node by id (RTA `focusNode`) |\n| `roku_remove_node` | Detach a node from its parent at runtime (RTA `removeNode`) |\n| `roku_create_node` | Create a new node and append it to a parent by id (RTA `createChild`) |\n| `roku_get_value` | Read a field value (or full `keyPath`) from the running scene (RTA `getValue`) |\n| `roku_observe_field` | Wait for a field to change or match a value (RTA `onFieldChangeOnce`) — great for \"wait until X\" assertions |\n\n**How it works.** Each tool opens a short-lived TCP connection to the RTA On-Device Component (port 9000) in the running channel, sends a length-prefixed JSON request (`setValue` / `getValue` / `focusNode` / ...) and parses the framed JSON response. Mutations apply on the SceneGraph thread without breaking into the debugger.\n\n**Node addressing.** `nodeId` accepts either:\n- A `uiElementId` like `RTA_1773` (visible in the `roku_query_sg_nodes` / `roku_query_app_ui` output for every node when RTA is running). This is the most robust target.\n- A real BrightScript `id` attribute defined on the node in the channel source.\n\nAnything matching `/^RTA_\\d+$/` is sent with RTA `base: \"elementId\"`; otherwise it's sent with `base: \"scene\"`.\n\n#### Required: install the RTA On-Device Component in your channel\n\nThese tools only work when the channel under test bundles RTA. You have two options:\n\n**Option A — let `roku-debug` inject RTA on every sideload (recommended for VS Code users).**\n\n1. In your `launch.json`, enable:\n\n    ```json\n    \"injectRdbOnDeviceComponent\": true\n    ```\n\n2. In `source/main.brs`, add the marker comment immediately after `screen.show()`:\n\n    ```brightscript\n    sub main()\n        screen = createObject(\"roSGScreen\")\n        ' ...\n        screen.show()\n        ' vscode_rdb_on_device_component_entry\n        ' ...\n    end sub\n    ```\n\n**Option B — bundle the RTA component yourself.** Copy the `device/components` folder from [roku-test-automation](https://github.com/triwav/roku-test-automation) into your channel and instantiate `RTA_OnDeviceComponent` once from your scene.\n\nEither way, on a successful install you will see this in the device log at channel launch:\n\n```\n[RTA][INFO] OnDeviceComponent init\n```\n\nIf a runtime UI tool returns a connection-refused error, RTA is not present in the running channel — apply one of the two install options above and redeploy.\n\n### BrightScript Profiler\n\nAnalyze `.bsprof` files generated by Roku devices. These tools use [bsprof-cli](https://www.npmjs.com/package/bsprof-cli) to parse the binary profiler format and return structured JSON reports.\n\n| Tool | Description |\n|---|---|\n| `analyze_bsprof` | Analyze a .bsprof file — memory leaks, CPU hot paths, full report, or summary. Supports filtering by module/file and sorting options. |\n| `compare_bsprof` | Compare two .bsprof profiles to detect regressions, improvements, new leaks, and resolved leaks. |\n| `bsprof_info` | Get header metadata (target name, device, firmware, format version, features) without full parsing. |\n\nTo generate a `.bsprof` file, enable the profiler in your Roku app's `manifest` (`bs_prof_enabled=true`), run the app, and download the profile from `http://<device-ip>:8080`.\n\n### Perfetto Tracing\n\nRecord, analyze, and compare Perfetto traces from Roku devices. Requires **Roku OS 15.1+**. These tools use [roku-perfetto](https://www.npmjs.com/package/roku-perfetto) for ECP control, WebSocket recording, and PerfettoSQL analysis.\n\n| Tool | Description |\n|---|---|\n| `roku_perfetto_enable` | Enable Perfetto tracing for a channel via ECP (tracing starts on next app launch) |\n| `roku_perfetto_start` | Start recording a Perfetto trace via WebSocket binary stream |\n| `roku_perfetto_stop` | Stop recording and return file path, size, and duration |\n| `analyze_perfetto` | Analyze a .trace file — summary, frame-drops, key-events, observers, rendezvous, set-fields, or threads. Returns AI-friendly structured JSON with suggestions. |\n| `compare_perfetto` | Compare two .trace files to detect performance regressions and improvements |\n| `query_perfetto` | Run a raw PerfettoSQL query against a trace file for custom analysis |\n\nWorkflow: enable tracing → start recording → interact with app → stop recording → analyze. The `.trace` files can also be opened at [ui.perfetto.dev](https://ui.perfetto.dev/).\n\n### Stream Diagnosis\n\nFigure out why an HLS/DASH stream that plays everywhere else fails on Roku.\n\n| Tool | Description |\n|---|---|\n| `roku_diagnose_stream` | Correlate the Video-node `errorInfo`, the manifest (a fetchable `url` or pasted `content`), and an optional Charles/HAR capture into ranked Roku-specific root causes (cause, evidence, confidence, severity, fix, doc link). Optionally `captureLive=true` deploys the bundled StreamProbe harness to capture the device error first. |\n\nIt detects Roku-specific gotchas such as muxed audio+video in fMP4/CMAF HLS (plays video but silent), video codecs/levels beyond the hardware decoder (e.g. 4K H.264 or 8K HEVC), token/403-gated CDNs, and DRM license rejections. The static manifest checks are treated as hints; when you supply the real device `errorInfo` the diagnosis is corroborated to high confidence.\n\n## Requirements\n\n- Node.js 18+\n- A Roku device with [Developer Mode](https://developer.roku.com/docs/developer-program/getting-started/developer-setup.md) enabled on the same network\n- For screenshots and deploy: a sideloaded dev channel must be running\n\n## License\n\nMIT\n",
  "bytes": 17453,
  "sha": "800d89faed61e091db7fa54406e3a048d1c2066faa188141f9a589fdb2585eef",
  "repo_slug": "jack1590/rokumcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_jack1590_rokumcp_84950ae8/readme"
}