内容
# switchMCP
通过MCP驱动自制任天堂Switch AI代理。
`[仅限Atmosphère]` `[已在HOS 22.1.0上测试]` `[emuMMC和sysMMC]`
两个部分:
- **`agent/`** — `switch-agentd`,一个C++系统模块,在主机后台运行,并通过TCP 6060端口公开控制协议。
- **`server/`** — 一个Python MCP服务器,在计算机上运行,将该协议转换为LLM可以调用的工具。
```
Claude ── MCP/stdio ── server/ (Python) ── TCP 6060 (Wi-Fi) ── agent/ (系统模块)
```
全新安装是只读的:代理以`observe`层级启动,在您故意提升之前,无法更改主机上的任何内容。
---
## 功能
### 眼睛和手
- 屏幕捕获,默认缩放至原生JPEG大小的约20% — 同一个菜单在四分之一的标记下可读
- `screen_changed`,等待UI稳定并仅在发生实际更改时返回**一张**图像
- 控制器和触摸输入,宏序列,虚拟USB键盘
- 读取**物理**控制器,并将真实输入记录到可回放的宏中
### 文件和存档
- 浏览、传输、哈希和搜索SD卡 — `find`和`grep`在**主机上**运行,因此您不会通过Wi-Fi传输目录树进行筛选
- 枚举系统上的**所有**存档(游戏、系统、BCAT、设备、缓存),无需事先知道标题ID
- 以**只读**方式挂载任意存档并原地读取
### 诊断
- 一次性故障排除:系统信息、正在运行的应用程序、崩溃报告、截图
- Atmosphère崩溃**和**致命报告
- 进程列表、模块列表(带有构建ID)、网络配置
- `preflight` — 电池、充电器、可用空间、emuMMC vs sysMMC — 在进行任何不可逆操作之前
### 调试和内存
- 附加调试器:内存映射、线程、寄存器、回溯
- 模块基址 + 构建ID,以便在Ghidra/IDA中将地址转换为`main+0x1a2f4`
- 通过`dmnt:cht`读写正在运行的**未暂停**游戏的内存
- 使用候选值在主机上进行值搜索的缩小(`find_value` → `narrow_search`),每个步骤只需一次往返
### 安全
- 三个能力层级,在任何处理程序运行之前强制执行
- 每个变异命令的`dry_run`
- 破坏性工具需要一个与确切效果绑定的两调用确认令牌
- 设备上的审计日志和一个计算无客户端启动次数的看门狗
完整工具参考:**[工具](https://github.com/AboveColin/switchMCP/wiki/Tools)**。有效配方:**[示例](https://github.com/AboveColin/switchMCP/wiki/Examples)**。
---
## 已知限制
在提交问题之前请阅读这些 - 所有这些都是已文档化的行为。
- **硬件观察点和断点被禁用但永远不会触发。** 系统调用被允许,控制字编码被接受,槽位分配和清除 — 但在HOS 22.1.0上永远不会传递异常。核心亲和力被测试并排除。使用缩小内存搜索代替;它有效。
- **USB传输无效。** 设备端编译并默认关闭。没有主机客户端,它从未针对硬件进行测试。
- **一次一个客户端** — 不是一个命令,而是一个**会话**。代理在客户端保持连接时不会再次到达`accept()`,因此第二个客户端在第一个客户端断开连接之前被阻止。长时间的`wait_event`阻止所有操作。
- **寄存器写入需要调试事件时停止的线程。** 暂停附件不足;内核返回`InvalidState`。这是正常的调试器合同,不是错误。
- **吞吐量受Wi-Fi限制,而不是协议**:测量的2.8 MB/s上行,4.1 MB/s下行,22.8毫秒往返。
- 家酿软件无法通过标题ID启动。`launch_title`拒绝hbloader ID,因为这样会产生一个进程,渲染无内容,然后阻塞实际启动路径。
---
## 安装
1. 下载最新的发行版zip文件。
2. 将其提取到**SD卡的根目录**,让文件夹合并:
```
atmosphere/contents/420000000000AE57/exefs.nsp
atmosphere/contents/420000000000AE57/flags/boot2.flag <- 空;使其自动启动
atmosphere/contents/420000000000AE57/toolbox.json
config/switch-agentd/config.ini.example
```
3. 重启主机。
首次启动时,代理会在`sd:/config/switch-agentd/config.ini`中写入一个**随机生成的令牌**。读取该文件以获取令牌 — 您需要它来连接。它从不通过网络传输:客户端通过回答HMAC挑战来证明其了解令牌。
**成功检查:** `sd:/config/switch-agentd/agent.log`应以`listening on port 6060`结尾。完全没有日志意味着模块未启动 — 请参见[故障排除](https://github.com/AboveColin/switchMCP/wiki/Troubleshooting)。
### 连接代理
```bash
cd server && uv sync
claude mcp add switch \
-e SWITCH_HOST=<主机IP> -e SWITCH_TOKEN=<config.ini中的令牌> \
-- uv --directory $(pwd) run switch-mcp
```
`SWITCH_MCP_TOOLS`选择注册哪些工具组:未设置给出69个工具,`all`给出102个,`core`给出15个。请参见**[配置](https://github.com/AboveColin/switchMCP/wiki/Configuration)**。
---
## 配置
`sd:/config/switch-agentd/config.ini`。重要设置:
```ini
# observe - 只读。无法更改任何内容。(默认)
# control - 控制台持有者可以执行的操作:输入、启动应用程序、
# SD卡文件、重启。 这里没有任何内容会损坏固件。
# invasive - NAND/BIS写入、原始i2c、实时内存修补、卸载。
tier = observe
```
达到`invasive`是必要的,但对于最锋利的边缘来说是不够的:`allow_nand_write`、`allow_overclock`和`allow_hardware`是单独的选择。
emuMMC自动检测并在握手过程中报告。在emuMMC上,错误可以通过恢复SD镜像来恢复;在sysMMC上,可能不会。
---
## 删除
删除这些并重启:
```
sd:/atmosphere/contents/420000000000AE57/
sd:/config/switch-agentd/
sd:/switch-agentd/ (保存备份和日志 — 安全保留)
```
如果一个糟糕的构建阻止主机启动,请在启动时按住**音量上**以跳过boot2系统模块,然后删除内容文件夹。
---
## 构建
需要带有`switch-dev`的[devkitPro](https://devkitpro.org/wiki/Getting_Started)。
```bash
sudo dkp-pacman -S switch-dev
make -C agent # 构建switch-agentd.nsp
make -C agent dist # 汇总SD卡发行版zip
make -C agent host-tests # JSON编码器和路径策略的单元测试;
# 原生运行 — 无需devkitPro或主机
cd server && uv sync --extra dev && uv run pytest
```
主机测试构建`json.cpp`和`path.cpp`,在ASan/UBSan下。它们涵盖了每个请求都经过的代码,包括阻止目录遍历的路径策略 — 在进行交叉构建之前运行是值得的。
---
## 关于稳定性的说明
这在开发过程中软性砖了主机三次。所有三次都是可以恢复的,并且都已修复。它们值得记录,因为故障模式推广到任何系统模块:
- **32 KiB栈上的64 KiB栈缓冲区。** GCC在序言中保留帧,因此模块在进入函数之前死亡,之前没有任何代码运行。
- **使用`psc`注册但未回答。** 电源状态模块如果未能确认睡眠请求,则会挂起主机 — 黑屏,无崩溃报告。
- **将`INNER_HEAP_SIZE`提高到16 MiB。** 系统模块的堆来自受限系统池;在初始化期间分配失败,模块在能够记录任何内容之前死亡。现在有一个`static_assert`来对抗它。
最后两个产生**没有日志和崩溃报告**,这就是为什么存在启动看门狗和设备日志。
---
## 免责声明
这是一个用于管理您自己的主机和开发家酿软件的工具。运行自定义固件并连接到任天堂的在线服务存在非零的封禁风险,本项目不尝试隐藏自己。作者对任何损害、数据丢失或接收到的封禁不承担责任。**请自行承担风险。**
安装标题不在此范围内且未实现。
---
## 鸣谢
基于[libnx](https://github.com/switchbrew/libnx)和
[Atmosphère](https://github.com/Atmosphere-NX/Atmosphere)。感谢switchbrew、devkitPro、SciresM和ReSwitched社区 — 这里的协议工作大量借鉴了他们的文档。
根据[GPLv3](LICENSE)许可。