wsl-round-mcp — 本机 ⇄ WSL OpenCode 互通工具
打通本机 OpenCode 与 WSL 里的 OpenCode:skill 列表互查、skill 一键推送、MCP 配置对调开关。 全部零第三方依赖,只要装了 Python 3 就能跑。
一、双击就能用(小白版)
把整个 wsl-round-mcp 文件夹拷到任意位置,双击 oc.bat —— 只有这一个入口,
启动打印数字菜单,输编号或中文都能进:
============================================
OC 工具箱(输入编号或中文,0 退出)
============================================
0. 退出
1. 技能管理(skill 拉取 / 推送)
2. 连接器管理(MCP 开关 / 模式)
请选择:
1/技能管理→ 列表(1)、推送(2)、拉取(3)、目录(4);每层0返回2/连接器管理→ 状态(1)、开启(2)、关闭(3)、模式(4)、备份(5)、t切换本机/WSL- 任意位置输入
/home(或「首页 / 返回首页 / 回首页 / 回主页 / 主菜单 / 主页」)直接跳回顶层菜单—— 菜单位、参数位(路径/技能名/新模式 的输入框)、回车前都算,不用一层层按0; 在顶层菜单输/home会提示「已经在首页了」 - 菜单内所有操作会逐项问参数(路径、是否覆盖…),回车即用默认值
- 旧的 6 个分散 bat(skill-list / skill-push / …)已合并删除,功能全部并入本菜单
等价命令行(免菜单直传,写脚本时用):
python oc.py skill list # = 旧 skill-list.bat
python oc.py mcp status # = 旧 mcp-status.bat
python oc.py list # 自动识别归属
bat 内部会自动
chcp 65001,中文输出不会乱码。 没装 Python 或没加进 PATH,会提示Python not found in PATH。
二、命令行用法
1. ocskill.py — skill 互通
# 列出 WSL OC 的 skill(API 连不上会自动退回目录扫描)
python ocskill.py list
# 推送:压缩包(自动解压)
python ocskill.py push .\my-skill.zip
# 推送:整个 skill 目录
python ocskill.py push .\my-skill
# 推送:单个 SKILL.md(会自动包成以 name 命名的目录)
python ocskill.py push .\SKILL.md
# 推送:base64 内容
python ocskill.py push <一长串base64> --base64
# 只校验格式、不写入
python ocskill.py push .\my-skill --dry-run
# 覆盖同名 skill(先自动备份成 .bak-时间戳)
python ocskill.py push .\my-skill --force
# 反向:把 WSL 里的 skill 拷回本机
python ocskill.py pull java-expert --out .\skills-backup
# 看两端目录与 API 连接状态
python ocskill.py dirs
push 的完整流程(对应「先解码 → 确认标准 skill 格式 → 传入 skill 目录」):
- 解码归一:zip 就解压(带 zip-slip 目录穿越防护),目录原样用,
单个
.md会包成目录,base64 字符串先解成文件再判断是 zip 还是 md。 - 定位
SKILL.md:允许压缩包里多套一层父目录(最深 3 层)。 - 校验标准 skill 格式,四项全过才算通过:
- 找得到
SKILL.md - 文件以
---开头,有 YAML frontmatter - frontmatter 里有
name,且只含字母/数字/._- - frontmatter 里有
description(大模型靠它决定何时调用)
- 找得到
- 写入
\\wsl.localhost\<发行版>\root\.config\opencode\skills\<name>\, OC 会 watch 这个目录(约 100ms 去抖后自动 rescan 并推skill.reload),不用重启。
常用参数:
| 参数 | 默认 | 说明 |
|---|---|---|
--distro |
Ubuntu-24.04 |
WSL 发行版名 |
--url |
自动探测 | 显式指定 OC 地址,如 http://localhost:4096 |
--port |
4096 |
OC 端口(等价于环境变量 OC_PORT) |
--password |
自动读 | OC 口令,读取链 service.json → 环境变量 OPENCODE_PASSWORD/OPENCODE_SERVER_PASSWORD → opencode.json server.password;鉴权统一 Basic base64("opencode:<口令>")(用户名固定 opencode)。端口 4096 没监听时会 tasklist+netstat 自动发现 OC 实际随机端口并探活 |
2. mcpctl.py — MCP 配置对调开关
python mcpctl.py status # 看状态(只读)
python mcpctl.py on # 对调成含 MCP + 热重载
python mcpctl.py off # 对调成安静版 + 热重载
python mcpctl.py mode # 看当前模式
python mcpctl.py mode 手动 # 改模式(自动/手动/关闭,或 auto/manual/off)
python mcpctl.py status --target wsl # 操作 WSL 那一份配置
python mcpctl.py off --no-reload # 只对调文件,不调用重载
它读的正是 mcpcfg.txt(键值格式,小白直接改值即可):
# MCP 开关配置:改完保存,重启 OC 生效
模式: 自动 ← 自动 / 手动 / 关闭
含MCP的配置: C:\...\opencode.json
安静配置: C:\...\opencode.json.2
兼容旧「裸三行」格式(第1行模式、第2行含MCP、第3行安静),
插件/CLI 读到旧格式会自动迁移写回成上面的键值格式;
两行路径指向的文件不存在时会自动扫同目录 opencode.json.* 自愈并写回,
避免路径写错把 /mcpon /mcpoff 锁死。
状态判定只看活文件(文件名为 opencode.json 的那份)里 mcp.servers 是否非空,
所以对调之后两行的身份怎么漂移都不影响判断——这与 TUI 插件、server 插件完全一致。
另外 on/off 成功后会维护 mcp.on.flag(开写、关切):
自动模式的「启动归位」见到标记就跳过,不会把刚开启的状态又换回去。
模式语义(三个入口共用同一套规则):
| 模式 | /mcpon /mcpoff |
大模型(server 插件) | 本工具 mcpctl.py |
|---|---|---|---|
| 自动 | 可用(视为手动切换一次) | 可用 | 可用 |
| 手动 | 仅此可用 | 拒绝 | 可用(等价于用户输入命令) |
| 关闭 | 不注册 | 拒绝 | 拒绝(可用 --ignore-mode 强行) |
热重载打的是 POST /api/location/reload,会重建 location 并重读磁盘配置,MCP 立即生效;
失败时配置文件已经对调完成,重启 OC 一样生效。
开启方向多了「推送兜底」(双保险):on 在对调+写 flag 之后、reload 之前,
先把活配置里的 mcp 推进运行中的 OC。三端同一套语义——GET+merge 补 shell
→ PATCH 真实路由,按各自运行方式实现:
- TUI 插件(v10,进程内 SDK):
client.config.get()取 shell →config.update({config})→({body})→experimental.config.update三跳; - server 插件(v3,raw HTTP):
GET /api/config?directory=取 shell →PATCH /api/experimental/config?directory=,口令读service.json链、Basic base64("opencode:<口令>"); - 本 CLI(mcpctl):
tasklist+netstat端口发现(OC 每次启动随机端口, 写死 4096 常 10061)→GET /api/config探活并取info.shell(GET→活文件→null 三级兜底)→PATCH /api/experimental/config?directory=,body 必含shell(缺则 400Missing key at ["shell"];裸PATCH /config是 405)。
推送成功再 reload = 双保险,MCP 百分百加载;推送失败不阻断,自动降级为原 reload 单通道。
稳定性设计(WSL 相关)
| 问题 | 修复 |
|---|---|
| WSL 路径假错「两键路径不存在 / mcpcfg.txt 不存在」 | mcpcfg 内部是 POSIX 路径(/root/...),Windows 上曾被解析成 C:\root。现在统一过 fs_view() 翻译成 \\wsl.localhost\<发行版>\... 再访问;报错与展示仍用原文(你在 txt 里看到的样子) |
参数顺序被 argparse 拒(mcpctl status --target wsl 报 unrecognized) |
_hoist_shared() 在解析前把共享 flag(--target/--distro/--port/--timeout/--password/--no-reload/--ignore-mode)提到最前,子命令前后都能写 |
| WSL 没跑时读配置卡死/假错 | wsl_gate 统一门控:读写都先唤醒——「先给机器启动起来,再去读配置」:status / mode 查看 / backup / list / dirs 等读操作,VM 没跑同样打印「正在唤醒」拉起 VM(超时 45s)再读,绝不秒回假错;唤醒失败给清晰指引 |
wsl.exe 超时后进程永久卡死(必须 ctrl+C) |
所有 wsl.exe 调用改走 _wsl_safe_run:stdin=DEVNULL + stdout/stderr 落临时文件(零管道)+ 先查 -l -q --running 绝不无提示冷启动。根因是管道句柄被 wslrelay 等后代继承,client 被 kill 后 communicate() 等 EOF 永不返回 |
菜单被子命令 raise SystemExit 杀死 |
oc.py 的 run_safe() 护栏:KeyboardInterrupt → 已取消回菜单;SystemExit → 报告信息回菜单;异常 → 打印错误回菜单,菜单本体永不退出 |
list / dirs 连接 OC 前会先打印「正在唤醒以便读配置…」(VM 没跑时)和
「正在探测 OpenCode API 连接…」进度行(flush),
几秒无响应时一眼看出是在唤醒/探测而不是死了;list 唤醒失败绝不回落到
UNC 目录扫描(那会触发冷启动卡死),只走 API 或明确报错。
三、连不上 OC 怎么办
先看这一条(最常见):有 HTTP 代理时会假报 502。
两个脚本已默认绕过系统代理直连(ProxyHandler({}))。
如果环境里有 HTTP_PROXY / HTTPS_PROXY,urllib 默认会把 localhost 请求也丢给代理,
结果是代理回 502,看起来像 OC 挂了、其实是被劫走了。
确实需要走代理时,设环境变量再运行:MCPCTL_USE_PROXY=1 / OCSKILL_USE_PROXY=1。
其余排查:
- 确认 WSL 里的 OC 起了:
opencode serve --port 4096 - 端口不对不用管:OC 每次启动端口随机(实测如 49374),工具会
tasklist找opencode.exe的 PID、netstat -ano找它 LISTENING 的端口, 再逐候选GET /api/config探活(200 = 命中);仍要显式指定就加--port或环境变量OC_PORT - 提示
401 WWW-Authenticate: Basic realm="Secure Area"→ OC 启用了服务口令。 用--password传值(默认按service.json→ 环境变量OPENCODE_PASSWORD/OPENCODE_SERVER_PASSWORD→opencode.json server.password的顺序读,用户名固定opencode、Basic 鉴权)。注意临时opencode serve --port X实例用每次启动随机口令且不落盘,service.json读到的口令对它必 401——要么用 TUI 启动的 OC(走service.json),要么--password传启动时设的口令 localhost不通 → 工具会自动wsl hostname -I取 WSL 真实 IP 再试- 全都失败 →
list会自动降级为直接扫目录,照样能看到 skill 列表
四、和另外两个仓库的关系
本目录是独立 git 仓库,分支名 = 文件夹名 wsl-round-mcp,远程与主仓库共用同一个根:
| 文件夹 | 分支 | 内容 |
|---|---|---|
oc_session/(主仓库) |
main |
TUI 插件 oc-session-all(/sessions-all、/mcpon、/mcpoff) |
oc_session/ai-mcp/ |
ai-mcp |
server 插件 ai-mcp.ts,给大模型用的 mcp_switch 工具 |
oc_session/wsl-round-mcp/ |
wsl-round-mcp |
本目录:skill 互通 CLI + MCP 命令行开关 |
远程:https://git.ypshidifu.cn/youpaishidifu/oc_session.git