RokuHarness MCP服务器
用于全面Roku自动化测试的模型上下文协议(MCP)服务器。RokuHarness联合收割机 年 WebDriver 和 ECP(外部控制协议) 提供UI状态验证和设备控制,实现真正的验收标准验证,而不仅仅是远程控制模拟。
为什么选择WebDriver与ECP?
| 能力 | ECP | WebDriver |
|---|---|---|
| 按下遥控器按钮 | ✅ | ✅ |
| 启动应用程序 | ✅ | ✅ |
| 查询UI元素 | ❌ | ✅ |
| 验证文本是否显示在屏幕上 | ❌ | ✅ |
| 检查元素属性 | ❌ | ✅ |
| 获取场景图XML | ❌ | ✅ |
| 截图 | ❌ | ✅ |
| 验证验收标准 | ❌ | ✅ |
底线:ECP可以按下按钮,WebDriver可以验证发生了什么。
建筑
Your Tests (via any MCP client)
↓
RokuHarness MCP Server (this project)
↓ (WebDriver HTTP API)
Roku WebDriver Server (from Roku's repo)
↓ (ECP + Debug APIs)
Roku Device (your sideloaded channel)关键点:Roku WebDriver服务器使用ECP(用于控制)和Roku的调试API(用于UI验证)。此MCP服务器为这两种功能提供了统一的接口。
先决条件
1. WebDriver 服务器
您需要下载并运行Roku的官方WebDriver服务器:
# Clone Roku's automated testing repo
git clone https://github.com/rokudev/automated-channel-testing.git
cd automated-channel-testing
# Build the WebDriver server (requires Go)
cd src
go build
# Run the server
./RokuWebDriver # Linux/Mac
# or
RokuWebDriver.exe # Windows服务器将于启动 http://localhost:9000 默认情况下。
下载预构建的二进制文件:检查 automated-channel-testing/bin 用于预编译可执行文件的文件夹。
2.侧载通道
WebDriver要求您的通道在开发人员模式下进行侧向加载:
- 在Roku上启用开发人员模式:设置→ 系统→ 关于→ 按主页5次、向上、倒退2次、快进2次
- 将您的频道打包为
.zip文件 - 访问
http://YOUR_ROKU_IP在浏览器中 - 上传并安装您的频道
重要:WebDriver仅适用于:
- 侧载开发人员频道(应用程序ID:
dev) - 在特定设备上与您的开发人员帐户打包的频道
- 基于SceneGraph的通道(不是传统的BrightScript)
3.此MCP服务器
npm install
npm run build安装和设置
1.构建此MCP服务器
npm install
npm run build2.配置您的MCP客户端
对于Claude Desktop:
增添 claude_desktop_config.json:
{
"mcpServers": {
"rokuharness": {
"command": "node",
"args": ["/absolute/path/to/rokuharness-mcp/build/index.js"]
}
}
}对于自定义MCP客户端:
RokuHarness与MCP无关,可与任何MCP客户端配合使用。有关集成示例,请参阅下面的“在没有Claude Desktop的情况下使用”部分。
3.启动Roku WebDriver服务器
在单独的终端中:
cd /path/to/automated-channel-testing/bin
./RokuWebDriver # or RokuWebDriver.exe on Windows测试时保持此运行状态。
4.重新启动克劳德桌面
MCP服务器现在将在Claude中可用。
使用指南
步骤1:创建会话
每个测试会话都从创建WebDriver会话开始:
Create a Roku WebDriver session:
- WebDriver URL: http://localhost:9000
- Roku IP: 192.168.1.100
- App: dev这将连接到您的旁瓣信道。
步骤2:获取UI源代码(关键!)
在编写任何验证查询之前,请检查UI:
Get the UI source to see what elements are on screen您将返回SceneGraph XML,如下所示:
此XML显示:
- 标签:组件类型(标签、按钮、海报等)
- 属性:属性如
id,text,focused,visible - 层级:嵌套结构
步骤3:验证元素
现在,您可以编写验收标准测试:
Verify that a Label with text "Welcome to My App" is present on screenVerify that a Button with id "loginButton" and focused=true is presentVerify that the login button text says "Log In"步骤4:导航和测试
Navigate using these keys: ["Down", "Down", "Select"]
Then verify that a Label with text "Account Settings" appears步骤5:运行完整的测试场景
Run this acceptance test:
Test: Login Flow
Steps:
1. Press Select to click login button
2. Verify keyboard screen appears (look for Label with text "Enter Email")
3. Send text "test@example.com"
4. Press Down to go to password field
5. Send text "password123"
6. Press Select to submit
7. Verify success message appears
8. Take screenshot可用工具
会话管理
create_webdriver_session
创建新的WebDriver会话。
参数:
webdriver_url(可选):WebDriver服务器的URL(默认值:http://localhost:9000)roku_ip(必填):Roku设备的IP地址app(可选):应用程序ID或“dev”表示侧面加载(默认值:“dev“)
例子:
Create a WebDriver session for Roku at 192.168.1.100end_webdriver_session
结束当前会话并进行清理。
______________________________________________________________________
UI状态验证(关键功能!)
get_ui_source
以XML或JSON格式获取当前UI层次结构。
参数:
parsed(可选):返回JSON而不是XML
例子:
Get the UI source to see current screen structure退货:
这是 必要的 了解存在哪些元素以及如何查询它们。
find_element
在屏幕上搜索特定元素。
参数:
text(可选):要匹配的文本内容tag(可选):SceneGraph组件类型attributes(可选):属性键值对
示例:
Find a Label with text "Home Screen"Find a Button with id "playButton"Find an element with tag "Poster" and attribute uri="https://example.com/image.jpg"verify_element_present
检查元素是否存在(返回true/false)。
参数:
- 同
find_element timeout_ms(可选):等待多长时间(默认值:10000)
示例:
Verify a Label with text "Loading..." is presentCheck if login button is focused: Button with focused=trueverify_screen_loaded
等待特定屏幕完全加载。
参数:
screen_marker:标识屏幕的元素查询timeout_ms(可选):最长等待时间
例子:
Verify the home screen loaded by checking for Label with text "Featured Content"______________________________________________________________________
导航和输入
press_key
按下一个遥控器按钮。
参数:
key:按钮名称(主页、后退、向上、向下、向左、向右、选择、播放、暂停等)
navigate
执行一系列按钮按下。
参数:
keys:要按的按键阵列delay_ms(可选):按下之间的延迟
例子:
Navigate: Down, Down, Right, Select with 750ms delayssend_text
发送文本输入(用于键盘/表单)。
参数:
text:要键入的文本
______________________________________________________________________
媒体和应用程序
launch_app
启动一个带有可选深度链接的应用程序。
参数:
app_id:应用程序ID(“dev”表示侧面加载)content_id(可选):深度链接内容IDmedia_type(可选):类型(电影、连续剧等)
get_player_state
获取当前播放状态。
退货: 位置、持续时间、状态、缓冲信息
get_installed_apps
列出所有已安装的应用程序。
______________________________________________________________________
截图
take_screenshot
捕获当前屏幕。
参数:
save_path(可选):保存图像的位置
例子:
Take a screenshot and save to /tmp/login_screen.png______________________________________________________________________
验收测试
run_acceptance_test
执行一个包含多个步骤的完整测试用例。
参数:
test_name:测试名称steps:一系列测试步骤
步骤类型:
navigate:执行按键序列verify_element:检查元件是否存在press_key:按单键send_text:键入文本wait:暂停一段时间screenshot:捕获屏幕
例子:
Run this acceptance test:
Name: "Video Playback Test"
Steps:
1. Action: navigate, Keys: ["Down", "Down", "Select"], Description: "Select first video"
2. Action: verify_element, Query: {tag: "Video", attributes: {state: "playing"}}, Description: "Verify video is playing"
3. Action: wait, Duration: 5000, Description: "Let video play for 5 seconds"
4. Action: press_key, Key: "Pause", Description: "Pause playback"
5. Action: verify_element, Query: {tag: "Video", attributes: {state: "paused"}}, Description: "Verify video paused"
6. Action: screenshot, Description: "Capture paused state"______________________________________________________________________
元素查询语法
使用以下组合查询元素:
由文本的
{ "text": "Log In" }查找包含此确切文本的元素。
按标签
{ "tag": "Button" }查找此SceneGraph类型的元素。
常见标签:
Label-文本显示Button-交互按钮Poster-图片Video-视频播放器LayoutGroup-集装箱RowList-可滚动列表Grid-网格布局
按属性
{
"attributes": {
"id": "loginButton",
"focused": "true"
}
}常见属性:
id-唯一标识符focused-有焦点(真/假)visible-可见(真/假)text-文本内容uri-图像/视频URI
组合查询
{
"tag": "Button",
"text": "Log In",
"attributes": {
"focused": "true"
}
}查找当前具有焦点的文本为“登录”的按钮。
______________________________________________________________________
真实世界的例子
示例1:验证登录屏幕
1. Create WebDriver session for Roku at 192.168.1.100
2. Get UI source to inspect elements
3. Verify these elements are present:
- Label with text "Sign In"
- Button with text "Email Login"
- Button with text "Guest Mode"
4. Take screenshot for documentation示例2:测试视频播放
Run this acceptance test:
Name: "Video Playback Verification"
Steps:
1. Navigate to content: ["Down", "Down", "Select"]
2. Verify video player loaded: tag=Video
3. Wait 3 seconds for playback to start
4. Verify video is playing: tag=Video, attributes={state: "playing"}
5. Press "Info" to show controls
6. Verify play/pause button visible: tag=Button, text="Pause"
7. Take screenshot of player controls示例3:搜索功能
Test search feature:
1. Press "Search" key
2. Verify keyboard screen: Label with text "Search"
3. Send text "Breaking Bad"
4. Press "Select" to submit
5. Verify results loaded: Label with text "Results for: Breaking Bad"
6. Verify at least one result: tag=Poster (poster images indicate results)示例4:设置导航
Navigate to settings and verify:
1. Press Home
2. Navigate: ["Down", "Down", "Down", "Right", "Right", "Select"]
3. Verify settings screen: Label with text "Settings"
4. Navigate: ["Down", "Select"]
5. Verify account screen: Label with text "Account Information"
6. Get UI source to document screen structure______________________________________________________________________
故障排除
“没有活动会话”
你必须打电话 create_webdriver_session 在任何其他命令之前。
“WebDriver服务器没有响应”
确保Roku WebDriver服务器正在运行:
./RokuWebDriver“找不到元素”
- 首先获取UI源代码:
get_ui_source - 检查实际的XML结构
- 调整查询以匹配实际元素
- 检查拼写和大小写(XML区分大小写)
“无法从通道获取源”
- 仅适用于侧载信道或该设备上封装的信道
- 生产渠道阻止源访问(安全功能)
- 确保您的频道正在运行(不在主屏幕上)
截图不起作用
屏幕截图仅在以下情况下有效:
- 您的侧载信道处于活动状态
- 开发人员模式已启用
- WebDriver具有适当的访问权限
查询速度慢
- WebDriver查询可能需要500ms-2s,具体取决于复杂性
- 使用特定查询(标签+属性)以获得更快的结果
- 避免过于宽泛的询问
______________________________________________________________________
Roku WebDriver限制
- 仅限侧载频道 -生产渠道阻碍UI反思
- 仅限SceneGraph -不支持传统BrightScript通道
- 无视觉比较 -您得到的是XML结构,而不是渲染像素
- 元素边界是相对的 -绝对位置检查很复杂
- 无直接元素交互 -您仍然使用D-pad导航,而不是点击
______________________________________________________________________
最佳实践
1.始终先检查
Get UI source → Understand structure → Write queries2.使用特定查询
❌ { "text": "Play" } // Might match multiple elements
✅ { "tag": "Button", "id": "mainPlayButton", "text": "Play" }3.等待屏幕加载
verify_screen_loaded with appropriate timeout4.一次测试一件事
将复杂的流程分解为单独的测试用例。
5.拍摄屏幕截图
记录关键步骤前后的状态。
6.使用验收测试工具
对于多步骤场景,请使用 run_acceptance_test 以获得结构化的结果。
______________________________________________________________________
与CI/CD集成
此MCP服务器可以集成到CI/CD管道中:
- 在您的测试实验室中配置Roku设备
- 在每个服务器上启动WebDriver服务器
- 通过MCP服务器运行测试
- 收集结果和截图
- 发布测试报告
______________________________________________________________________
使用无Claude桌面
RokuHarness基于开放式MCP标准构建,与 任何MCP客户端以下是集成示例:
Python CI/CD集成
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
# Connect to RokuHarness MCP server
server_params = StdioServerParameters(
command="node",
args=["/path/to/rokuharness-mcp/build/index.js"]
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# Create WebDriver session
result = await session.call_tool(
"create_webdriver_session",
arguments={
"roku_ip": "192.168.1.100",
"app": "dev"
}
)
# Get UI source
ui_source = await session.call_tool("get_ui_source", {})
# Verify element
verify_result = await session.call_tool(
"verify_element_present",
arguments={
"text": "Welcome",
"tag": "Label"
}
)
# Assert in your test framework
assert verify_result["present"] == True
# Run acceptance test
test_result = await session.call_tool(
"run_acceptance_test",
arguments={
"test_name": "Login Flow",
"steps": [
{
"action": "navigate",
"description": "Go to login",
"keys": ["Down", "Down", "Select"]
},
{
"action": "verify_element",
"description": "Check login screen",
"element_query": {"text": "Sign In"}
}
]
}
)
print(f"Test Status: {test_result['summary']['status']}")Node.js集成
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
const transport = new StdioClientTransport({
command: 'node',
args: ['/path/to/rokuharness-mcp/build/index.js']
});
const client = new Client({
name: 'roku-test-runner',
version: '1.0.0'
}, {
capabilities: {}
});
await client.connect(transport);
// Create session
const session = await client.request({
method: 'tools/call',
params: {
name: 'create_webdriver_session',
arguments: {
roku_ip: '192.168.1.100',
app: 'dev'
}
}
});
// Verify element
const result = await client.request({
method: 'tools/call',
params: {
name: 'verify_element_present',
arguments: {
tag: 'Button',
text: 'Play'
}
}
});
console.log('Element present:', result.present);集成点
✅ CI/CD管道 -Jenkins、GitHub Actions、GitLab CI、CircleCI\ ✅ 测试框架 - 是, Mocha, Pytest, JUnit\ ✅ QA平台 -TestRail、Zephyr、qTest、X射线\ ✅ 自定义仪表板 -构建自己的测试运行器UI\ ✅ 预定测试 -Cron作业、AWS Lambda、Azure功能\ ✅ 任何与MCP兼容的工具 -协议完全开放
GitHub操作工作流示例
name: Roku UI Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '20'
- name: Install dependencies
run: |
cd rokuharness-mcp
npm install
npm run build
- name: Start Roku WebDriver Server
run: |
wget https://github.com/rokudev/automated-channel-testing/releases/download/v1.0/RokuWebDriver
chmod +x RokuWebDriver
./RokuWebDriver &
- name: Run tests
run: python tests/run_roku_tests.py
env:
ROKU_IP: ${{ secrets.ROKU_IP }}
- name: Upload screenshots
if: always()
uses: actions/upload-artifact@v3
with:
name: test-screenshots
path: screenshots/______________________________________________________________________
与其他工具的比较
vs Roku机器人框架
- 这:通过Claude的自然语言,MCP协议
- 机器人:关键字驱动的单独测试文件
vs Appium Roku驱动程序
- 这:直接访问WebDriver,设置更简单
- Appium:Appium生态系统集成,更多工具
vs手动测试
- 这:自动化、可重复、快速
- 手册:全面但缓慢、昂贵
______________________________________________________________________
资源
______________________________________________________________________
支持
对于问题或疑问:
______________________________________________________________________
许可证
MIT许可证-免费用于您的Roku测试需求。
