返回市场
风景_mcp_实验版

风景_mcp_实验版

作者:scenic-contrib6 星标更新:2025-11-06

项目介绍

Scenic MCP

适用于Scenic GUI应用程序的模型上下文协议(MCP)服务器

版本:1.0.0

使AI助手能够通过键盘输入、鼠标控制和视觉反馈与Scenic GUI应用程序进行交互。非常适合自动化测试、AI驱动的开发工作流程以及辅助工具。

功能

  • 🎹 键盘输入 - 发送文本和特殊键,支持修饰符(Ctrl, Shift, Alt, Cmd)
  • 🖱️ 鼠标控制 - 移动光标并在特定坐标点击
  • 🎯 语义交互 - 使用语义标记点击特定组件,而不仅仅是原始坐标
  • 📸 视觉反馈 - 检查视口结构并捕获屏幕截图
  • 🤖 MCP集成 - 与Claude Desktop、Claude Code和其他MCP客户端兼容

快速开始

1. 在您的Scenic应用的mix.exs中添加

请注意,这尚未发布到hex,因此您需要克隆它并将其作为本地依赖项添加。

defp deps do
  [
    {:scenic_mcp, "../scenic_mcp"}
  ]
end

2. 配置您的视口和驱动程序

Scenic MCP需要命名的视口和驱动程序进程。更新您的监督树:

# 在您的application.ex中
def start(_type, _args) do
  children = [
    {Scenic, scenic_viewport_config()}
  ]

  Supervisor.start_link(children, strategy: :one_for_one)
end

defp scenic_viewport_config do
  [
    name: :main_viewport,  # 必需!
    size: {800, 600},
    default_scene: MyApp.RootScene,
    drivers: [
      [
        name: :scenic_driver,  # 必需!
        module: Scenic.Driver.Local,
        window: [title: "我的应用"],
        on_close: :stop_system
      ]
    ]
  ]
end

请注意,这里的name定义了将成为视口和驱动程序进程注册名称的原子。我们需要知道这一点以便找到该进程的pid,从而与视口进行交互。我们的解决方案是查找这个特定名称main_viewport,因此您需要在配置中设置此名称以使ScenicMCP正常工作。

视口名称::main_viewport 驱动程序名称::scenic_driver

可选:自定义进程名称

如果您需要不同的进程名称,请进行配置:

# config/config.exs
config :scenic_mcp,
  viewport_name: :my_custom_viewport,
  driver_name: :my_custom_driver,
  port: 9999

3. 安装TypeScript依赖项

cd scenic_mcp
npm install
npm run build

4. 配置Claude Code或Claude Desktop

使用Claude Code CLI(推荐)

claude mcp add scenic-mcp /path/to/scenic_mcp/dist/index.js
claude mcp list  # 验证安装

手动配置

编辑~/.claude.json

{
  "projects": {
    "/path/to/your/project": {
      "mcpServers": {
        "scenic-mcp": {
          "type": "stdio",
          "command": "/path/to/scenic_mcp/dist/index.js",
          "args": [],
          "env": {}
        }
      }
    }
  }
}

可选:Tidewave MCP配置

Tidewave为Elixir/Phoenix应用提供运行时检查(日志、SQL查询、代码评估、文档)。如果您的项目包含Tidewave(Flamelex/Quillex),请将以下内容添加到同一项目配置中:

{
  "projects": {
    "/path/to/your/project": {
      "mcpServers": {
        "scenic-mcp": {
          "type": "stdio",
          "command": "/path/to/scenic_mcp/dist/index.js",
          "args": [],
          "env": {}
        },
        "tidewave": {
          "type": "http",
          "url": "http://localhost:4000/tidewave/mcp"
        }
      }
    }
  }
}

5. 启动您的Scenic应用

cd your_scenic_app
iex -S mix

您应该看到:

✅ ScenicMCP成功启动在端口9999上

使用方法

可用工具

连接与状态

  • connect_scenic - 建立与正在运行的Scenic应用的连接
  • get_scenic_status - 检查连接状态和服务器信息

用户输入

  • send_keys - 发送键盘输入(文本、特殊键、修饰符)
  • send_mouse_move - 将光标移动到坐标位置
  • send_mouse_click - 在坐标处点击(左/右/中间按钮)

视觉反馈

  • inspect_viewport - 获取视口结构的文本描述
  • take_screenshot - 捕获PNG屏幕截图(路径或base64)

示例

文本输入

send_keys({ text: "Hello, World!" })

特殊键

send_keys({ key: "enter" })
send_keys({ key: "escape" })
send_keys({ key: "tab" })

键盘快捷键

send_keys({ key: "s", modifiers: ["ctrl"] })      // Ctrl+S(保存)
send_keys({ key: "c", modifiers: ["cmd"] })       // Cmd+C(Mac上的复制)
send_keys({ key: "z", modifiers: ["ctrl", "shift"] })  // Ctrl+Shift+Z(重做)

鼠标控制

send_mouse_move({ x: 100, y: 200 })
send_mouse_click({ x: 150, y: 250, button: "left" })
send_mouse_click({ x: 300, y: 100, button: "right" })  // 右击

视觉检查

inspect_viewport()  // 获取组件结构

take_screenshot({ format: "path" })  // 保存到/tmp
take_screenshot({
  filename: "app_state.png",
  format: "base64"  // 获取base64数据
})

架构

AI代理(Claude Desktop/Code)
    ↓ stdio
TypeScript MCP服务器(此包)
    ↓ TCP(端口9999)
Elixir GenServer(ScenicMcp.Server)
    ↓ 函数调用
Scenic驱动程序进程
    ↓ 输入事件
您的Scenic应用

工作原理

  1. TypeScript MCP服务器通过stdio处理MCP协议
  2. TCP桥接器维持与Elixir的持久连接
  3. Elixir GenServer通过TCP接收JSON命令
  4. 工具处理器与Scenic视口和驱动程序交互
  5. 驱动程序将输入事件注入您的应用

配置

可用选项

# config/config.exs
config :scenic_mcp,
  # MCP服务器的TCP端口(默认:9999)
  port: 9999,

  # 视口进程名称(默认::main_viewport)
  viewport_name: :main_viewport,

  # 驱动程序进程名称(默认::scenic_driver)
  driver_name: :scenic_driver,

  # 日志的应用名称(默认:"未知")
  app_name: "我的应用"

多个Scenic应用

如果您正在运行多个Scenic应用,请配置独特的端口:

# 在flamelex/config/config.exs中
config :scenic_mcp, port: 9999, app_name: "Flamelex"

# 在quillex/config/config.exs中
config :scenic_mcp, port: 9997, app_name: "Quillex"

# 在your_test/config/test.exs中
config :scenic_mcp, port: 9996, app_name: "测试"

连接到特定端口:

connect_scenic({ port: 9997 })  // 连接到Quillex

开发

构建TypeScript

npm run build       # 一次性构建
npm run dev         # 开发模式下的监视模式

打包用于分发

npm run bundle      # 将dist/*复制到priv/mcp_server/

运行测试

# Elixir测试
mix test

# 测试特定文件
mix test test/scenic_mcp/server_test.exs

项目结构

scenic_mcp/
├── lib/
│   ├── scenic_mcp.ex           # 模块文档
│   └── scenic_mcp/
│       ├── application.ex      # OTP应用
│       ├── config.ex           # 配置管理
│       ├── server.ex           # TCP服务器(GenServer)
│       └── tools.ex            # 工具处理器
├── src/
│   ├── index.ts                # MCP服务器入口点
│   ├── connection.ts           # TCP连接管理
│   └── tools.ts                # 工具定义
├── test/
│   └── scenic_mcp/
│       └── server_test.exs     # 集成测试
└── dist/                       # 编译的TypeScript

故障排除

MCP服务器无法连接

错误: MCP服务器无法连接或工具在Claude Code/Desktop中不可用

解决方法: 编译的dist/index.js文件必须可执行。TypeScript编译不会保留可执行权限,即使源文件具有这些权限也是如此。

修复:

chmod +x /path/to/scenic_mcp/dist/index.js

自动修复: 构建脚本现在会自动使文件可执行。如果您在添加此修复之前进行了构建,则可以:

  1. 再次运行npm run build(推荐)
  2. 手动运行chmod +x dist/index.js

修复后,重新启动Claude Code或开始新的对话以使更改生效。

端口已被使用

错误: 端口9999已被使用!

解决方法: 在您的config.exs中配置不同的端口:

config :scenic_mcp, port: 9998

无法找到视口

错误: 无法找到Scenic视口进程':main_viewport'

解决方法:

  1. 确保您的视口命名为:name: :main_viewport在您的Scenic配置中
  2. 或者配置预期名称:config :scenic_mcp, viewport_name: :your_name
  3. 验证您的Scenic应用是否正在运行:Process.whereis(:main_viewport)

无法找到驱动程序

错误: 无法找到Scenic驱动程序进程':scenic_driver'

解决方法:

  1. 确保您的驱动程序命名为:name: :scenic_driver在您的驱动程序配置中
  2. 或者配置预期名称:config :scenic_mcp, driver_name: :your_name
  3. 检查驱动程序是否已启动:Process.whereis(:scenic_driver)

连接超时

错误: 命令超时5000ms

解决方法:

  1. 检查Scenic应用是否正在运行
  2. 验证正确的端口:connect_scenic({ port: YOUR_PORT })
  3. 检查防火墙设置(应允许localhost:9999)

测试失败

如果测试因连接错误而失败:

  1. 确保没有其他应用正在使用测试端口(9996-9998)
  2. 使用mix test --trace运行测试以获取详细输出
  3. 检查scenic_driver_local依赖项是否正确编译

安全注意事项

⚠️ 重要安全提示:

  • Scenic MCP仅绑定到localhost - 不对外部网络访问
  • 无身份验证 - 具有本地访问权限的任何人都可以控制您的应用
  • 仅适用于开发和测试环境
  • 不要将TCP端口(9999)暴露给不受信任的网络
  • 在生产环境中使用前请采取额外的安全措施

详见SECURITY.md中的详细安全指南。

集成指南

详见docs/INTEGRATION.md中的逐步集成说明,包括:

  • 将Scenic MCP添加到现有应用
  • 常见模式和最佳实践
  • 测试策略
  • 示例实现

API参考

错误处理

所有工具函数返回一致的错误结构:

{
  "error": "带有上下文和潜在解决方案的描述性错误消息"
}

成功响应包括一个status字段:

{
  "status": "ok",
  "message": "操作成功完成",
  ...附加数据...
}

贡献

欢迎贡献!请:

  1. 分叉仓库
  2. 创建功能分支
  3. 为新功能添加测试
  4. 确保mix test通过
  5. 提交拉取请求

要求

  • Elixir ~> 1.14
  • Erlang/OTP 24+
  • Node.js >= 18.0
  • Scenic ~> 0.11
  • Claude Desktop或Claude Code(用于MCP客户端)

许可证

MIT许可证 - 详情见LICENSE

相关项目

  • Scenic - 适用于Elixir的2D UI框架
  • MCP - 模型上下文协议规范
  • Tidewave - Elixir/Phoenix MCP工具

更新日志

详见CHANGELOG.md中的版本历史。

支持


为Elixir和Scenic社区制作,充满爱心